AES CBC无填充在解密JAVa中提供额外字符

AES CBC无填充在解密JAVa中提供额外字符,java,encryption,aes,Java,Encryption,Aes,我试图在JAVA中使用AES/CBC/NOP加密和解密。我使用(mcrypt)在JAVA和PHP中进行了加密,得到了相同的结果,使用了相同的密钥和iv。然而,当我尝试用JAVA解密时,我得到了正确的单词,但总是带有额外的字符。我阅读了其他问题,发现我需要添加填充。所以我添加了Padding5,但得到了相同的结果。不管怎么说,我需要它而不需要填充,因为这就是它在PHP中的工作方式。感谢您的帮助。我的代码如下,结果如下:] PHP mcrypt包装器(或底层mcrypt库)填充零字节,直到块长度(如

我试图在JAVA中使用AES/CBC/NOP加密和解密。我使用(mcrypt)在JAVA和PHP中进行了加密,得到了相同的结果,使用了相同的密钥和iv。然而,当我尝试用JAVA解密时,我得到了正确的单词,但总是带有额外的字符。我阅读了其他问题,发现我需要添加填充。所以我添加了Padding5,但得到了相同的结果。不管怎么说,我需要它而不需要填充,因为这就是它在PHP中的工作方式。感谢您的帮助。我的代码如下,结果如下:]

PHP mcrypt包装器(或底层mcrypt库)填充零字节,直到块长度(如果16是密码的块大小,则填充零到15个字节)。在这之后,块被加密

在Java中解密时,需要使用
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));
         }

   }