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

时间:2017-05-23 12:37:31

标签: java encryption aes

我正在尝试使用JAVA中的AES / CBC / NoPadding进行加密和解密。我使用(mcrypt)在JAVA和PHP中进行加密,并使用相同的密钥和iv获得相同的结果。但是,当我尝试在JAVA中解密时,我正确地得到了这个词,但总是带有额外的字符。我读了其他问题,发现我需要添加填充。所以我添加了Padding5但得到了相同的结果。无论如何,我需要它没有填充,因为这是它在PHP中的工作方式。任何帮助表示赞赏。我的代码如下,结果在此处:result is in image[![][1]] 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));
         }

   }

1 个答案:

答案 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使用的填充定义不兼容如果明文的大小可以分割,则可能会失败按密码的块大小。