javax.crypto.BadPaddingException:给定的最后一个块没有正确填充-奇怪的错误
javax.crypto.BadPaddingException:给定的最后一个块没有正确填充-这就是我得到的错误。我不知道为什么。我的代码似乎没问题。加密和解密期间密钥相同。我能说的是,已经回答的问题中没有一个包含我问题的解决方案。这是我的密码:javax.crypto.BadPaddingException:给定的最后一个块没有正确填充-奇怪的错误,java,security,encryption,cryptography,aes,Java,Security,Encryption,Cryptography,Aes,javax.crypto.BadPaddingException:给定的最后一个块没有正确填充-这就是我得到的错误。我不知道为什么。我的代码似乎没问题。加密和解密期间密钥相同。我能说的是,已经回答的问题中没有一个包含我问题的解决方案。这是我的密码: public String decrypt(String text) throws Exception { String key = "SiadajerSiadajer"; // 128 bit key // Create key
public String decrypt(String text) throws Exception {
String key = "SiadajerSiadajer"; // 128 bit key
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
byte[]encrypted = text.getBytes();
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted = new String(cipher.doFinal(encrypted)); //Here is the error
return decrypted;
}
以及php中的加密机制
function encrypt($data, $size)
{
$length = $size - strlen($data) % $size;
return $data . str_repeat(chr($length), $length);
}
function decrypt($data)
{
return substr($data, 0, -ord($data[strlen($data) - 1]));
}
$key = "SiadajerSiadajer";
$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);
$name = openssl_encrypt(encrypt($name, 16), 'AES-256-CBC', $key, 0, $iv);
编辑
现在在php部分,我的代码是:
$key = "SiadajerSiadajer";
$iv_size = 16; // 128 bits
$iv = openssl_random_pseudo_bytes($iv_size, $strong);
$EIV = base64_encode($iv);
$name = openssl_encrypt(encrypt($name, 16), 'AES-256-CBC', $key, 0, $EIV);
它给了我警告:警告:openssl_encrypt():传递的IV长度为24字节,比所选密码预期的16字节长,在第68行的C:\xampp2\htdocs\standardfinalinserting.php中截断
在Java部分,我的解密方法与我的问题的答案完全相同,但运行后,它会给我一个错误:Java.security.InvalidKeyException:行上的非法密钥大小:
cipher.init(cipher.DECRYPT_模式,aesKey,ivParameterSpec)
编辑2:
所以这是我的全部主要课程。它包含整个Java代码示例
public class Main {
private byte[] padKey(byte[] key) {
byte[] paddedKey = new byte[32];
System.arraycopy(key, 0, paddedKey, 0, key.length);
return paddedKey;
}
private byte[] unpad(byte[] data) {
byte[] unpaddedData = new byte[data.length - data[data.length - 1]];
System.arraycopy(data, 0, unpaddedData, 0, unpaddedData.length);
return unpaddedData;
}
public String decrypt(String encodedJoinedData) throws Exception {
// Base64-decode the joined data
byte[] joinedData = Base64.decode(encodedJoinedData);
// Get IV and encrypted data
byte[] iv = new byte[16];
System.arraycopy(joinedData, 0, iv, 0, iv.length);
byte[] encryptedData = new byte[joinedData.length - iv.length];
System.arraycopy(joinedData, iv.length, encryptedData, 0, encryptedData.length);
// Pad key
byte[] key = padKey("SiadajerSiadajer".getBytes());
Key aesKey = new SecretKeySpec(key, "AES");
// Specify CBC-mode
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec); //HERE IS THE ERROR
// Decrypt data
byte[] decryptedData = cipher.doFinal(encryptedData);
// Remove custom padding
byte[] unpaddedData = unpad(decryptedData);
return new String(unpaddedData);
}
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
String decryptedData = new Main().decrypt(encodedJoinedData);
System.out.println(decryptedData + " - " + decryptedData.length());
}
}
运行代码会导致错误:
Exception in thread "main" java.security.InvalidKeyException: Illegal key size
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1039)
at javax.crypto.Cipher.implInit(Cipher.java:805)
at javax.crypto.Cipher.chooseProvider(Cipher.java:864)
at javax.crypto.Cipher.init(Cipher.java:1396)
at javax.crypto.Cipher.init(Cipher.java:1327)
at com.dd.escuel.Main.decrypt(Main.java:43)
at com.dd.escuel.Main.main(Main.java:57)
Java代码有几个问题:
byte[] unpaddedData = unpad(decryptedData);
SiadajerSiadajer
的长度只有16字节。键填充也必须在Java代码中完成。为此,例如,可以使用以下Java方法:
private byte[] padKey(byte[] key) {
byte[] paddedKey = new byte[32];
System.arraycopy(key, 0, paddedKey, 0, key.length);
return paddedKey;
}
Cipher.getInstance(“AES”)
选择ECB
-模式和PKCS5Padding
。必须在Java代码中使用
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
$options
设置为0
,这意味着返回的数据是Base64编码的。因此,在Java代码中,数据必须在解密之前进行Base64解码:
byte[]encryptedData = Base64.decode(text);
CBC
-模式,因此必须考虑加密的IV
。一种可能的方法是使用Base64在PHP代码(加密之后)中对IV
进行编码
并将该值作为第二个参数传递给Java方法decrypt
。在此,必须对IV
进行解码并用于解密:
byte[] iv = Base64.decode(ivEncoded);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
...
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
openssl\u encrypt
中,第四个参数$options
设置为0
,这意味着使用默认填充(PKCS7
)。此外,在PHP方法encrypt
中,实现了一种自定义填充(顺便说一句:该方法的名称不合适,因为它不加密),因此,它被填充了两次。因此,解密后,必须在Java代码中删除自定义填充(可能包含空格):
byte[] unpaddedData = unpad(decryptedData);
与
public String decrypt(String text, String ivEncoded) throws Exception {
// Pad key
byte[] key = padKey("SiadajerSiadajer".getBytes());
Key aesKey = new SecretKeySpec(key, "AES");
// Base64 decode data
byte[]encryptedData = Base64.decode(text);
// Base64 decode iv
byte[] iv = Base64.decode(ivEncoded);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Specify CBC-mode
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
// Decrypt
byte[] decryptedData = cipher.doFinal(encryptedData);
// Remove custom padding
byte[] unpaddedData = unpad(decryptedData);
return new String(unpaddedData);
}
测试:
PHP代码输入:纯文本($data
),键($key
):
PHP代码输出:Base64编码IV($encodedIV
),加密数据($name
):
如果该输出用作Java方法decrypt
的输入,则解密的数据等于纯文本
关于PHP代码,我建议删除自定义或默认(PKCS7
)填充(如果您有选择的话)。后者可以通过使用标志OPENSSL\u ZERO\u PADDING
作为OPENSSL\u encrypt
方法中的第四个参数来实现(注意:该标志不是指“带零值的pad”,而是“无填充”)。如果保留了自定义填充,则至少应将PHP方法encrypt
和decrypt
分别重命名为pad
和unpad
(或类似的名称)
如评论中所述,GCM
-模式可能比-CBC
模式更好。但是,在编码之前了解基本知识是很有用的,例如,
解释GCM模式以及随GCM模式一起出现的(GCM是安全的,但前提是您遵循某些指导原则,例如,使用相同密钥加密的每条消息的uniqe IV/nonce)
您可以使用PHP方法找出PHP中支持的允许AES模式。这将得到更详细的解释。对于AES-256和AES模式GCM
,必须指定AES-256-GCM
(小写(!)字母)。这大概就是为什么会出现“未知密码算法”——错误
编辑:
您可以使用以下PHP代码进行加密(这是问题中PHP代码的稍微修改版本):
Jave方法解密
变为:
public String decrypt(String encodedJoinedData) throws Exception {
// Base64-decode the joined data
byte[] joinedData = Base64.decode(encodedJoinedData);
// Get IV and encrypted data
byte[] iv = new byte[16];
System.arraycopy(joinedData, 0, iv, 0, iv.length);
byte[] encryptedData = new byte[joinedData.length - iv.length];
System.arraycopy(joinedData, iv.length, encryptedData, 0, encryptedData.length);
// Pad key
byte[] key = padKey("SiadajerSiadajer".getBytes());
Key aesKey = new SecretKeySpec(key, "AES");
// Specify CBC-mode
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, aesKey, ivParameterSpec);
// Decrypt data
byte[] decryptedData = cipher.doFinal(encryptedData);
// Remove custom padding
byte[] unpaddedData = unpad(decryptedData);
return new String(unpaddedData);
}
Java方法main
的示例如下:
public static void main(String[] args) throws Exception {
String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
String decryptedData = new Main().decrypt(encodedJoinedData);
System.out.println(decryptedData + " - " + decryptedData.length());
}
用法如下:
$data = 'This is a plain text which needs to be encrypted...';
decrypt
。在上面的示例(main
-method)中,字符串是
String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
decrypt
将提供初始纯文本$encryptedData = openssl_encrypt(pad($data, 16), 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
与
并移除pad
-和unpad
-方法
在Java代码中,替换行
// Remove custom padding
byte[] unpaddedData = unpad(decryptedData);
return new String(unpaddedData);
与
并删除unpad
-方法
编辑3:
问题的Edit2部分中提到的
InvalidKeyException(非法密钥大小)
已经在这里和这里进行了讨论。Java代码有几个问题:
byte[] unpaddedData = unpad(decryptedData);
SiadajerSiadajer
的长度只有
$data = 'This is a plain text which needs to be encrypted...';
String encodedJoinedData = "RB6Au33KGOF1/z3BQKqievUmh81Y8q4uw7s4vEs9xurQmNZAKwmhRQtS9wGYKQj8cJaPpK2xaDzx3RppQ8PsM/rQ9/p0Lme+x75dozBEbmFn6Q9eCXOCiCivVsKzZ8Vz";
$encryptedData = openssl_encrypt(pad($data, 16), 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
$encryptedData = openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA, $iv);
// Remove custom padding
byte[] unpaddedData = unpad(decryptedData);
return new String(unpaddedData);
return new String(decryptedData);