Android aes encryption pad block corrupted - android

I am using the methods below and if I enter the right key everything works fine.
But if I enter a wrong key I am receiving a BadPaddingException:pad block corrupted...
Am I doing something wrong?
public void initKey(String passwd, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException{
byte[] localsalt = salt;
PBEKeySpec password = new PBEKeySpec(passwd.toCharArray(),localsalt, 1024,128);//, localsalt, 1000, 128); //128bit enc aes
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBEWithMD5And128BitAES-CBC-OpenSSL","BC");
PBEKey key = (PBEKey) factory.generateSecret(password);
encKey = new SecretKeySpec(key.getEncoded(), "AES");
}
public String txt2enc(String etxt) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
final Cipher cipher = Cipher.getInstance("AES");//AES
cipher.init(Cipher.ENCRYPT_MODE, encKey);
byte[] encrypted = cipher.doFinal((etxt).getBytes("UTF-8"));
return Base64.encodeToString(encrypted, 0);
}
//decryption
public String txt2dec(String dtxt) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException{
final Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, encKey);
byte[] decrypt = cipher.doFinal(Base64.decode(dtxt, 0));
return new String(decrypt);//return Base64.encodeToString(decrypt, 0);
}

You're not doing anything wrong. It's expected. This is technically a duplicate of Java Encryption issue (which doesn't seem to be easy to find). See this answer for a good explanation. You can consider adding a MAC (Message Authentication Code) to safely accomplish something more like a checksum.

Other than supplying the wrong key, I don't think so :)
A stack trace would help, so we can see which function is throwing the BadPaddingException.
This may well be because the 'bad' key is a different length to the 'good' key - does the 'bad' key come out of initKey() or somewhere else?
Best wishes,
Phil Lello

Related

AES-GCM 256 bit - Node.js encrypt / Android decrypt - 16 byte authentication tags don't match

Trying to use AES-GCM 256 to encrypt "Hello World" in Node.js in such a way that the encrypted string sent ota to an Android phone can be decrypted. The Node.js encryption code is:
const KEY = new Buffer('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21', 'hex');
var iv = Buffer.from("0000000000000000",'base64');
var cipher = crypt.createCipheriv('aes-256-gcm', Buffer.from(KEY, 'utf-8'), iv);
var ciph = cipher.update(Buffer.from("Hello World", 'utf-8'), 'utf8', 'base64');
ciphered += cipher.final('base64');
console.log(cipher.getAuthTag().toString('base64'));
and the Android (Studio) decryption code is:
public static byte[] decrypt(byte[] data)
throws CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException,
KeyStoreException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKey secretKey = null;
byte[] decodedKey = new byte[] {(byte)0x1b,(byte)0xc0,(byte)0xd5,(byte)0x63,(byte)0x32,(byte)0x9d,(byte)0x29,(byte)0xfc,(byte)0x62,(byte)0x36,(byte)0xf0,(byte)0x99,(byte)0x37,(byte)0x1e,(byte)0x33,(byte)0x4f,(byte)0xeb,(byte)0x9b,(byte)0xbf,(byte)0x3e,(byte)0x91,(byte)0xbb,(byte)0xa2,(byte)0xad,(byte)0xb4,(byte)0x04,(byte)0x3f,(byte)0xeb,(byte)0x87,(byte)0x0b,(byte)0x6b,(byte)0x21};
secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
byte[] iv = Base64.decode("0000000000000000", Base64.DEFAULT);
GCMParameterSpec gcmspec = new GCMParameterSpec(128, iv);
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
cipher.init(Cipher.DECRYPT_MODE, secretKey, gcmspec);
return cipher.doFinal(data);
}
which fails to decrypt because of authentication tag mismatch. I verified the tags don't match by encrypting the same string in Android with the same key and initialization vector:
public void TEST_ENCRYPT() throws IOException, CertificateException, NoSuchAlgorithmException, InvalidKeyException, UnrecoverableEntryException, InvalidAlgorithmParameterException, NoSuchPaddingException, NoSuchProviderException, BadPaddingException, KeyStoreException, IllegalBlockSizeException {
String inputString = "Hello World";
byte[] byteArray = inputString.getBytes();
String value = Base64.encodeToString(encrypt(byteArray), Base64.DEFAULT);
Log.d("TEST_ENCRYPT", value);
}
public static byte[] encrypt(byte[] data)
throws CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableEntryException,
KeyStoreException, NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,
InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
SecretKey secretKey = null;
byte[] decodedKey = new byte[] {(byte)0x1b,(byte)0xc0,(byte)0xd5,(byte)0x63,(byte)0x32,(byte)0x9d,(byte)0x29,(byte)0xfc,(byte)0x62,(byte)0x36,(byte)0xf0,(byte)0x99,(byte)0x37,(byte)0x1e,(byte)0x33,(byte)0x4f,(byte)0xeb,(byte)0x9b,(byte)0xbf,(byte)0x3e,(byte)0x91,(byte)0xbb,(byte)0xa2,(byte)0xad,(byte)0xb4,(byte)0x04,(byte)0x3f,(byte)0xeb,(byte)0x87,(byte)0x0b,(byte)0x6b,(byte)0x21};
secretKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
Cipher cipher = Cipher.getInstance(ALGORITHM_NAME);
byte[] iv = Base64.decode("0000000000000000", Base64.DEFAULT);
GCMParameterSpec gcmspec = new GCMParameterSpec(128, iv);
try {
cipher.init(Cipher.ENCRYPT_MODE, secretKey, gcmspec);
}catch(Exception e)
{
Log.d("error", e.toString());
}
return cipher.doFinal(data);
}
and comparing the appended 16 bytes to the encrypted message (i.e. the Android authentication tag) to the Node.js authentication tag. This authentication tag mismatch occurs despite the fact the encrypted messages are the same, and makes decryption of messages on the Android phone throw errors. How can this problem be solved? I would expect the AES-GCM 256 algorithm to work the same on both client and server.
Look at your Buffer:
new Buffer('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21');
This is not what you expect, this is simply a string.
You need this:
Buffer.from('1bc0d563329d29fc6236f099371e334feb9bbf3e91bba2adb4043feb870b6b21', 'hex');

