This is the main class, and it controls the state changes between screens.
It also calls the Codec
class for encrypting (addNewMessage
method)
and decrypting (showDecryptedMessage
method) messages.
Notice that the calls to Codec
needed to encrypt and
decrypt messages are done in a separate thread using the inner class CryptoRunnable
To create the class:
Assign the
class to the package satsa
and import the required classes.
package satsa; import java.security.GeneralSecurityException; import javax.crypto.BadPaddingException; import javax.microedition.lcdui.Display; import javax.microedition.midlet.MIDlet; import javax.microedition.midlet.MIDletStateChangeException;
Create the class, initialize the internal fields, and start up the UI.
// Main SATSA MIDlet class // It controls the state of the user interface // and handles the encryption and decryption process public class SATSAMIDlet extends MIDlet { 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 { 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(this); messageStore = new MessageStore(this); // Startup the UI showMessageList(); }
First show
a list of messages and then decrypt the chosen message, display the password
screen, and then show the decrypted message. Call the Codec
class
by using the showEncryptedMessage()
method to decrypt
the message. In addition, create an instance of the inner class CryptoRunnable
to
handle the decrypting process in a separate thread.
// 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 message 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); } void exitMIDlet() { if (messageStore != null) { messageStore.close(); } notifyDestroyed(); }
Call the Codec
class
for encrypting the message by using the addNewMessage()
method.
Create an instance of the inner class CryptoRunnable
to
handle the encrypting process in a separate thread.
// adds a new message encrypting it an storing it 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(); }
Create a new
inner class CryptoRunnable
to handle the decryption and
encryption process in a separate thread.
// 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 multiple // 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 raised when // the password is incorrect showError("Incorrect password."); } catch (GeneralSecurityException gse) { // Handles all other exceptions showError("General Security Exception while decrypting: " + gse.toString()); } } } } }