- In an internet driven environment, it is imperative for a company to keep its product or business to the forefront of potential customers' minds. The ...
- A successful enterprise is all about constantly reinventing ways to work more efficiently. In today’s techno age, this translates to testing new too...
- The IT industry plays a pivotal role in providing application development solutions and custom software development to a wide range of industries, i...
- Royal Victorian Eye and Ear Hospital, 2010 Atcomm has been contracted to implement a complex IOP glaucoma management tool which will be distribut...
- We are pleased to announce another implementation of a CMS system for a large Melbourne based fitness center - Star Plate Studio. Atcomm has depl...
The J2ME Crypto Recipes
20.1 Overview of Recipes
The sample applications in this chapter provide ready-to-use code snippets for symmetric key encryption, password-based encryption, public key encryption, and digital signature tasks. You can use them in your custom J2ME applications. Brief descriptions of those common tasks are given in Table 20.1. For detailed discussions on those tasks, please refer to the relevant sections.

The source code zip archive, which you can download from this book's Web site (see "Resources"), contains four sample applications, each demonstrating the API use of a crypto package (Bouncy Castle, IAIK, Phaos, and jNeo). Table 20.2 lists the toolkits versions used in this chapter. Inside each sample application, the most important class is CryptoEngine, which stores keys and provides thin wrappers over API methods. CryptoEngine sports a monolithic single class design not optimized for code reuse. Please do not consider it a best-practice example. Instead, the examples are designed to get you started with working code quickly. Each method in the CryptoEngine class demonstrates a complete application task (for example, the RSAEncrypt() method encrypts an input byte array using RSA).

20.1.1 The Package Structure
All the J2ME crypto libraries used in the sample applications run on both CLDC and CDC platforms. To evaluate their performance in the most restricted environment, I provided user interface (UI) for the MIDP. The MIDlets drive the CryptoEngine and measure time spent on each task.
Building and running the sample applications is easy. You simply change the parameters in the build.xml file to reflect your system settings and run ANT tasks package and run. I bundled Bouncy Castle 1.16 in the BC sample. For other toolkit samples, you must contact vendors to obtain their software and evaluation licenses. You should put library JAR files in the lib/ directory.
20.1.2 Key Serialization
Besides basic encryption/decryption operations, key serialization is a core feature demonstrated in the examples. There are two important reasons for key serialization.
-
Except for the NTRUEncrypt algorithm, generating public key pairs on mobile devices is extremely time consuming.
-
In most applications, the sender and receiver use different devices, which requires keys to be transported over the network.
Note
In our examples, key serialization is used to minimize on-device key generation. All our encrypt/decrypt and sign/verify method pairs in the CryptoEngine class use the same in-memory key objects.
Classes in directory keygensrc pregenerate keys and serialize them to files in directory res/keys before MIDP suite packaging. CryptoEngine's constructor constructs pregenerated keys from files in the JAR's keys/ directory (res/keys directory in the build system). CryptoEngine also has methods to support direct key generation on mobile devices.
20.2 Symmetric Encryption
Symmetric encryption algorithms use randomly generated secret keys to encrypt and decrypt data. The sender and receiver must share the same key. The biggest advantage of symmetric algorithms is their speed. Symmetric algorithms are viable solutions even on small MIDP phones. However, the data security depends on the secrecy of the key. If an attacker somehow intercepted the key, he could easily forge or decrypt the entire communication content. The transportation and storage of secret keys is a big issue over the insecure networks. Our demo MIDlet for symmetric encryption and decryption is shown in Figure 20.1.