RSA Encryption/Decryption Convert Byte[] to String and Vice Versa

I am workin on a Rsa encrypt/decrypt application on android.I create and save my public/private key to sharedpreferences.I am reading them and using for encrypt/decrypt with this code block:
public String RSADecrypt(byte[] encryptedBytes) throws NoSuchAlgorithmException, NoSuchPaddingException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, UnsupportedEncodingException {
privateKey = getPrivateKey();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] cipherData = cipher.doFinal(encryptedBytes);
return new String(cipherData,"UTF-16BE");
}
public String RSAEncrypt(String plain) throws NoSuchAlgorithmException, NoSuchPaddingException,InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidKeySpecException, UnsupportedEncodingException {
publicKey = getPublicKey();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipherData = cipher.doFinal(plain.getBytes());
return new String(cipherData,"UTF-16BE");
}
Now, for example i am trying to encrypt "BAHADIR", it writes to EditText meaningless words. I used "UTF-8", "UTF-16", "UTF-16LE", "UTF16BE" and "ISO-8859-1" but everytime i get meaningless words again, not same but all of them meaningless. Where am i wrong, can you help me? Thank you.
You shouldn't convert binary data to a String. You can, for example, encode it with Base64 encoding if you want it as a printable String.
Try the following:
import android.util.Base64
...
byte[] cipherData = cipher.doFinal(encryptedBytes);
String cipherString = Base64.encodeBytes(cipherData);

AES Decryption: javax.crypto.BadPaddingException: pad block corrupted in Android

I am stuck with a problem with AES Decryption in my android Application. I have searched a lot but unable to get the solution.
Here are the steps, what i am doing.
Encrypt the credit card number with my key send to the Web server.
Web server Decrypt the credit card number and save it.
When we fetch the credit card number from the Web service.
Then web server encrypt the credit card number with the same key and send to Us.
Now When we decrypt this number, it throws bad padding exception for some credit card number information.
Also encrypted information is not same coming from the server, what we have send in encrypted format.
While the same thing is done in iPhone app, and iPhone is able to decrypt the information successfully.
I am using the following code for encryption and decryption.
public class AES256Cipher {
public static byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
public static String AES_Encode(String str, String key) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] textBytes = str.getBytes("UTF-8");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = null;
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, newKey, ivSpec);
return Base64.encodeToString(cipher.doFinal(textBytes), 0);
}
public static String AES_Decode(String str, String key) throws java.io.UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
byte[] textBytes =Base64.decode(str,0);
//byte[] textBytes = str.getBytes("UTF-8");
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
SecretKeySpec newKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, newKey, ivSpec);
return new String(cipher.doFinal(textBytes), "UTF-8");
}
Please suggest.
EDIT:
I one more thing, it is working for < 16 digits information. When we put the 16 digit information, then it is throwing the Exception in decryption.
If the server encounters unknown encodings that don't map to specific characters then the key will not transfer properly and fail once in a while, resulting in an incorrect key. The ciphertext is encoded using base64 so that's probably OK, but your key may not be so lucky.
Note that any change in the key or the last blocks of the ciphertext is likely to result in a BadPaddingException.

