Enterprise J2ME Developing Mobile Java Applications [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

Enterprise J2ME Developing Mobile Java Applications [Electronic resources] - نسخه متنی

Michael Juntao Yuan

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید



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.


Figure 20.1. AES symmetric encryption using the BC library.



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.


Phaos Secure Number Generator


The Phaos MF for CLDC package is not shipped with random generator classes. You must supply your own generator, which implements the com.phaos.micro.crypto.RandomBitsSource interface using secure random facilities provided by the device vendor. For testing purposes, I supplied SecureRandom and SecureRBS classes in my Phaos examples. Class SecureRandom is based on the Bouncy Castle implementation of SecureRandom, and SecureRBS implements the RandomBitsSource interface.

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;
}


/ 204