20.2.1 Bouncy Castle
The Bouncy Castle package supports a long list of symmetric algorithms, including AES, Rijndael, DES, triple DES, RC2, and RC4. Each cipher supports multiple buffering, padding, and ECB/CBC modes. The AES implementation is the most optimized. BC has three cipher engine classes for AES: AESLightEngine is an implementation optimized for low memory usage; AESFastEngine is optimized for speed; AESEngine is the compromise of the two.
The AES key and its initial vector (IV) are generated by random number generators in the generateAESKey() method in the CryptoEngine class (Listing 20.1).
Listing 20.1. Generate AES keys with BC
public void generateAESKey () throws Exception {
SecureRandom sr = new SecureRandom();
AESkey = new byte [16];
sr.nextBytes(AESkey);
AESinitV = new byte [16];
sr.nextBytes(AESinitV);
}
Listing 20.2 illustrates how to serialize the key and IV to disk files (the GenerateAllKeys class). The CryptoEngine constructor reads out the serialized keys for later use on the mobile device (Listing 20.3). Since BC's AES keys are simple byte arrays, the serialization and deserialization involve only simple file stream operations.
Listing 20.2. Serialize AES keys to files offline
out = new FileOutputStream(outdir + "AESkey.dat"); out.write(AESkey); out.flush(); out.close(); out = new FileOutputStream(outdir+"AESinitV.dat"); out.write(AESinitV); out.flush(); out.close();
Listing 20.3. Read out AES keys in the CryptoEngine constructor
Class c = this.getClass();
InputStream is;
is = c.getResourceAsStream("/keys/AESkey.dat");
byte [] AESkey = readFromStream(is);
is.close();
is = c.getResourceAsStream("/keys/AESinitV.dat");
byte [] AESinitV = readFromStream(is);
is.close();
With keys generated, the AESFastEncrypt() method in the CryptoEngine class uses the AESFastEngine to encrypt a byte array of plain text into cipher text. The AESFastDecrypt() method decrypts the message into a plain text byte array. The code for both methods is shown in Listing 20.4.
Listing 20.4. AES encryption and decryption methods
public byte [] AESFastEncrypt (byte [] toEncrypt) throws Exception {
BufferedBlockCipher cipher =
new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESFastEngine()));
// If initV is not given, the program will
// assume all zeros
ParametersWithIV piv = new ParametersWithIV (
(new KeyParameter(AESkey)), AESinitV);
cipher.init(true, piv);
byte[] result =
new byte[cipher.getOutputSize(toEncrypt.length)];
int len = cipher.processBytes(toEncrypt, 0,
toEncrypt.length, result, 0);
try {
cipher.doFinal(result, len);
} catch (CryptoException ce) {
// handles error
}
return result;
}
public byte [] AESFastDecrypt (byte [] toDecrypt) throws Exception {
BufferedBlockCipher cipher =
new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESFastEngine()));
ParametersWithIV piv = new ParametersWithIV (
(new KeyParameter(AESkey)), AESinitV);
cipher.init(false, piv);
byte[] result = new byte[cipher.getOutputSize(toDecrypt.length)];
int len = cipher.processBytes(toDecrypt, 0,
toDecrypt.length, result, 0);
try {
cipher.doFinal(result, len);
} catch (CryptoException ce) {
// Handle error
}
return result;
}
20.2.2 IAIK JCE-ME
In our IAIK JCE-ME example, the AES key serialization and deserialization part is exactly the same as the Bouncy Castle example. So, we only look at the key generation generateAESKey() method (Listing 20.5) in class CryptoEngine.
Listing 20.5. The generateAESKey() method
private byte [] AESkey;
private byte [] AESinitV;
// ... ...
public void generateAESKey () throws Exception {
SecureRandom sr = new SecureRandom();
AESkey = new byte [16];
sr.nextBytes(AESkey);
AESinitV = new byte [16];
sr.nextBytes(AESinitV);
}
The encryption and decryption methods are shown in Listing 20.6.
Listing 20.6. AES encryption and decryption using IAIK JCE-ME
public byte [] AESEncrypt (byte [] toEncrypt) throws Exception {
CryptoBag cipherKey = CryptoBag.makeSecretKey(AESkey);
CryptoBag ivparam = CryptoBag.makeIV(AESinitV);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, cipherKey, ivparam, null);
return cipher.doFinal(toEncrypt);
}
public byte [] AESDecrypt (byte [] toDecrypt) throws Exception {
CryptoBag cipherKey = CryptoBag.makeSecretKey(AESkey);
CryptoBag ivparam = CryptoBag.makeIV(AESinitV);
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, cipherKey, ivparam, null);
return cipher.doFinal(toDecrypt);
}
20.2.3 Phaos Micro Foundation
In the Phaos MF example, the generateAESKey() method (Listing 20.7) generates the AES key and IV.
Listing 20.7. Generate AES key and IV with Phaos MF
RandomBitsSource.setDefault(new SecureRBS());
RandomBitsSource.getDefault().seed();
public void generateAESKey () throws Exception {
AlgorithmIdentifier algID = AlgIDList.AES_128_CBC;
SymmetricKeyGenerator generator =
new SymmetricKeyGenerator(algID,
RandomBitsSource.getDefault());
AESkey = generator.generateKey();
// Create a new cipher, initialize it and then get
// CBC init vector.
Cipher cipher = BlockCipher.getInstance(algID,
AESkey, BlockCipher.PADDING_PKCS5);
CBCAlgID AESalgID =
(CBCAlgID) cipher.createAlgID();
AESinitV = AESalgID.iv;
return;
}
In the Phaos MF package, the key serialization API is slightly different from BC and IAIK. Listings 20.8 and 20.9 illustrate the serialization and deserialization processes.
Listing 20.8. Serialize AES key and IV
FileOutputStream out = new FileOutputStream(outdir + "AESkey.der"); out.write(AESkey.keyMaterial); out.flush(); out.close(); out = new FileOutputStream(outdir + "AESinitV.der"); out.write(AESinitV); out.flush(); out.close();
Listing 20.9. AES key and IV deserialization in the CryptoEngine constructor
// 192 bit AES key
private SymmetricKey AESkey;
// CBC cipher init vector
private byte [] AESinitV;
// ... ...
Class c = this.getClass();
InputStream is;
// The AES init vector
is = c.getResourceAsStream("/keys/AESinitV.der");
AESinitV = readFromStream(is);
// The AES key
is = c.getResourceAsStream("/keys/AESkey.der");
byte[] keyMaterial = readFromStream(is);
AESkey = new SymmetricKey(keyMaterial, 0, keyMaterial.length);
The AESEncrypt() and AESDecrypt() methods demonstrate how to use the cipher (Listing 20.10).
Listing 20.10. The AESEncrypt() and AESDecrypt() methods
public byte [] AESEncrypt (byte [] toEncrypt) throws Exception {
if ( AESkey == null || AESinitV == null)
throw new Exception("Generate AES key first!");
CBCAlgID AESalgID = new CBCAlgID(OIDList.AES_128_CBC, AESinitV);
Cipher cipher = BlockCipher.getInstance(AESalgID,
AESkey, BlockCipher.PADDING_PKCS5);
PooledArray ciphertext =
((BlockCipher)cipher).encryptFinal(toEncrypt, 0, toEncrypt.length);
return ciphertext.toByteArray(true);
}
public byte [] AESDecrypt (byte [] toDecrypt) throws Exception {
if ( AESkey == null )
throw new Exception("Generate AES key first!");
CBCAlgID AESalgID = new CBCAlgID(OIDList.AES_128_CBC, AESinitV);
Cipher cipher = BlockCipher.getInstance(AESalgID,
AESkey, BlockCipher.PADDING_PKCS5);
PooledArray plaintext =
((BlockCipher)cipher).decryptFinal(toDecrypt, 0, toDecrypt.length);
return plaintext.toByteArray(true);
}
20.2.4 NTRU jNeo
Symmetric key encryption is not the core innovation of NTRU but it is provided for the completeness of the package. AES key and IV are generated using code in Listing 20.11.
Listing 20.11. Generate AES key and IV with jNeo
RandomNumber rn =
new RandomNumber(NTRUConst.NTRU_SHA1_HASH);
// ... ...
public void generateAESKey () throws Exception {
AESinitV = new byte [RijndaelKey.BLOCK_SIZE];
rn.getRandom(AESinitV, 0, AESinitV.length);
byte [] keydata =
new byte [RijndaelKey.BLOCK_SIZE];
rn.getRandom(keydata, 0, keydata.length);
AESkey = new RijndaelKey(keydata,
RijndaelKey.NTRU_SYM_KEYSTRENGTH_128);
return;
}
The key serialization (Listing 20.12) and deserialization (Listing 20.13) processes are both very simple.
Listing 20.12. AES key and IV serialization
out = new FileOutputStream(outdir + "AESinitV.dat"); out.write(AESinitV); out.flush(); out.close(); out = new FileOutputStream(outdir + "AESkeydata.dat"); out.write(keydata); out.flush(); out.close();
Listing 20.13. AES key and IV deserialization
// AES init vector and 128 bit key
private byte [] AESinitV;
private RijndaelKey AESkey;
// ... ...
Class c = this.getClass();
InputStream is;
is = c.getResourceAsStream("/keys/AESkeydata.dat");
byte [] keydata = readFromStream(is);
AESkey = new RijndaelKey(keydata,
RijndaelKey.NTRU_SYM_KEYSTRENGTH_128);
is.close();
is = c.getResourceAsStream("/keys/AESinitV.dat");
AESinitV = readFromStream(is);
is.close();
Now, we can encrypt and decrypt messages (Listing 20.14). However, one thing important to note is that the plain text array to encrypt MUST have a length of a multiple of 16 bytes. If the message does not satisfy this requirement, the caller application must pad it properly. Please refer to the source code of the MIDlets for padding examples.
Listing 20.14. The AES encryption and decryption methods
// toEncrypt array length must be a multiple
// of 16 bytes
public byte [] AESEncrypt (byte [] toEncrypt) throws Exception {
if ( AESkey == null || AESinitV == null )
throw new Exception("Generate AES key first!");
if ( toEncrypt.length \% 16 != 0 )
throw new Exception("Not multiple of 16 bytes");
int len = AESkey.ciphertextLength(
RijndaelKey.NTRU_ENC_RIJNDAEL,
RijndaelKey.NTRU_SYM_MODE_CBC,
RijndaelKey.NTRU_SYM_KEYSTRENGTH_128,
toEncrypt.length, false);
byte [] result = new byte [len];
AESkey.encrypt(toEncrypt, 0, toEncrypt.length,
result, 0, RijndaelKey.NTRU_SYM_MODE_CBC,
AESinitV, 0, false);
return result;
}
public byte [] AESDecrypt (byte [] toDecrypt) throws Exception {
if ( AESkey == null || AESinitV == null )
throw new Exception("Generate AES key first!");
int len = AESkey.plaintextLength(
RijndaelKey.NTRU_ENC_RIJNDAEL,
RijndaelKey.NTRU_SYM_MODE_CBC,
RijndaelKey.NTRU_SYM_KEYSTRENGTH_128,
toDecrypt.length, false);
byte [] result = new byte [len];
AESkey.decrypt(toDecrypt, 0, toDecrypt.length,
result, 0, RijndaelKey.NTRU_SYM_MODE_CBC,
AESinitV, 0, false);
return result;
}
20.3 Password-Based Encryption
One problem with symmetric algorithms is that the users must keep the random keys. Since there is no way users can remember them in their heads, they store the keys in files, and that significantly increases the security risk. Password-based encryption (PBE) schemes use easy-to-remember passwords to generate keys for underlying symmetric parsers. PBE schemes are widely used to protect on-device data. In fact, we can use PBE-protected storages to keep other symmetric or private keys. Now, let's have a look at how PBE works in those libraries. Since the key is generated every time on-the-fly from the password, there is no key serialization process. All operations are contained in the encryption and decryption methods in the CryptoEngine class. For all algorithms, the underlying key generated from the password must be mixed in over and over again with a random "salt" to guarantee security. The iteration number is a programmable parameter and should be at least 1000. Our demo MIDlet for password-based encryption and decryption is shown in Figure 20.2.

