AES CBC无填充在解密JAVa中提供额外字符
我试图在JAVA中使用AES/CBC/NOP加密和解密。我使用(mcrypt)在JAVA和PHP中进行了加密,得到了相同的结果,使用了相同的密钥和iv。然而,当我尝试用JAVA解密时,我得到了正确的单词,但总是带有额外的字符。我阅读了其他问题,发现我需要添加填充。所以我添加了Padding5,但得到了相同的结果。不管怎么说,我需要它而不需要填充,因为这就是它在PHP中的工作方式。感谢您的帮助。我的代码如下,结果如下:] PHP mcrypt包装器(或底层mcrypt库)填充零字节,直到块长度(如果16是密码的块大小,则填充零到15个字节)。在这之后,块被加密 在Java中解密时,需要使用AES CBC无填充在解密JAVa中提供额外字符,java,encryption,aes,Java,Encryption,Aes,我试图在JAVA中使用AES/CBC/NOP加密和解密。我使用(mcrypt)在JAVA和PHP中进行了加密,得到了相同的结果,使用了相同的密钥和iv。然而,当我尝试用JAVA解密时,我得到了正确的单词,但总是带有额外的字符。我阅读了其他问题,发现我需要添加填充。所以我添加了Padding5,但得到了相同的结果。不管怎么说,我需要它而不需要填充,因为这就是它在PHP中的工作方式。感谢您的帮助。我的代码如下,结果如下:] PHP mcrypt包装器(或底层mcrypt库)填充零字节,直到块长度(如
NoPadding
手动删除解密后明文右侧的任何零字节。当十六进制编码解密的明文时,当然可以看到零值填充字节。但是,在输出字符串时,零字节要么被省略,要么被转换为替换字符(取决于字符集和终端)
请注意,PHP零填充有一个很大的缺点:如果明文以一个或多个零值字节结尾,则可以通过任何取消添加的例程将其从解密的明文中剥离。这就是为什么PKCS#7填充(填充1到16字节)应该是首选的原因
还要注意,PHP实际上需要rtrim(“\0”)
来删除零字节本身;mcrypt只是把它们留在那里,但通常不会打印出来
请注意,Bouncy Castle crypto库还具有
ZeroPadding
作为选项。但是,这是1到16字节的零填充(即,它总是填充/取消填充),因此它与PHP mcrypt使用的填充不兼容,如果明文大小可以除以密码的块大小,则可能会失败。您是说在PHP中,即使您指定不填充,额外的字节也会自动删除吗?因为只有在加密可被blocksize整除的数据时才需要填充,否则需要以某种方式去除多余的字节。我在PHP中不使用填充,它可以在不删除任何多余字节的情况下工作。。另外,这两种加密结果在PHP和JAVAWell中是相同的。如果您真的使用了无填充选项,那么它不应该工作。填充需要知道哪些字节是“额外的”,所以很可能您实际上是在不知道的情况下在PHP中使用填充。您的代码似乎也实现了您自己的“填充”。这是不必要的,一个坏主意,可能是你问题的根源。更不用说这是一种过时的方式。请删除decryptedVal
右侧大小的零字节。
public class RijndaelCrypt {
//private String key = "2a4e2471c77344b3bf1de28ab9aa492a444abc1379c3824e3162664a2c2b811d";
private static String iv = "beadfacebadc0fee";
private static String hashedKey = "6a2dad9f75b87f5bdd365c9de0b9c842";
private static Cipher cipher;
public static String decrypt(String text) throws UnsupportedEncodingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, NoSuchProviderException {
SecretKeySpec keyspec = new SecretKeySpec(hashedKey.getBytes("UTF-8"), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes("UTF-8"));
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
byte[] decodedValue = Base64.decode(text.getBytes("UTF-8"));
byte[] decryptedVal = cipher.doFinal(decodedValue);
return new String(decryptedVal);
}
public static String encryptNew(String data) throws Exception {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes("UTF-8");
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(hashedKey.getBytes("UTF-8"), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes("UTF-8"));
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return DatatypeConverter.printBase64Binary(encrypted);
}
public static void main (String [] args) throws Exception
{
Security.addProvider(new BouncyCastleProvider());
String data = "Hello";
System.out.println("New Decrypted: " + RijndaelCrypt.decrypt(RijndaelCrypt.encryptNew(data)));
System.out.println("New Encryption: " + RijndaelCrypt.encryptNew(data));
}
}