I have found hundreds of examples of Android AES encryption and decryption but I am unable to make them work, even the simplest. The following code does some encryption and decryption but it spits out garbage after decrypting the encrypted text. Can you please take a look and tell me where I am wrong?
Thanks
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom());
SecretKey secretKey = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES");
String plainText = "This is supposed to be encrypted";
String plainKey = Base64.encodeToString(secretKey.getEncoded(), Base64.DEFAULT);
//encrypt
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
String encryptedText = Base64.encodeToString(encryptedBytes, Base64.DEFAULT);
//decrypt
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[]decryptedBytes = cipher.doFinal(encryptedBytes);
String decryptedText = Base64.encodeToString(decryptedBytes, Base64.DEFAULT);
#Barend answer works:
Your code works fine. What #greenapps said. Instead of Base64.encodeToString(..), try printing the output of new String(decryptedBytes), you'll see that it's the value you were looking for.
SecretKeySpec sks = null;
try {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed("Complex Key for encryption".getBytes());
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, sr);
sks = new SecretKeySpec((kg.generateKey()).getEncoded(), "AES");
} catch (Exception e) {
Log.e(TAG, "AES secret key spec error");
}
// Encode the original data with AES
byte[] encodedBytes = null;
try {
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, sks);
encodedBytes = c.doFinal(theTestText.getBytes());
} catch (Exception e) {
Log.e(TAG, "AES encryption error");
}
TextView tvencoded = (TextView)findViewById(R.id.textitem2);
tvencoded.setText("[ENCODED]:\n" +
Base64.encodeToString(encodedBytes, Base64.DEFAULT) + "\n");
// Decode the encoded data with AES
byte[] decodedBytes = null;
try {
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, sks);
decodedBytes = c.doFinal(encodedBytes);
} catch (Exception e) {
Log.e(TAG, "AES decryption error");
}
TextView tvdecoded = (TextView)findViewById(R.id.textitem3);
tvdecoded.setText("[DECODED]:\n" + new String(decodedBytes) + "\n");
Related
I am implementing encryption/decryption to my files. code is given below. I can't find out the problem.
Am I missing anything? I need to implement 128 bit AES Encryption.
Is there anything wrong?
It end up with error
"javax.crypto.BadPaddingException: error:1e06b065:Cipher functions:EVP_DecryptFinal_ex:BAD_DECRYPT"
Please help me.
private static byte[] encodeFile(byte[] yourKey, byte[] fileData)
throws Exception {
byte[] encrypted = null;
SecretKeySpec skeySpec = new SecretKeySpec(yourKey, 0, yourKey.length, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
encrypted = cipher.doFinal(fileData);
return encrypted;
}
private static byte[] generateKey() throws NoSuchAlgorithmException {
byte[] keyStart = "This is my key".getBytes();
String id = "dummypass";
int iterationCount = 1000;
int saltLength = 32;
int keyLength = 128;
SecureRandom random = new SecureRandom();
byte[] salt = Arrays.copyOf(keyStart,saltLength);
random.nextBytes(salt);
KeySpec keySpec = new PBEKeySpec(id.toCharArray(), salt,
iterationCount, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
byte[] keyBytes = new byte[0];
try {
keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
} catch (InvalidKeySpecException e) {
e.printStackTrace();
}
SecretKey key = new SecretKeySpec(keyBytes, "AES");
return key.getEncoded();
}
private static byte[] decodeFile(byte[] yourKey, byte[] encryptedData)
throws Exception {
SecretKeySpec skeySpec = new SecretKeySpec(yourKey, 0, yourKey.length,
"AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encryptedData);
return decrypted;
}
public static void Encrypt(byte[] bytesToEncrypt, File target) {
try {
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(target));
byte[] key = generateKey();
byte[] encryptedBytes = encodeFile(key, bytesToEncrypt);
bos.write(encryptedBytes);
bos.flush();
bos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] DecryptFile(byte[] bytesToDecrypt) {
byte[] decodedData = new byte[0];
try {
byte[] key = generateKey();
decodedData = decodeFile(key, bytesToDecrypt);
} catch (Exception e) {
e.printStackTrace();
}
return decodedData;
}
Verify that key is the same in both Encrypt and DecryptFile.
Since both call generateKey and generateKey calls SecureRandom nextBytes the keys are going to be different.
You need to save the encryption key for use during decryption.
I have to encrypt and decrypt text on android devices. I have found some solution, but when I encrypt the text again, the result is different. Can anyone tell me why?
Here is my code:
public class AESDemo {
private static final String password = "test";
private static String salt;
private static int pswdIterations = 65536;
private static int keySize = 256;
private byte[] ivBytes;
public String encrypt(String plainText) throws Exception {
//get salt
salt = generateSalt();
byte[] saltBytes = salt.getBytes("UTF-8");
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
//null,
pswdIterations,
keySize
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
//encrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(plainText.getBytes("UTF-8"));
//return new Base64().encodeAsString(encryptedTextBytes);
return Base64.encodeToString(encryptedTextBytes, Base64.DEFAULT);
}
#SuppressWarnings("static-access")
public String decrypt(String encryptedText) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8");
//byte[] encryptedTextBytes = new Base64().decodeBase64(encryptedText);
byte[] encryptedTextBytes= Base64.decode(encryptedText, Base64.DEFAULT);
// Derive the key
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(
password.toCharArray(),
saltBytes,
pswdIterations,
keySize
);
SecretKey secretKey = factory.generateSecret(spec);
SecretKeySpec secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
// Decrypt the message
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
public String generateSalt() {
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[20];
String ss = "";
random.nextBytes(bytes);
String s = new String(bytes);
return "sare";
}
}
I've hardcoded the salt to be the same, but the result is different every time. Can anyone tell me why?
Your IV handling puzzles me. You call getIV() but where do you actually set the IV for the encryption? It seems to me you are using a random IV which might explain why you get a different encrypted data each time.
I would suggest to try create a dynamic IvParameterSpec class and fill it with a preset IV.
i try to cipher but my outputs after "cipher.init" won't output. Also no exceptions..and I don't know why...(new on android)
public void login() {
LoginData loginData = this.fragmentBox.getUpdatedLoginData();
String finishString = new String();
try {
Cipher cipher = Cipher.getInstance("AES");
byte[] output = null;
SecretKeySpec secretKey = new SecretKeySpec(
Globals.ENCRYPTPW.getBytes(), "AES");
System.out.println(secretKey.getEncoded().toString() + "----" + Globals.ENCRYPTPW);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
output = cipher.doFinal(loginData.getPassword().getBytes());
byte[] encryptedUsernameString = Base64.encode(output, 0);
finishString = new String(encryptedUsernameString, "UTF-8");
} catch (InvalidKeyException e) {
e.getStackTrace();
Log.v("Fehler im Code","");
} catch(Exception e){}
System.out.println("Code: " + finishString);
}
any idea?
I have done an encryption using the AES but iam not able to do the decryption Iam gettin an javax.crypto.IllegalBlockSizeException: last block incomplete in decryption.....I cant trace out where is the problem.I appreciate any help.
try {
in = new FileInputStream("/sdcard/Pic 1.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
File f=new File("/sdcard/Pic 1.txt");
buf = new byte[(int) f.length()+2];
try {
in.read(buf);
} catch (IOException e) {
e.printStackTrace();
}
try {
decryptedData = decrypt(key, buf);
decryptedimage = BitmapFactory.decodeByteArray(
decryptedData, 0, decryptedData.length);
loadedimage.setImageBitmap(decryptedimage);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public void Encription(Bitmap bm) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.JPEG, 100, baos);
b = baos.toByteArray();
try {
keyStart = ".....".getBytes();
kgen = KeyGenerator.getInstance("AES");
sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(keyStart);
kgen.init(128, sr); // 192 and 256 bits may not be available
skey = kgen.generateKey();
key = skey.getEncoded();
encryptedData = encrypt(key, b);
encryptedimage = BitmapFactory.decodeByteArray(encryptedData, 0,
encryptedData.length);
out = new FileOutputStream("/sdcard/"+"Pic "+i+".txt");
out.write(encryptedData, 0, encryptedData.length);
out.close();
} catch (Exception e) {
}
i++;
}
private 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 byte[] decrypt(byte[] raw, byte[] encrypted) throws Exception {
long start=System.currentTimeMillis()/1000l;
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal(encrypted);
return decrypted;
}
02-19 08:27:06.972: W/System.err(12742): javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
I'm a newbie to android dev, right now I implemented an AES on Android and it could encrypt strings with user input passwords. The encryption seems fine and it could omit Base64/Hex encoded strings.
But When I try to decrypt it, the problem comes: With the decryption, the omission always showing me a load of messy characters.
In order to get rid of it, I've tried debugging it by define a charset (Like UTF-8) while casting from string to byte[], but no hit, and also tried to encode the omit with base 64 or Hex, but both of them failed.
I've also tried to define AES/CBC/PKCS5Padding or just AES while using cipher.getInstance method, but still no go.
It is quite irritating, could you guys help me please?
Forgot to mention that I once asked a similar question https://stackoverflow.com/questions/6727255/aes-decryption-on-android-not-correct , the grammer problem there have been corrected.
And Here's the code:
For Encryption
public String AESEncrypt(String sKey, String PlainMsg)
throws Exception {
//Try use some Android based alert dialog to catch this exception.
if (sKey == null) {
Log.e("SecureChat", "IllegalArgumentException Catched");
throw new IllegalArgumentException ("NULL Secret NOT ALLOWED!");
}
/*Old Method
//byte[] rawKey = getRawKey(sKey.getBytes("UTF-8"));
byte[] rawKey = getRawKey(sKey.getBytes());
//Encrypt start
SecretKeySpec keySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, keySpec);
//byte[] cipherText = cipher.doFinal(PlainMsg.getBytes("UTF-8"));
byte[] cipherText = cipher.doFinal(PlainMsg.getBytes());
return Base64Encoded(cipherText);
*/
//New Method
byte[] salt = getSalt();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec(sKey.toCharArray(), salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
//Encryption Process
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
byte[] cipherText = cipher.doFinal(PlainMsg.getBytes());
//return Base64Encoded(cipherText);
//Hex
return toHex(cipherText);
}
For Decryption
public String AESDecrypt(String sKey, String EncryptMsg)
throws Exception {
/*Old Method
//byte[] rawKey = getRawKey(sKey.getBytes("UTF-8"));
byte[] rawKey = getRawKey(sKey.getBytes());
SecretKeySpec keySpec = new SecretKeySpec(rawKey, "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, keySpec);
//byte[] plainText = Base64Decoded(EncryptMsg.getBytes("UTF-8"));
byte[] plainText = Base64Decoded(EncryptMsg);
cipher.doFinal(plainText);
return new String(plainText, "UTF-8");
*/
//New Method
byte[] salt = getSalt();
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
KeySpec spec = new PBEKeySpec(sKey.toCharArray(), salt, 1024, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
//byte[] bCipherText = Base64Decoded(EncryptMsg);
//Hex
byte[] bCipherText = toByte(EncryptMsg);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
cipher.doFinal(bCipherText);
return new String(bCipherText);
}
private byte[] getSalt() throws NoSuchAlgorithmException {
/*Mark for old key method
//Initialize the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
//Init for 256bit AES key
kgen.init(Constants.AES_KEY_SIZE, sr);;
SecretKey secret = kgen.generateKey();
//Get secret raw key
byte[] rawKey = secret.getEncoded();
return rawKey;
*/
//New key method with some salt
SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
byte[] ransalt = new byte[20];
random.nextBytes(ransalt);
return ransalt;
}
#Override
public byte[] getRawKey(byte[] seed) throws Exception {
/*Old Method
//Initialize the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
sr.setSeed(seed);
//Init for 256bit AES key
kgen.init(Constants.AES_KEY_SIZE, sr);
SecretKey secret = kgen.generateKey();
//Get secret raw key
byte[] rawKey = secret.getEncoded();
return rawKey;
*/
return null;
}
/**
*
* #param toBeDecoded
* #return
*/
public byte[] Base64Decoded(String toBeDecoded) {
byte[] decoded = Base64.decode(toBeDecoded, 0);
return decoded;
}
//Hex Mode
public String toHex(String txt) {
return toHex(txt.getBytes());
}
public String fromHex(String hex) {
return new String(toByte(hex));
}
public 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 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 final String HEX = "0123456789ABCDEF";
private void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
}
I've referenced/compared with these code on Stackoverflow:
Android aes encryption pad block corrupted
and
incorrect decryption using AES/CBC/PKCS5Padding in Android
Seems that my problem lies on the charset encoding, but I cannot find out where the problem is.
Any comments/answers are very appreciated!
Thank you for helping me!
This code I wrote works flawlessly. Look at this link below:
http://pocket-for-android.1047292.n5.nabble.com/Encryption-method-and-reading-the-Dropbox-backup-td4344194.html#a4454327
Without looking too carefully at your code I would suggest you should specify the encoding here though I'm not sure if this is the cause of your problems:
byte[] cipherText = cipher.doFinal(PlainMsg.getBytes());
and here:
return new String(bCipherText);