20.3.1 Bouncy Castle
Password-based encryption and decryption using the Bouncy Castle package are demonstrated in Listing 20.15.
Listing 20.15. Methods for PBE in the Bouncy Castle CryptoEngine example
// Generate random salt
private byte [] salt;
SecureRandom sr = new SecureRandom();
salt = new byte [16];
sr.nextBytes(salt);
// Get password to generate symmetric key with
// (or without IV) To be used in
// an AES underlying cipher
private CipherParameters getAESPasswdKey
(char [] passwd) throws Exception {
PBEParametersGenerator generator =
new PKCS12ParametersGenerator(new SHA1Digest());
generator.init(
PBEParametersGenerator.PKCS12PasswordToBytes(passwd),
salt, 1024);
// Generate a 128 bit key w/ 128 bit IV
ParametersWithIV key =
(ParametersWithIV)generator.generateDerivedParameters(128, 128);
// Generate a 128 kit key
// CipherParameters key =
// generator.generateDerivedParameters(128);
return key;
}
// Password based encryption using AES
public byte [] AESPasswdEncrypt (byte [] toEncrypt,
char [] passwd)throws Exception {
ParametersWithIV key =
(ParametersWithIV) getAESPasswdKey(passwd);
// The following code uses an AES cipher to
// encrypt the message
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESFastEngine()));
cipher.init(true, key);
byte[] result = new byte[cipher.getOutputSize(toEncrypt.length)];
int len = cipher.processBytes(toEncrypt, 0,
toEncrypt.length, result, 0);
try {
cipher.doFinal(result, len);
} catch (CryptoException ce) {
// handle error
}
return result;
}
// Password based decryption using AES
public byte [] AESPasswdDecrypt (byte [] toDecrypt,
char [] passwd) throws Exception {
ParametersWithIV key = (ParametersWithIV) getAESPasswdKey(passwd);
// The following code uses an AES cipher to
// decrypt the message
BufferedBlockCipher cipher =
new PaddedBufferedBlockCipher(
new CBCBlockCipher(new AESFastEngine()));
cipher.init(false, key);
byte[] result =
new byte[cipher.getOutputSize(toDecrypt.length)];
int len = cipher.processBytes(toDecrypt, 0,
toDecrypt.length, result, 0);
try {
cipher.doFinal(result, len);
} catch (CryptoException ce) {
// handle error
}
return result;
}
In the demo code package (see "Resources"), I have also included an example of PBE using underlying triple DES symmetric key. The triple DES key does not have an IV parameter.
20.3.2 IAIK JCE-ME
The use of PBE in IAIK JCE-ME is similar to that in Bouncy Castle but with a simpler API. I demonstrate the use of RC2 as the underlying cipher in the IAIK example (Listing 20.16).
Listing 20.16. PBE in the IAIK JCE-ME
private byte [] salt;
SecureRandom sr = new SecureRandom();
salt = new byte [16];
sr.nextBytes(salt);
// ... ...
public byte [] PBEEncrypt (byte [] toEncrypt,
char [] passwd) throws Exception {
PBE pbe = PBE.getInstance(PBE.OID_PKCS12_RC2_40_SHA);
Cipher c = pbe.getCipher(Cipher.ENCRYPT_MODE,
passwd, salt, 1024, null);
return c.doFinal(toEncrypt);
}
public byte [] PBEDecrypt (byte [] toDecrypt,
char [] passwd) throws Exception {
PBE pbe = PBE.getInstance(PBE.OID_PKCS12_RC2_40_SHA);
Cipher c = pbe.getCipher(Cipher.DECRYPT_MODE,
passwd, salt, 1024, null);
return c.doFinal(toDecrypt);
}
20.3.3 Phaos Micro Foundation
In the Phaos MF example (Listing 20.17), we use the PKCS #5 scheme to generate the symmetric key. The salt mix-in iteration number is the default 1024 specified by the implementation. In the Phaos MF API, we need to generate the random IV AESinitV for the AES key ourselves. Also, please note that although handling PooledArray is tedious, it produces performance gains on small devices.
Listing 20.17. Password based encryption and decryption using Phaos MF
private byte [] salt;
RandomBitsSource.setDefault(new SecureRBS());;
RandomBitsSource.getDefault().seed();
salt = new byte[PBES2AlgID.DEFAULT_SALT_LENGTH];
RandomBitsSource.getDefault().randomBytes(salt);
// ... ...
// PKCS #5 password scheme 2 using
// AES as underlying cipher
public byte [] AESPasswdEncrypt(byte [] toEncrypt,
String password) throws Exception {
// Use SHA1 with AES
AlgorithmIdentifier algID = new PBES2AlgID(salt,
PBES2AlgID.DEFAULT_ITERATION_COUNT,
PBES2AlgID.KEY_LENGTH_NOT_PRESENT,
AlgIDList.HMAC_WITH_SHA1,
new CBCAlgID(OIDList.AES_128_CBC, AESinitV));
ByteArrayInputStream in = new ByteArrayInputStream(toEncrypt);
PooledArray plaintext = ByteArrayPool.getArray(in.available());
in.read(plaintext.buffer, 0, plaintext.length);
in.close();
// PKCS #5 only uses lower 8 bits of
// each password char
PasswordBasedEncryptionScheme pbes =
PasswordBasedEncryptionScheme.getInstance(algID,
password.getBytes());
PooledArray ciphertext =
pbes.encryptFinal(plaintext.buffer, 0,
plaintext.length);
ByteArrayOutputStream out = new ByteArrayOutputStream ();
algID.output(out);
out.write(ciphertext.buffer, 0,
ciphertext.length);
byte [] encrypted = out.toByteArray();
out.close();
plaintext.release();
ciphertext.release();
return encrypted;
}
// PKCS #5 password scheme 2 decryption
//
// Since the algID is embedded inside the
// encrypted byte array, this method can decrypt
// any Phaos PBES messages with any
// underlying ciphers.
public byte [] AESPasswdDecrypt(byte [] toDecrypt,
String password) throws Exception {
ByteArrayInputStream in = new ByteArrayInputStream(toDecrypt);
AlgorithmIdentifier algID = new AlgorithmIdentifier(in);
PooledArray ciphertext = ByteArrayPool.getArray(in.available());
in.read(ciphertext.buffer, 0, ciphertext.length);
in.close();
PasswordBasedEncryptionScheme pbes =
PasswordBasedEncryptionScheme.getInstance(algID,
password.getBytes());
PooledArray plaintext =
pbes.decryptFinal(ciphertext.buffer, 0,
ciphertext.length);
ByteArrayOutputStream out = new ByteArrayOutputStream ();
out.write(plaintext.buffer, 0, plaintext.length);
byte [] decrypted = out.toByteArray();
out.close();
plaintext.release();
ciphertext.release();
return decrypted;
}
20.4 Public Key Encryption
Public key algorithms eliminate the key exchange problems associated with symmetric algorithms. Basically, each user has a pair of keys. The public key is available to anyone, and the private key is known only to the user. Public key algorithms are designed to be one-way trapdoor systems where a message encrypted by the public key can only be decrypted by the corresponding private key (see Figure 20.3). So, if Alice wants to send Bob a secret message, she uses Bob's public key to encrypt the data and sends it over any general insecure network. Only Bob himself has the correct private key to decrypt the message. The beauty of this scheme is that no secret key ever needs to be exchanged.

