我正在尝试使用JAVA中的AES / CBC / NoPadding进行加密和解密。我使用(mcrypt)在JAVA和PHP中进行加密,并使用相同的密钥和iv获得相同的结果。但是,当我尝试在JAVA中解密时,我正确地得到了这个词,但总是带有额外的字符。我读了其他问题,发现我需要添加填充。所以我添加了Padding5但得到了相同的结果。无论如何,我需要它没有填充,因为这是它在PHP中的工作方式。任何帮助表示赞赏。我的代码如下,结果在此处:] 2
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));
}
}
答案 0 :(得分:1)
PHP mcrypt包装器(或底层mcrypt库)填充零字节直到块长度(0到15个填充字节,如果16是密码的块大小)。之后,这些块由密码加密。
在Java中解密时,您需要使用NoPadding
在解密后手动删除明文右侧的任何零字节。当对解密的明文进行十六进制编码时,当然可以看到零值填充字节。但是,在输出字符串时,零字节要么被省略,要么转换为替换字符(取决于字符集和终端)。
请注意,PHP零填充有一个很大的缺点:如果明文以一个或多个零值字节结尾,则可以通过任何非填充例程从解密的明文中删除它。这就是首选PKCS#7填充(填充1到16个字节)的原因。
另请注意,PHP实际上需要rtrim("\0")
来删除零字节本身; mcrypt只是将它们留在那里,但它们通常不会被打印出来。
请注意,Bouncy Castle加密库也有ZeroPadding
作为选项。但是,这是1到16个字节的零填充(即它总是填充/取消),因此与PHP mcrypt使用的填充定义不兼容如果明文的大小可以分割,则可能会失败按密码的块大小。