I am making an Android application and I want to encrypt a String before sending it to a DataBase, and encrytpion is correct. The problem happens when decrypting the String because I get a BadPaddingException and I have no idea where the problem is. Here is the code:
public final static String HEX = "36A52C8FB7DF9A3F";
public static String encrypt(String seed, String cleartext) throws Exception
{
byte[] rawKey = getRawKey(seed.getBytes());
byte[] result = encrypt(rawKey, cleartext.getBytes());
return toHex(result);
}
public static String decrypt(String seed, String encrypted) throws Exception
{
byte[] rawKey = getRawKey(seed.getBytes());
byte[] enc = toByte(encrypted);
byte[] result = decrypt(rawKey, enc);
return new String(result);
}
public static String toHex(String txt) {
return toHex(txt.getBytes());
}
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
return raw;
}
private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted = cipher.doFinal(clear);
return encrypted;
}
private static byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
I encrypt and decrypt with this code:
String encrypted = encrypt(HEX, "some text");
String decrypted = decrypt(HEX, encrypted);
Can anyone help me please?
Thank you very much!!
EDIT: Problem is not solved, but I have a bit more information. First of all, I encrypt in a Java project, and I decrypt in an Android project. I have tried to decrypt in the same Java project, and there is no problem, but if I try to decrypt in Android, it doesn't work. The problem is in method "getRawKey" (look at the kgen.generateKey() comment):
JAVA:
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed); //Seed: [51, 54, 65, 53, 50, 67, 56, 70, 66, 55, 68, 70, 57, 65, 51, 70]
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey(); //skey.key = [-97, -52, 45, -95, -64, -58, 16, -20, 124, -50, -104, 58, 23, -75, 88, 94]
byte[] raw = skey.getEncoded();
return raw;
}
ANDROID:
private static byte[] getRawKey(byte[] seed) throws Exception {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed); //Seed: [51, 54, 65, 53, 50, 67, 56, 70, 66, 55, 68, 70, 57, 65, 51, 70]
kgen.init(128, sr); // 192 and 256 bits may not be available
SecretKey skey = kgen.generateKey(); //skey.key = [-114, 32, 16, -52, -81, 125, -88, 88, -76, 20, -117, -11, 33, -61, 32, -91]
byte[] raw = skey.getEncoded();
return raw;
}
I am not a crypt expert, but how can be possible that with the same seed, I get a different key??
For those who wish to use String and Base64-encoding for usage with a database you can use these (slightly rewritten) functions from Mike Keskinov (and xalien on Anddev.org).
This code also uses the built-in Android Base64 libraries, so no need for importing any additional external libraries.
Something I didn't realise at first was how to actually use this class from another class (my ignorance). Here's a simple example:
One more thing on Base64. I found out the hard way that Base64 encoding adds a '/n' linefeed character (0x0a) whenever the string gets longer than 76 characters. This severely messes up the decrypt results. To strip out these newline characters you can add something like:
Hopefully it helps someone.
getRawKey
assumes that theSecureRandom
instance is a well defined, deterministic Pseudo Random Number Generator.First of all, it isn't well defined; the
"SHA1PRNG"
method is not precisely defined. It may - and has - changed even for the SUN provider itself.Second, the fact that seeding the
SecureRandom
instance directly after construction makes it deterministic is SUN provider specific. In other words, other providers may choose to add the seed to the entropy pool. This entropy pool may have already been seeded with values obtained from the operating system. This is the case on many versions of Android. To explain it in layman terms: the AndroidSecureRandom
instance is fully random even if seeded directly after construction. This means that thegetRawKey
method on such systems always generates a new, completely random key.So what's the solution? The solution is either to store the key in a
KeyStore
or to generate a key from a passphrase. In that case you may use the PBKDF2 (password based key derivation function #2) functionality already present in java SE and Android:I had the some problem. The solution:
}
I found this solution here. This works perfect. But I really wonder to know, what was the problem with AES.
From the general perspective , I think BadPaddingException can be due to the following reasons:
i> Incorrect size of the data for the encryption algorithm.
ii> Different keys are being used to encrypt & decrypt data.