Decrypt Files Encrypted with Sun Crypto Provider on Android (AES)

I have a Java application that runs on desktop computers. It encrypts and decrypts its documents using AES. When I encrypt a file using the desktop version, and decrypt it in the Android emulator, the decryption fails. The cipher.doFinal line throws this exception: javax.crypto.BadPaddingException: pad block corrupted.
When the desktop version runs, it uses the Sun crypto provider. When the Android version runs, it uses the BouncyCastle provider. I realize that the call to Cipher.getInstance is only specifying the algorithm ("AES"). I have tried to specify the algorithm, mode, and padding scheme. For instance, Cipher.GetInstance("AES/ECB/PKCS5Padding"), but, I have yet to determine a mode and padding scheme that is compatible between the Sun crypto provider and BouncyCastle.
I realize that I could simply bundle BouncyCastle with my application, and use it on the desktop and in Android, but I'd prefer not to. I'd also like to avoid any solution to this problem that forces users of the desktop program to convert their encrypted files into a format that works in Android.
My question is: how can I successfully decrypt, on Android, files that were encrypted using the Sun crypto provider?
Sincerely,
Eric Bergman-Terrell
www.EricBT.com
private static byte[] getPasswordMessageDigest(String password) throws NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-512");
byte[] passwordMessageDigest = messageDigest.digest(password.getBytes());
return passwordMessageDigest;
}
public static SecretKey createSecretKey(String password) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] passwordMessageDigest = getPasswordMessageDigest(password);
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(passwordMessageDigest);
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
return secretKey;
}
public static byte[] encrypt(String password, byte[] plainText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES");
SecretKey secretKey = createSecretKey(password);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText);
return cipherText;
}
public static byte[] decrypt(String password, byte[] cipherText) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
Cipher cipher = Cipher.getInstance("AES");
SecretKey secretKey = createSecretKey(password);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] plainText = cipher.doFinal(cipherText);
return plainText;
}

android encryption

I want to encrypt/decrypt some passwords in the SQLite database of my application. To do that I have searched on the internet and I have found the AES algorithm.
I have this code:
public String encript(String dataToEncrypt)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
// I'm using AES encription
if(!dataToEncrypt.equals("")){
String key = "FMVWf8d_sm#fz";
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k;
try {
k = new SecretKeySpec(key.getBytes(), "AES");
c.init(Cipher.ENCRYPT_MODE, k);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return new String(c.doFinal(Base64.decode(dataToEncrypt)));
}
return "";
}
public String decript(String encryptedData)
throws NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
if(!encryptedData.equals("")){
String key = "FMVWf8d_sm#fz";
Cipher c = Cipher.getInstance("AES");
SecretKeySpec k = new SecretKeySpec(Base64.decode(key), "AES");
c.init(Cipher.DECRYPT_MODE, k);
return new String(c.doFinal(Base64.decode(encryptedData)));
}
return "";
}
After running this I get this error on encrypt method:
01-27 14:50:51.698: ERROR/ACTIVITY(782):
java.security.InvalidKeyException: Key length not 128/192/256 bits.
I have seen some other cases here on stackoverflow but I want to give the key to the AES not to generate it...
Can somebody help me with this? If there is other encryption method to use but without using another jars or external classes and to let me give the key.
Thank you very much!
The error message makes it perfectly clear: your encryption key must be of certain size: 128, 192 or 256 bits. And your key is 104 bits. Note, that as you want to use only printable characters in your key, the length of the key should be 192 or longer bits, cause your alphabet (set of characters that you use) makes encryption weaker.
Usual practice is such:
Get password (in your case String key = "FMVWf8d_sm#fz";)
Generate using some hash function key with length 128, 192 or 256
Put it into encryption algorithm
Have fun
So you are missing key generation stage. Do smth like:
// Get the KeyGenerator
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128); // 192 and 256 bits may not be available
// Generate the secret key specs.
SecretKey skey = kgen.generateKey();
byte[] raw = skey.getEncoded();
SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
byte[] encrypted =
cipher.doFinal((args.length == 0 ?
"This is just an example" : args[0]).getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] original =
cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " +
originalString + " " + asHex(original));

Categories

Resources