5

In this code, this line is causing an exception:

clearText = c.doFinal(Base64.decode(encryptedText, Base64.DEFAULT));

javax.crypto.BadPaddingException: pad block corrupted

I got the code from: http://www.techrepublic.com/blog/software-engineer/attention-android-developers-keep-user-data-safe/

Any ideas?

    private String decrypt (String encryptedText) {
        byte[] clearText = null;
        try {
            SecretKeySpec ks = new SecretKeySpec(getKey(), "AES");
            Cipher c = Cipher.getInstance("AES");
            c.init(Cipher.DECRYPT_MODE, ks);
            clearText = c.doFinal(Base64.decode(encryptedText, Base64.DEFAULT));
            return new String(clearText, "UTF-8");
        } catch (Exception e) {
            return null;
        }
    }

Details: I am encrypting it on the android as well

President James K. Polk
  • 40,516
  • 21
  • 95
  • 125
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168

4 Answers4

11

owlstead's advice was helpful, but for this case when using the code in

Attention Android developers: Keep user data safe http://www.techrepublic.com/blog/software-engineer/attention-android-developers-keep-user-data-safe/

I made some changes to the code that might be helpful for other people in the future. I completely deleted the getkey method.

private static String seed;

/**
 * Encrypts the text. 
 * @param clearText The text you want to encrypt
 * @return Encrypted data if successful, or null if unsucessful
 */
protected String encrypt(String clearText) {
    byte[] encryptedText = null;
    try {
        byte[] keyData = seed.getBytes();
        SecretKey ks = new SecretKeySpec(keyData, "AES");
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.ENCRYPT_MODE, ks);
        encryptedText = c.doFinal(clearText.getBytes("UTF-8"));
        return Base64.encodeToString(encryptedText, Base64.DEFAULT);
    } catch (Exception e) {
        return null;
    }
}

/**
 * Decrypts the text
 * @param encryptedText The text you want to encrypt
 * @return Decrypted data if successful, or null if unsucessful
 */
protected String decrypt (String encryptedText) {
    byte[] clearText = null;
    try {
        byte[] keyData = seed.getBytes();
        SecretKey ks = new SecretKeySpec(keyData, "AES");
        Cipher c = Cipher.getInstance("AES");
        c.init(Cipher.DECRYPT_MODE, ks);
        clearText = c.doFinal(Base64.decode(encryptedText, Base64.DEFAULT));
        return new String(clearText, "UTF-8");
    } catch (Exception e) {
        return null;
    }
}   
Esqarrouth
  • 38,543
  • 21
  • 161
  • 168
  • 3
    You should not be creating such examples if you are not sure what you are doing. For instance, you are still using AES ECB mode, which is unsafe. You are using `getBytes()` without specifying an encoding. You are using a string as if it was a key. Basically, you've fixed one issue but kept at least three others. – Maarten Bodewes Nov 30 '13 at 01:37
  • opened up to community wiki in case if you want to fix the things you mentioned. – Esqarrouth Nov 30 '13 at 17:38
  • Thanks, however I would have to do a rewrite, and in the end I would end up with code similar to [this answer](http://stackoverflow.com/questions/4551263/how-can-i-convert-string-to-secretkey/8828196#8828196). Maybe you want to take a look at it, it also contains some security advice. – Maarten Bodewes Nov 30 '13 at 17:45
  • 1
    if i use like above without getKey genaration process, its thowing exception. java.security.InvalidKeyException: Key length not 128/192/256 bits. – Raj Aug 07 '15 at 09:18
6

Java + Android + Encryption + Exception means just one thing normally, somebody is using the SecureRandom class again as a key derivation function. This fails when the SecureRandom implementation of "SHA1PRNG" does not behave as the one in Sun's implementation in Java SE. Especially if the seed is added to the state of the random number generator instead of the seed being used as a starting point of the PRNG.

Basically, simply use SecretKey aesKey = new SecretKeySpec(byte[] keyData, "AES") instead, or - if you start off with a password - try and generate the key using PBKDF2.

Maarten Bodewes
  • 90,524
  • 13
  • 150
  • 263
  • Isn't it more secure in the way stated in the link? If the guy took time to make a guide, it probably works on his machine, but why not mine? – Esqarrouth Nov 14 '13 at 13:19
  • 1
    byte[] keyData = "0123456789012345".getBytes(); SecretKey ks = new SecretKeySpec(keyData, "AES"); I tried this, it works. Buttt, since now it doesn't convert to 128-192-256-bits automatically, I had to enter it manually, I think I need to add a method which converts automatically, any recommendation? – Esqarrouth Nov 14 '13 at 13:57
  • 1
    @Esq There is no standardized way of creating smaller or larger keys by just adding zero values as it would obviously bring down the security provided by the key. So to do this it is required to use a KDF, that could be a KBKDF if there is enough entropy in the key data you now have. If there is less than 16 bytes of data (for AES-128) then you should strengthen the key by using a PBKDF. The PBKDF2 method has been implemented by Java. KBKDF's are not present, but they are relatively easy to construct from a HMAC, e.g. you could use HKDF. – Maarten Bodewes Nov 14 '13 at 16:17
  • Alternatively you can use a simple KDF such as KDF1. Basically you append an four bytes set to zero to the key seed, and then you append an `OtherInfo` structure to that (say, the ASCII representation of `"ENC"` or `"MAC"`). Finally you hash it using any cryptographically secure hash, e.g. SHA-256. Then use the leftmost bytes as output of your KDF. – Maarten Bodewes Aug 17 '15 at 11:11
  • Oh, and I've added the missing KDF's to Bouncy Castle. Alternatively use PBKDF2 with an iteration count of 1 as KBKDF. – Maarten Bodewes Dec 08 '16 at 13:06
1

For me, the problem is in getKey()

Make sure that two invocation of getKey() return the same value.

I used new SecureRandom(password.getBytes()) to generate key. It worked on Windows, but on Android, it returned different value for different call.

BaiJiFeiLong
  • 3,716
  • 1
  • 30
  • 28
  • I have same problem. I have separate the method to encrypt user's password to SHA1PRNG key, but everytime I call that method, it generated many difference strings. – dphans Jan 14 '18 at 07:25
-1

I Reffred From this : https://androidfreetutorial.wordpress.com/2017/03/14/android-encryptiondecryption-with-aes-algorithm/

Change to "AES" From "AES/ECB/PKCS7Padding";