However, without built-in hardware acceleration or native long-integer support, public key encryption can be very slow on mobile devices. In reality, we often use public key algorithms to exchange symmetric keys and use symmetric key channels for further communication. Our demo MIDlet for RSA public key encryption and decryption is shown in Figure 20.4.
.gif)
20.4.1 Bouncy Castle
To generate an RSA key pair, BC requires the developer to pick a mathematical parameter called public exponent. A common pick is 65537 (Hex 10001) for strong security and fast performance. Listing 20.18 demonstrates how to generate an RSA key pair in the CryptoEngine class.
Listing 20.18. BC RSA key pair generation
public void generateRSAKeyPair () throws Exception {
SecureRandom sr = new SecureRandom();
BigInteger pubExp = new BigInteger("10001", 16);
RSAKeyGenerationParameters RSAKeyGenPara =
new RSAKeyGenerationParameters(pubExp, sr, 1024, 80);
RSAKeyPairGenerator RSAKeyPairGen = new RSAKeyPairGenerator();
RSAKeyPairGen.init(RSAKeyGenPara);
AsymmetricCipherKeyPair keyPair = RSAKeyPairGen.generateKeyPair();
RSAprivKey = (RSAPrivateCrtKeyParameters) keyPair.getPrivate();
RSApubKey = (RSAKeyParameters) keyPair.getPublic();
}
Listings 20.19 and 20.20 demonstrate how to serialize the key pair offline to disk files and then read them back. Please note that since BC does not support a good key serialization mechanism in its lightweight API package, we have to manually serialize all key parameters, which is tedious.
Listing 20.19. Serialize the key pair to disk files
BigInteger mod = RSAprivKey.getModulus();
out = new FileOutputStream(outdir + "RSAmod.dat");
out.write(mod.toByteArray());
out.flush(); out.close();
BigInteger privExp = RSAprivKey.getExponent();
out = new FileOutputStream(outdir + "RSAprivExp.dat");
out.write(privExp.toByteArray());
out.flush(); out.close();
pubExp = RSAprivKey.getPublicExponent();
if ( !pubExp.equals(new BigInteger("10001", 16)) )
throw new Exception("wrong public exponent");
out = new FileOutputStream(outdir + "RSApubExp.dat");
out.write(pubExp.toByteArray());
out.flush(); out.close();
BigInteger dp = RSAprivKey.getDP();
out = new FileOutputStream(outdir + "RSAdp.dat");
out.write(dp.toByteArray());
out.flush(); out.close();
BigInteger dq = RSAprivKey.getDQ();
out = new FileOutputStream(outdir + "RSAdq.dat");
out.write(dq.toByteArray());
out.flush(); out.close();
BigInteger p = RSAprivKey.getP();
out = new FileOutputStream(outdir + "RSAp.dat");
out.write(p.toByteArray());
out.flush(); out.close();
BigInteger q = RSAprivKey.getQ();
out = new FileOutputStream(outdir + "RSAq.dat");
out.write(q.toByteArray());
out.flush(); out.close();
BigInteger qInv = RSAprivKey.getQInv();
out = new FileOutputStream(outdir + "RSAqInv.dat");
out.write(qInv.toByteArray());
out.flush(); out.close();
Listing 20.20. Deserialize the key pair in CryptoEngine constructor
Class c = this.getClass();
InputStream is;
is = c.getResourceAsStream("/keys/RSAmod.dat");
BigInteger RSAmod = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAprivExp.dat");
BigInteger RSAprivExp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSApubExp.dat");
BigInteger RSApubExp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAdp.dat");
BigInteger RSAdp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAdq.dat");
BigInteger RSAdq = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAp.dat");
BigInteger RSAp = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAq.dat");
BigInteger RSAq = new BigInteger(readFromStream(is));
is.close();
is = c.getResourceAsStream("/keys/RSAqInv.dat");
BigInteger RSAqInv = new BigInteger(readFromStream(is));
is.close();
RSAprivKey = new RSAPrivateCrtKeyParameters(
RSAmod, RSApubExp, RSAprivExp, RSAp,
RSAq, RSAdp, RSAdq, RSAqInv);
RSApubKey = new RSAKeyParameters(false, RSAmod, RSApubExp);
Now, we can encrypt and decrypt messages using the public key RSApubKey and private key RSAprivKey respectively (Listing 20.21).
Listing 20.21. RSA encryption and decryption with BC
// Public key encrypt using RSA
public byte [] RSAEncrypt (byte [] toEncrypt) throws Exception {
if (RSApubKey == null)
throw new Exception("Generate RSA keys first!");
AsymmetricBlockCipher eng = new RSAEngine();
eng = new PKCS1Encoding(eng);
eng.init(true, RSApubKey);
return eng.processBlock(toEncrypt, 0, toEncrypt.length);
}
// private key decrypt
public byte [] RSADecrypt (byte [] toDecrypt) throws Exception {
if (RSAprivKey == null)
throw new Exception("Generate RSA keys first!");
AsymmetricBlockCipher eng = new RSAEngine();
eng = new PKCS1Encoding(eng);
eng.init(false, RSAprivKey);
return eng.processBlock(toDecrypt, 0, toDecrypt.length);
}
20.4.2 IAIK JCE-ME
Listing 20.22 illustrates how to generate an RSA key pair using the IAIK library.
Listing 20.22. Generate RSA keys using the IAIK library
public void generateRSAKeyPair () throws Exception {
RSAKeyPairGenerator rsaKeyPairGenerator = new RSAKeyPairGenerator();
rsaKeyPairGenerator.initialize(1024, null, null);
CryptoBag cryptoBag = rsaKeyPairGenerator.generateKeyPair();
RSApubKey =
(PublicKey) cryptoBag.getCryptoBag(cryptoBag.V_KEY_PUBLIC);
RSAprivKey =
(PrivateKey) cryptoBag.getCryptoBag(cryptoBag.V_KEY_PRIVATE);
return;
}
Listings 20.23 and 20.24 demonstrate the serialization and deserialization processes in the GenerateAllKeys class and the CryptoEngine constructor.
Listing 20.23. Serialize the keys to a disk file
out = new FileOutputStream(outdir + "RSApub.dat"); out.write(RSApubKey.getEncoded()); out.flush(); out.close(); out = new FileOutputStream(outdir + "RSApriv.dat"); out.write(RSAprivKey.getEncoded()); out.flush(); out.close();
Listing 20.24. Deserialize the RSA key pair
Class c = this.getClass();
InputStream is;
byte [] asnArray;
is = c.getResourceAsStream("/keys/RSApub.dat");
asnArray = readFromStream(is);
is.close();
RSApubKey = new PublicKey(new ASN1(asnArray));
is = c.getResourceAsStream("/keys/RSApriv.dat");
asnArray = readFromStream(is);
is.close();
RSAprivKey = new PrivateKey(new ASN1(asnArray));
With the key pair, we can now encrypt and decrypt messages (Listing 20.25). Notice how simple the API is!
Listing 20.25. RSA encryption and decryption
// Public key encrypt using RSA
public byte [] RSAEncrypt (byte [] toEncrypt) throws Exception {
if (RSApubKey == null)
throw new Exception("Generate RSA keys first!");
Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsa.init(Cipher.ENCRYPT_MODE, RSApubKey, null, null);
return rsa.doFinal(toEncrypt);
}
// private key decrypt
public byte [] RSADecrypt (byte [] toDecrypt) throws Exception {
if (RSAprivKey == null)
throw new Exception("Generate RSA keys first!");
Cipher rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
rsa.init(Cipher.DECRYPT_MODE, RSAprivKey, null, null);
return rsa.doFinal(toDecrypt);
}
20.4.3 Phaos Micro Foundation
Using the Phaos MF library, generating an RSA key pair is easy (Listing 20.26).
Listing 20.26. Generate a RSA key pair using Phaos MF
public void generateRSAKeyPair () throws Exception {
RSAKeyGenParams params = new RSAKeyGenParams(1024);
KeyPairGenerator kpg =
KeyPairGenerator.getInstance(
OIDList.RSA_ENCRYPTION, params);
KeyPair kp = kpg.generateKeyPair();
RSApubKey = (RSAPublicKey)kp.publicKey;
RSAprivKey = (RSAPrivateKey)kp.privateKey;
return;
}
Serializing and deserializing keys in the Phaos library are demonstrated in Listings 20.27 and 20.28.
Listing 20.27. Serialize RSA keys to files
RSApubKey.output(new FileOutputStream(outdir + "RSApubKey.der")); RSAprivKey.output(new FileOutputStream(outdir + "RSAprivKey.der"));
Listing 20.28. Deserialize keys from the files
Class c = this.getClass();
InputStream is;
is = c.getResourceAsStream("/keys/RSApubKey.der");
RSApubKey = new RSAPublicKey(is);
is.close();
is = c.getResourceAsStream("/keys/RSAprivKey.der");
RSAprivKey = new RSAPrivateKey(is);
is.close();
Encryption and decryption are demonstrated in Listing 20.29.
Listing 20.29. RSA encryption and decryption
public byte [] RSAEncrypt (byte [] toEncrypt) throws Exception {
if (RSApubKey == null)
throw new Exception("Generate RSA keys first!");
byte [] encrypted;
PooledArray plaintext = ByteArrayPool.getArray(toEncrypt);
AlgorithmIdentifier algID = new OAEPAlgID();
Cipher cipher = Cipher.getInstance(algID, RSApubKey);
PooledArray ciphertext =
cipher.encrypt(plaintext.buffer, 0, plaintext.length);
ByteArrayOutputStream out = new ByteArrayOutputStream ();
algID.output(out);
out.write(ciphertext.buffer, 0, ciphertext.length);
encrypted = out.toByteArray();
out.close();
plaintext.release();
ciphertext.release();
return encrypted;
}
public byte [] RSADecrypt (byte [] toDecrypt) throws Exception {
if (RSAprivKey == null)
throw new Exception("Generate RSA keys first!");
byte [] decrypted;
ByteArrayInputStream in = new ByteArrayInputStream(toDecrypt);
AlgorithmIdentifier algID = new AlgorithmIdentifier(in);
PooledArray ciphertext = ByteArrayPool.getArray(in.available());
in.read(ciphertext.buffer, 0, ciphertext.length);
in.close();
Cipher cipher = Cipher.getInstance(algID, RSAprivKey);
PooledArray plaintext =
cipher.decrypt(ciphertext.buffer, 0, ciphertext.length);
decrypted = plaintext.toByteArray();
plaintext.release();
ciphertext.release();
return decrypted;
}
20.4.4 NTRU jNeo
Generating an NTRU key pair for the NTRUEncrypt algorithm takes only one line of code. The following code snippet generates an NTRU 251-bit encryption key, which has cryptographic strength equivalent to a 1,024-bit RSA key (Listing 20.30).
Listing 20.30. Generate the NTRU encryption key pair
private RandomNumber rn =
new RandomNumber(NTRUConst.NTRU_SHA1_HASH);
private Context ctx = new Context(rn);
// ... ...
public void generateNTRUencKeys () throws Exception {
NTRUencKeys = new EncKeys(ctx,
NTRUConst.NTRU_KEYSTRENGTH_251,
NTRUConst.NTRU_SHA1_HASH);
return;
}
NTRU jNeo provides its own key serialization methods. Let's see how it is done in the GenerateAllKeys class (Listing 20.31) and the CryptoEngine (Listing 20.32) constructor.
Listing 20.31. Serialize the key pair to disk files
byte [] pubKey = NTRUencKeys.exportPubKey(null, 0, true); out = new FileOutputStream(outdir + "EncPubKey.dat"); out.write(pubKey); out.flush(); out.close(); byte [] privKey = NTRUencKeys.exportPrivKey(null, 0, true); out = new FileOutputStream(outdir + "EncPrivKey.dat"); out.write(privKey); out.flush(); out.close();
Listing 20.32. Deserialize the key pair from disk files
Class c = this.getClass();
InputStream is;
is = c.getResourceAsStream("/keys/EncPubKey.dat");
byte [] encPubKeyData = readFromStream(is);
is.close();
is = c.getResourceAsStream("/keys/EncPrivKey.dat");
byte [] encPrivKeyData = readFromStream(is);
is.close();
NTRUencKeys = new EncKeys (encPubKeyData, o,
encPubKeyData.length,
encPrivKeyData, 0,
encPrivKeyData.length,
true);
The encryption and decryption methods are demonstrated in Listing 20.33. Notice that we take care of the proper block handling in our methods.
Listing 20.33. Encryption and decryption using the NTRU algorithm
public byte [] NTRUEncrypt (byte [] toEncrypt) throws Exception {
if ( NTRUencKeys == null )
throw new Exception("Generate keys first!");
int cipherBlockSize =
NTRUencKeys.ciphertextSize(NTRUConst.NTRU_KEYSTRENGTH_251);
int plainBlockSize =
NTRUencKeys.blockSize(NTRUConst.NTRU_KEYSTRENGTH_251);
byte [] cipherBlock = new byte [cipherBlockSize];
byte [] plainBlock = new byte [plainBlockSize];
int psize;
ByteArrayInputStream bais = new ByteArrayInputStream(toEncrypt);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ( (psize = bais.read(plainBlock)) != -1 ) {
// resize the last plain text block
if ( psize < plainBlockSize ) {
byte tmp [] = new byte [psize];
for (int i = 0; i < psize; i++) {
tmp[i] = plainBlock[i];
}
plainBlock = tmp;
}
NTRUencKeys.blockEncrypt(ctx, plainBlock, 0,
plainBlock.length, cipherBlock, 0);
baos.write(cipherBlock);
}
baos.flush();
byte [] result = baos.toByteArray();
baos.close(); bais.close();
return result;
}
public byte [] NTRUDecrypt (byte [] toDecrypt) throws Exception {
if ( NTRUencKeys == null )
throw new Exception("Generate keys first!");
int cipherBlockSize =
NTRUencKeys.ciphertextSize(NTRUConst.NTRU_KEYSTRENGTH_251);
int plainBlockSize =
NTRUencKeys.blockSize(NTRUConst.NTRU_KEYSTRENGTH_251);
byte [] cipherBlock = new byte [cipherBlockSize];
byte [] plainBlock = new byte [plainBlockSize];
int psize;
ByteArrayInputStream bais = new ByteArrayInputStream(toDecrypt);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
while ( bais.read(cipherBlock) != -1 ) {
psize = NTRUencKeys.blockDecrypt(ctx,
cipherBlock, 0,
cipherBlock.length,
plainBlock, 0);
// resize the last plain text block
if ( psize < plainBlockSize ) {
byte tmp [] = new byte [psize];
for (int i = 0; i < psize; i++) {
tmp[i] = plainBlock[i];
}
plainBlock = tmp;
}
baos.write(plainBlock);
}
baos.flush();
byte [] result = baos.toByteArray();
baos.close(); bais.close();
return result;
}
20.5 Digital Signature
Digital signature can guarantee message integrity and authenticity in an open network environment. To generate a signature, you first calculate a hash (also called digest) of your message. Then you encrypt that hash with your private key to generate a signature. The party at the receiving end first decrypts your signature into a hash using your public key. Then she calculates the hash from your message. If the two hashes match, the message is indeed from you and unaltered. The signing and verification processes are demonstrated in Figures 20.5 and 20.6 respectively.

