/* * Copyright © 2013 Nokia Corporation. All rights reserved. Nokia and Nokia * Connecting People are registered trademarks of Nokia Corporation. Oracle and * Java are trademarks or registered trademarks of Oracle and/or its affiliates. * Other product and company names mentioned herein may be trademarks or trade * names of their respective owners. See LICENSE.TXT for license information. */ package com.nokia.example.satsa; import com.nokia.mid.ui.orientation.Orientation; import com.nokia.mid.ui.orientation.OrientationListener; import java.security.GeneralSecurityException; import javax.crypto.BadPaddingException; import javax.crypto.ShortBufferException; import javax.microedition.lcdui.Display; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException; // Main SATSA MIDlet class // It controls the state of the user interface // and handles the encryption and decryption process // The class implements OrientationListener to detect a change in the orientation of the device's display */ public class SATSAMIDlet extends MIDlet implements OrientationListener{ private Display display; private MessageStore messageStore; private ListScreen listScreen; private EncryptScreen encryptScreen; private PasswordScreen passwordScreen; private DecryptScreen decryptScreen; private InfoScreen infoScreen; private NewScreen newScreen; private Codec codec; public SATSAMIDlet() { } protected void destroyApp(boolean unconditional) throws MIDletStateChangeException { exitMIDlet(); } protected void pauseApp() { } protected void startApp() throws MIDletStateChangeException { /** Registers the orientation listener. Applications that need information about events related to display orientation changes need to register with Orientation to get notifications of the events.*/ Orientation.addOrientationListener(this); if (display == null) { initMIDlet(); } } // Initialize all the internal fields private void initMIDlet() { // Init the user interface display = Display.getDisplay(this); listScreen = new ListScreen(this); encryptScreen = new EncryptScreen(this); passwordScreen = new PasswordScreen(this); decryptScreen = new DecryptScreen(this); infoScreen = new InfoScreen(); newScreen = new NewScreen(this); // Initialize the Cryptographic Codec and the message store codec = new Codec(); messageStore = new MessageStore(this); // Startup the UI showMessageList(); } // Shows the list of existing messages void showMessageList() { messageStore.fillList(listScreen); display.setCurrent(listScreen); } // Shows an encrypted message in HEX format void showEncryptedMessage(int index) { encryptScreen.setIndex(index); encryptScreen.setMessage(codec.byteToHex(messageStore.getMessage(index + 1))); display.setCurrent(encryptScreen); } // Displays the password screen void showPasswordScreen(int index) { passwordScreen.setIndex(index); display.setCurrent(passwordScreen); } // Shows a decrypted messages void showDecryptedMessage(int index, String password) { // 128bit (16 characters) key is needed for AES // just fill with blanks if too short while (password.length() < 16) { password = password.concat(" "); } decryptScreen.setIndex(index); byte message[] = messageStore.getMessage(index + 1); // Do the decryption and validation in a separate thread new Thread(new CryptoRunnable(message, password.getBytes(), false)).start(); } // Display an error message void showError(String messageString) { infoScreen.showError(messageString, Display.getDisplay(this)); } // Delete a message void deleteMessage(int index) { messageStore.deleteMessage(index + 1); messageStore.fillList(listScreen); } // Shows the new message void showNewMessage() { newScreen.createForm(); display.setCurrent(newScreen); } // adds a new message encrypting it an storing in the record store void addNewMessage(String message, String password) { // 128bit (16 characters) key is needed for AES // just fill with blanks if too short while (password.length() < 16) { password = password.concat(" "); } // Do the encryption in a separate thread new Thread(new CryptoRunnable(message.getBytes(), password.getBytes(), true)).start(); } void exitMIDlet() { if (messageStore != null) { messageStore.close(); } notifyDestroyed(); } // Internal class to handle the decryption and encryption // process in a separate thread as recommended in SATSA-CRYPTO private class CryptoRunnable implements Runnable { private byte[] message, password; private boolean encryption; CryptoRunnable(byte[] message, byte[] password, boolean encryption) { this.message = message; this.password = password; this.encryption = encryption; } public void run() { if (encryption) { try { // Encrypt the message byte[] encryptedMessage = codec.encrypt(password, message); // Calculate the digest of the encrypted message byte[] digest = codec.digest(encryptedMessage); // Compose the overall message byte[] messageBytes = new byte[encryptedMessage.length + digest.length]; System.arraycopy(digest, 0, messageBytes, 0, digest.length); System.arraycopy(encryptedMessage, 0, messageBytes, digest.length, encryptedMessage.length); // Store the encoded message messageStore.addMessage(messageBytes); } catch (GeneralSecurityException gse) { // Use of generic Exception type since mutiple // exceptions may be thrown at this point showError("General Security Exception while encrypting: " + gse.toString()); } showMessageList(); } else { try { // Get the cipher text and the digest // SHA-1 digest is 160 bits long byte[] digest = new byte[20]; byte[] cipherText = new byte[message.length - digest.length]; // Decompose the message System.arraycopy(message, 0, digest, 0, digest.length); System.arraycopy(message, digest.length, cipherText, 0, cipherText.length); // Verify the cipher's text digest if (codec.isDigestValid(cipherText, digest)) { // If digest is ok, let's decrypt byte[] plainText = codec.decrypt(password, cipherText); // Display the message on screen decryptScreen.setMessage(new String(plainText)); display.setCurrent(decryptScreen); } else { showError("Digest of message is not valid"); } } catch (BadPaddingException bpe) { // This is a particular exception when the password is incorrect showError("Incorrect password."); } catch (ShortBufferException bpe) { showError("Incorrect password."); } catch (GeneralSecurityException gse) { // Handles all other exceptions showError("General Security Exception while decrypting: " + gse.toString()); } } } } /** Called when display's orientation has changed. */ public void displayOrientationChanged( int newDisplayOrientation ){ /** Change MIDlet UI orientation */ Orientation.setAppOrientation(newDisplayOrientation); } }