I'm currently implementing a symmetric en-/decryption using AES 256 on Android, inspired by this post: Java 256bit AES Encryption. The purpose of my implementation is that I want to encrypt the data in a database.
For key generation I use the following constructor which takes a char[] password:
public Cryptography(char[] password) throws NoSuchAlgorithmException,
InvalidKeySpecException, NoSuchPaddingException {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec(password, salt, 1024, 256);
secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), "AES");
cipher = Cipher.getInstance(AES/CBC/PKCS5Padding);
}
So when I start my Activity in Android I initialize a new instance of my Cryptography class and therefore get a generated key. The salt is a fixed random byte[] of 16 bytes. So that means that I always get the same key. The reason for that later.
Now after I got an object in one Activity I can use the following encrypt and decrypt methods with always the same key:
public byte[] encrypt(String cleartext) throws InvalidKeyException,
IllegalBlockSizeException, BadPaddingException,
UnsupportedEncodingException, InvalidParameterSpecException {
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encText = cipher.doFinal(cleartext.getBytes(CHARSET_NAME));
byte[] iv = cipher.getParameters()
.getParameterSpec(IvParameterSpec.class).getIV();
byte[] enc = new byte[IV_SIZE + encText.length];
for (int i = 0; i < enc.length; i++) {
if (i < IV_SIZE)
enc[i] = iv[i];
else if (i < enc.length)
enc[i] = encText[i - IV_SIZE];
}
return enc;
}
public String decrypt(byte[] encryptedText) throws InvalidKeyException,
InvalidAlgorithmParameterException, UnsupportedEncodingException,
IllegalBlockSizeException, BadPaddingException {
byte[] iv = new byte[IV_SIZE];
byte[] dec = new byte[encryptedText.length - IV_SIZE];
for (int i = 0; i < encryptedText.length; i++) {
if (i < IV_SIZE)
iv[i] = encryptedText[i];
else if (i < encryptedText.length)
dec[i - IV_SIZE] = encryptedText[i];
}
cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
return new String(cipher.doFinal(dec), CHARSET_NAME);
}
As you can see, I save a fresh new IV along with the ciphertext everytime I encrypt a message.
In conclusion: I use ONE encryption key, ONE random salt and a new IV for EVERY field in a database table.
First I wanted to generate a new key with a new salt and a new IV everytime I encrypt ONE field in the database table and save the required salt and IV with along with the ciphertext, or at least for one table row. But the reason why I did it like above mentioned is, because generating a key on an Android device takes to much time. I tested in on an emulator, but it took about two seconds for generating a key. This is why I just generated one key when an Activity is started.
So finally my question: With my approach, is it secure enough by using just one key, but fresh random IV's for every message? Currently, I don't see another way to make it as secure as possible by keeping it in balance with performance.
I hope it is clear enough what I wrote and somebody could give me some advice on that.
Kind Regards
xoidberg