java - Java AES 给出 BadPaddingException
问题描述
我正在尝试用 Java 为我的程序编写一个简单的加密和解密方法。它应该使用另一个字符串作为密钥来加密和解密一个字符串。
在测试时,BadPaddingException
发生了一个。
我目前的加密方法:
public String encrypt(String strToEncrypt, String secretKey) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] salt = new Hash().hashString(secretKey).getBytes();
KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
byte[] ciphertext = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
System.out.println("Finished encryption");
return new Base64().encodeToString(ciphertext);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
我目前的解密方法:
public String decrypt(String strToDecrypt, String secretKey) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] salt = new Hash().hashString(secretKey).getBytes();
KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
byte[] decodedPlaintext = new Base64().decode(strToDecrypt);
byte[] plaintext = cipher.doFinal(decodedPlaintext);
System.out.println("Finished decryption");
return new Base64().encodeToString(plaintext);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
我收到以下异常:
javax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.
at java.base/com.sun.crypto.provider.CipherCore.unpad(CipherCore.java:975)
at java.base/com.sun.crypto.provider.CipherCore.fillOutputBuffer(CipherCore.java:1056)
at java.base/com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:853)
at java.base/com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:446)
at java.base/javax.crypto.Cipher.doFinal(Cipher.java:2202)
解决方案
在 Michael 和总裁 James K. Polk 的帮助下,我可以进行加密和解密工作,并改进了盐的生成。我的错误是,我没有使用相同IvParameterSpec
的加密和解密。
我的加密方法:
public static String encrypt(String strToEncrypt, String secretKey) {
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] salt = new byte[16];
SecureRandom.getInstanceStrong().nextBytes(salt);
KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = cipher.getParameters().getParameterSpec(IvParameterSpec.class).getIV();
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secret, ivspec);
byte[] ivBytes = ivspec.getIV();
byte[] ciphertext = cipher.doFinal(strToEncrypt.getBytes("UTF-8"));
System.out.println("Finished encryption");
byte[] outputBytes = concat(concat(salt, ivBytes), ciphertext);
return new Base64().encodeToString(outputBytes);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
我的解密方法:
public static String decrypt(String strToDecrypt, String secretKey) {
try {
byte[] decodedCiphertext = new Base64().decode(strToDecrypt);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
byte[] salt = Arrays.copyOfRange(decodedCiphertext, 0, 16);
KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = Arrays.copyOfRange(decodedCiphertext, 16, 32);
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
byte[] plaintext = cipher.doFinal(Arrays.copyOfRange(decodedCiphertext, 32, decodedCiphertext.length));
System.out.println("Finished decryption");
return new String(plaintext, "UTF-8");
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
推荐阅读
- angular - 从浏览器控制台中删除错误消息(Angular HttpClient)
- r - Change Y-axis from exponential to integer
- python - 在 python 脚本中解析输入文件
- python - 如何使用 asyncio 遍历长度不确定的迭代器
- java - Thymeleaf spring 安全方言根本不起作用
- macos - 如何在事件中处理彩虹光标
- reactjs - 我可以将我在 Windows 上开发的应用程序导出到 iPhone 上吗?
- javascript - Highcharts气泡图数据标签不显示
- oracle - 如何将 Oracle 查询的输出导出到 AWS RDS 实例中的 csv 文件
- python - ValueError:目标是多类但平均值='二进制'。请选择其他平均设置