BadPaddingException when AES decrypted with the same key

This is a tester:

public class CryptographySimpleTests extends ActivityTestCase
{
    public void testsCryptographyClass_encryptAndDecrypt()
    {
        final String orgVal     = "hi world! :D";
        final String key        = "key";

        try
        {
            final byte[] encryptKey       = Cryptography.deriveAES256Key(key);
            final byte[] decryptKey       = Cryptography.deriveAES256Key(key);

            //Deviation method
            Assert.assertTrue(Arrays.equals(encryptKey, decryptKey));

            byte[] encrypted = Cryptography.encryptAES(encryptKey, orgVal.getBytes());

            Assert.assertFalse(Arrays.equals(encrypted, orgVal.getBytes()));

            byte[] decrypted = Cryptography.decryptAES(decryptKey, encrypted);

            Assert.assertTrue(Arrays.equals(orgVal.getBytes(), decrypted));
        }
        catch (Exception e) {
            Assert.fail(e.getMessage());
        }
    }
}

      

Failing due to the last statement:

Assert.fail(e.getMessage());

      

When trying to execute:

byte[] decrypted = Cryptography.decryptAES(decryptKey, encrypted);

      

Gives this stack trace:

javax.crypto.BadPaddingException: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
        at com.android.org.conscrypt.NativeCrypto.EVP_CipherFinal_ex(Native Method)
        at com.android.org.conscrypt.OpenSSLCipher.doFinalInternal(OpenSSLCipher.java:430)
        at com.android.org.conscrypt.OpenSSLCipher.engineDoFinal(OpenSSLCipher.java:466)
        at javax.crypto.Cipher.doFinal(Cipher.java:1340)
        at bdevel.encuentralo.utils.Cryptography.decryptAES(Cryptography.java:59)
        at bdevel.encuentralo.CryptographySimpleTests.testsCryptographyClass_encryptAndDecrypt(CryptographySimpleTests.java:32)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at android.test.InstrumentationTestCase.runMethod(InstrumentationTestCase.java:214)
        at android.test.InstrumentationTestCase.runTest(InstrumentationTestCase.java:199)
        at junit.framework.TestCase.runBare(TestCase.java:134)
        at junit.framework.TestResult$1.protect(TestResult.java:115)
        at junit.framework.TestResult.runProtected(TestResult.java:133)
        at junit.framework.TestResult.run(TestResult.java:118)
        at junit.framework.TestCase.run(TestCase.java:124)
        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:191)
        at android.test.AndroidTestRunner.runTest(AndroidTestRunner.java:176)
        at android.test.InstrumentationTestRunner.onStart(InstrumentationTestRunner.java:555)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1837)

      

These are my functions:

public class Cryptography {

    /**
     * @param key           AES Key
     * @param inputValue    Data to encrypt
     * @return Can return null if something goes wrong
     */
    public static byte[] encryptAES(byte[] key, byte[] inputValue)
            throws NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException
    {
        SecretKeySpec sKeyS = new SecretKeySpec(key, "AES");

        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, sKeyS);
        }
        catch (NoSuchAlgorithmException | InvalidKeyException i) {
            cipher = null;
        }

        return cipher != null ? cipher.doFinal(inputValue) : null;
    }

    public static byte[] decryptAES(byte[] key, byte[] encryptedData)
            throws NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException
    {
        SecretKeySpec sKeyS = new SecretKeySpec(key, "AES");

        Cipher cipher = null;
        try {
            cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, sKeyS);
        }
        catch (NoSuchAlgorithmException | InvalidKeyException i) {
            cipher = null;
        }

        return cipher != null ? cipher.doFinal(encryptedData) : null;
    }

    private static byte[] deriveAES256KeySalt = null;
    public static byte[] deriveAES256Key(String password)
            throws InvalidKeySpecException, NoSuchAlgorithmException
    {

    /* Store these things on disk used to derive key later: */
        int iterationCount = 1000;
        int saltLength = 32; // bytes; should be the same size as the output (256 / 8 = 32)
        int keyLength = 256; // 256-bits for AES-256, 128-bits for AES-128, etc

    /* When first creating the key, obtain a salt with this: */
    if(deriveAES256KeySalt == null) {
        SecureRandom random = new SecureRandom();
        deriveAES256KeySalt = new byte[saltLength];
        random.nextBytes(deriveAES256KeySalt);
    }

    /* Use this to derive the key from the password: */
        KeySpec keySpec = new PBEKeySpec(password.toCharArray(), deriveAES256KeySalt, iterationCount, keyLength);
        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();

        return keyBytes;
    }
}

      

If the assertion that checks if the keys work the same, why am I getting this exception?

+3


source to share


2 answers


You are eating an exception java.security.InvalidKeyException: Illegal key size or default parameters

in your methods encryptAES

and decryptAES

. So don't eat them, throws

advertise them or advertise them RuntimeException

.

It turns out that you have two problems: for this reason , you cannot do 256, but 128 solves that, then you also ask CBC

without IvParameterSpec

(which causes java.security.InvalidKeyException: Parameters missing

). So put this or change to ECB

:

public static byte[] encryptAES(byte[] key, byte[] inputValue)
        throws NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeyException {
    SecretKeySpec sKeyS = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.ENCRYPT_MODE, sKeyS);

    return cipher.doFinal(inputValue);
}

public static byte[] decryptAES(byte[] key, byte[] encryptedData)
        throws NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, NoSuchAlgorithmException, InvalidKeyException {
    SecretKeySpec sKeyS = new SecretKeySpec(key, "AES");

    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
    cipher.init(Cipher.DECRYPT_MODE, sKeyS);

    return cipher.doFinal(encryptedData);
}

      



Key length:

public static byte[] deriveAES256Key(String password)
                throws InvalidKeySpecException, NoSuchAlgorithmException {

   ...
    int keyLength = 128; // 256-bits for AES-256, 128-bits for AES
   ...

      

So I worked like this, but the first step is to stop there is an exception and you will get better hints and will probably work on your own.

+3


source


I am using CBC without IvParameterSpec.

It was decided to add the following for encryption and decryption:



cipher.init(Cipher."mode here", sKeyS, getIvSpecAES256()); 

      

Where "getIvSpecAES256 ()" always returns the same value.

-1


source







All Articles