If someone altered the message during its transmission and generated a new hash based on the modified message, public key algorithms guarantee that he cannot produce a matching signature without knowing your private key. The two parties must share four pieces of information: the message itself, its digital signature, the hash and signing algorithms, and the public key. Our demo MIDlet for digital signature is shown in Figure 20.7.

20.5.1 Bouncy Castle
Bouncy Castle supports DSA, RSA, and ECC (Elliptic Curve Cryptography) digital signature algorithms. But only RSA seems to have an acceptable performance on MIDP devices. So, the code example here only shows how to work with RSA signatures. Since the RSA key pair generation and serialization part is already covered by the last section, we go directly to the code for signature generation and verification (Listing 20.34).
Listing 20.34. Sign and verify a message using the RSA algorithm in BC
public byte [] RSASign (byte [] toSign) throws Exception {
if (RSAprivKey == null)
throw new Exception("Generate RSA keys first!");
SHA1Digest dig = new SHA1Digest();
RSAEngine eng = new RSAEngine();
PSSSigner signer = new PSSSigner(eng, dig, 64);
signer.init(true, RSAprivKey);
signer.update(toSign, O, toSign.length);
return signer.generateSignature();
}
public boolean RSAVerify (byte [] mesg, byte [] sig)
throws Exception {
if (RSApubKey == null)
throw new Exception("Generate RSA keys first!");
SHA1Digest dig = new SHA1Digest();
RSAEngine eng = new RSAEngine();
PSSSigner signer = new PSSSigner(eng, dig, 64);
signer.init(false, RSApubKey);
signer.update(mesg, 0, mesg.length);
return signer.verifySignature(sig);
}
20.5.2 IAIK JCE-ME
Our IAIK digital signature example also uses the RSA algorithm. So, again, we do not show any code for the key generation and serialization. Listing 20.35 demonstrates the signing and verification processes.
Listing 20.35. RSA digital signature sign and verify methods in IAIK
// RSA signature
public byte [] RSASign (byte [] toSign) throws Exception {
if (RSAprivKey == null)
throw new Exception("Generate RSA keys first!");
Signature sharsa = Signature.getInstance("SHA1withRSA");
sharsa.initSign(RSAprivKey, null);
sharsa.update(toSign);
return sharsa.sign();
}
// RSA signature verification
public boolean RSAVerify (byte [] mesg, byte [] sig)
throws Exception {
if (RSApubKey == null)
throw new Exception("Generate RSA keys first!");
Signature sharsa = Signature.getInstance("SHA1withRSA");
sharsa.initVerify(RSApubKey);
sharsa.update(mesg);
return sharsa.verify(sig);
}
20.5.3 Phaos Micro Foundation
Phaos MF supports DSA and RSA digital signatures. DSA is certainly slower than RSA. But since we already have two RSA examples, we will have a look at a DSA example here. Generating DSA key pairs using the Phaos MF API is illustrated in Listing 20.36. Variable DSApubKeyDer is not the public key itself. Rather, it is a byte array representation of the public key in DER (Distinguished Encoding Rules) format. The public key can be reconstructed from this array using an appropriate algorithm identifier (see Listing 20.38).
Listing 20.36. Phaos MF DSA key pair generation
// 1024-bit DSA key
private DSAPrivateKey DSAprivKey;
// This is the DSA public key data you can serialize
private byte [] DSApubKeyDer;
public void generateDSAKeyPair () throws Exception {
DSAKeyGenParams params =
new DSAKeyGenParams(1024, RandomBitsSource.getDefault());
KeyPairGenerator kpg =
KeyPairGenerator.getInstance(OIDList.DSA, params);
KeyPair kp = kpg.generateKeyPair();
DSAprivKey = (DSAPrivateKey)kp.privateKey;
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
((DSAPublicKey)kp.publicKey).output(baos);
DSApubKeyDer = baos.toByteArray();
return;
}
The Phaos DSA key pair serialization and deserialization processes are illustrated in Listings 20.37 and 20.38.
Listing 20.37. Phaos MF DSA key pair serialization
DSAPublicKey pubKey = (DSAPublicKey)kp.publicKey;
DSAPrivateKey privKey = (DSAPrivateKey)kp.privateKey;
pubKey.output(new FileOutputStream(outdir + "DSApubKey.der"));
privKey.output(new FileOutputStream(outdir + "DSAprivKey.der"));
DSAParams dsaParams =
new DSAParams(
new ByteArrayInputStream(
privKey.createAlgID(true).encodeParameters()));
dsaParams.output(new FileOutputStream(outdir + "DSAparams.der"));
Listing 20.38. Phaos MF DSA key pair deserialization
// The DSA private key
is = c.getResourceAsStream("/keys/DSAparams.der");
DSAParams params = new DSAParams(is);
AlgorithmIdentifier algID = getDSAalgID(params);
is.close();
is = c.getResourceAsStream("/keys/DSAprivKey.der");
DSAprivKey = new DSAPrivateKey(algID, is);
is.close();
// The DSA public key byte array
is = c.getResourceAsStream("/keys/DSApubKey.der");
baos = new ByteArrayOutputStream();
b = new byte[1];
while ( is.read(b) != -1 ) {
baos.write(b);
}
is.close();
DSApubKeyDer = baos.toByteArray();
baos.close();
The method getDSAalgID() (Listing 20.38) retrieves the algorithm identifier from DSA parameters. It is also used in DSA sign and verify examples (Listing 20.39).
Listing 20.39. Phaos MF DSA sign and verify methods
private AlgorithmIdentifier getDSAalgID (DSAParams params)
throws Exception {
ByteArrayOutputStream paramsOut = new ByteArrayOutputStream();
params.output(paramsOut);
paramsOut.close();
return new AlgorithmIdentifier(OIDList.DSA, paramsOut.toByteArray());
}
public byte [] DSASign (byte [] toSign) throws Exception {
if (DSAprivKey == null)
throw new Exception("Generate DSA keys first!");
Signature signature =
Signature.getInstance(AlgIDList.SHA1_WITH_DSA, DSAprivKey);
byte [] result =
signature.sign(toSign, 0, toSign.length).toByteArray(true);
DSAParams params = new DSAParams(
new ByteArrayInputStream(
DSAprivKey.createAlgID(true).encodeParameters()));
AlgorithmIdentifier algID = getDSAalgID (params);
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
algID.output(baos);
baos.write(result, 0, result.length);
baos.flush(); baos.close();
return baos.toByteArray();
}
public boolean DSAVerify (byte [] mesg, byte [] sig)
throws Exception {
InputStream is = new ByteArrayInputStream(sig);
AlgorithmIdentifier algID = new AlgorithmIdentifier(is);
PooledArray sigBytes = ByteArrayPool.getArray(is.available());
is.read(sigBytes.buffer, 0, sigBytes.length);
is.close();
DSAPublicKey DSApubKey = new DSAPublicKey(algID,
new ByteArrayInputStream(DSApubKeyDer));
Signature signature =
Signature.getInstance(AlgIDList.SHA1_WITH_DSA, DSApubKey);
return signatur Layout managers in Java Swing
Layout Managers
This section of the chapter discusses eight important layout managers:
❑ BoxLayout
❑ CardLayout
❑ FlowLayout
❑ GridbagLayout
❑ GridLayout
❑ SpringLayout
❑ GroupLayout
BorderLayout
The following BorderLayout example emulates a test application that quizzes the user with five fairly simple arithmetic queries. As a user sequentially steps through the test questions, a progress bar will track where the test taker is with respect to the end of the test and what the running score is. Figure 4-1 provides a model of the application and shows how the different GUI components will occupy the BorderLayout panel.

BoxLayout

FlowLayout
Figure 4-5 provides a high-level view of the FlowLayoutPanel application and how the Swing components are positioned on the FlowLayout panel.
The following GridLayout example processes mouse events on buttons generated with Java 2D classes. Figure 4-7 shows how the buttons are organized on the GridLayoutPanel display.
The table here describes some attributes that can be implemented to position the GridBagLayout manager on a user display.