使用相同密钥解密 AES 时出现 BadPaddingException
BadPaddingException when decrypting AES with the same key
这是测试人员:
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());
}
}
}
由于最后一个断言而失败:
Assert.fail(e.getMessage());
尝试执行时:
byte[] decrypted = Cryptography.decryptAES(decryptKey, encrypted);
给出此堆栈跟踪:
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.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)
这些是我的职能:
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;
}
}
如果检查键是否相同的断言有效,为什么会出现该异常?
您正在 encryptAES
和 decryptAES
方法中处理 java.security.InvalidKeyException: Illegal key size or default parameters
异常。所以不要吃它们,要么声明为 throws
要么提升为 RuntimeException
.
原来你有两个问题,for this reason, you can't do 256, but 128 solves that, then you are also requesting CBC
without an IvParameterSpec
(导致 java.security.InvalidKeyException: Parameters missing
)。所以提供或更改为 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);
}
密钥长度:
public static byte[] deriveAES256Key(String password)
throws InvalidKeySpecException, NoSuchAlgorithmException {
...
int keyLength = 128; // 256-bits for AES-256, 128-bits for AES
...
所以我让它像那样工作,但第一步是停止吃异常,你会得到更好的线索,可能会自己解决。
我正在使用没有 IvParameterSpec 的 CBC。
加解密解决了:
cipher.init(Cipher."mode here", sKeyS, getIvSpecAES256());
其中 "getIvSpecAES256()" return 总是相同的值。
这是测试人员:
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());
}
}
}
由于最后一个断言而失败:
Assert.fail(e.getMessage());
尝试执行时:
byte[] decrypted = Cryptography.decryptAES(decryptKey, encrypted);
给出此堆栈跟踪:
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.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)
这些是我的职能:
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;
}
}
如果检查键是否相同的断言有效,为什么会出现该异常?
您正在 encryptAES
和 decryptAES
方法中处理 java.security.InvalidKeyException: Illegal key size or default parameters
异常。所以不要吃它们,要么声明为 throws
要么提升为 RuntimeException
.
原来你有两个问题,for this reason, you can't do 256, but 128 solves that, then you are also requesting CBC
without an IvParameterSpec
(导致 java.security.InvalidKeyException: Parameters missing
)。所以提供或更改为 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);
}
密钥长度:
public static byte[] deriveAES256Key(String password)
throws InvalidKeySpecException, NoSuchAlgorithmException {
...
int keyLength = 128; // 256-bits for AES-256, 128-bits for AES
...
所以我让它像那样工作,但第一步是停止吃异常,你会得到更好的线索,可能会自己解决。
我正在使用没有 IvParameterSpec 的 CBC。
加解密解决了:
cipher.init(Cipher."mode here", sKeyS, getIvSpecAES256());
其中 "getIvSpecAES256()" return 总是相同的值。