java中的Aes解密-填充问题

Posted

技术标签:

【中文标题】java中的Aes解密-填充问题【英文标题】:Aes decryption in java - problems with padding 【发布时间】:2016-09-03 02:15:41 【问题描述】:

我想用java实现一个简单的加密/解密工具。 因此我找到了一个小教程:http://www.codejava.net/coding/file-encryption-and-decryption-simple-example

我更改了一些代码行,以保证大文件的加密。 现在我遇到了问题,解密不起作用。

我收到以下错误消息/异常:

Error encrypting/decrypting file
    at Algorithmus.Encryptor.doCrypto(Encryptor.java:71)
    at Algorithmus.Encryptor.decrypt(Encryptor.java:39)
    at GUI.MainWindow$encryptThread.run(MainWindow.java:838)
Caused by: javax.crypto.BadPaddingException: Given final block not properly padded
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:966)
    at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:824)
    at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:436)
    at javax.crypto.Cipher.doFinal(Cipher.java:2165)
    at Algorithmus.Encryptor.doCrypto(Encryptor.java:60)
    ... 2 more

我尝试将 Transoformation 参数更改为 AES/CBC/PKCS5Padding,但这没有任何效果。有谁知道,如何优化给定的代码?

        private static final String ALGORITHM = "AES";

        private static final String TRANSFORMATION = "AES";

        public static  void encrypt(String key, File inputFile, File outputFile)
                throws ExtendedException 
            doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
        

        public static  void decrypt(String key, File inputFile, File outputFile)
                throws ExtendedException 
            doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
        

        private static void doCrypto(int cipherMode, String key, File inputFile,
                File outputFile) throws ExtendedException 
            try 
                Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
                Cipher cipher = Cipher.getInstance(TRANSFORMATION);
                cipher.init(cipherMode, secretKey);

                FileInputStream inputStream = new FileInputStream(inputFile);


                CipherOutputStream out = new CipherOutputStream(new FileOutputStream(outputFile), cipher);
                byte[] buffer = new byte[8192];
                byte[] outputBytes = null;
                FileOutputStream outputStream = new FileOutputStream(outputFile);
                int count;
                while ((count = inputStream.read(buffer)) > 0)
                
                    out.write(buffer, 0, count);
                    outputBytes = cipher.doFinal(buffer);

                


                inputStream.close();
                outputStream.close();

             catch (NoSuchPaddingException | NoSuchAlgorithmException
                    | InvalidKeyException | BadPaddingException
                    | IllegalBlockSizeException | IOException ex) 
                throw new ExtendedException("Error encrypting/decrypting file", ex);
            
        

【问题讨论】:

【参考方案1】:

只需使用CipherOutputStream。不要调用cipher.doFinal(buffer),也不要忘记关闭输出流。

FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream fileout = new FileOutputStream(outputFile);
CipherOutputStream out = new CipherOutputStream(fileout , cipher);

try 
    byte[] buffer = new byte[8192];
    int count;

    while ((count = inputStream.read(buffer)) > 0) 
        out.write(buffer, 0, count);
    
 finally 
    out.close();
    inputStream.close();

CipherOutputStream 为您管理密码。当流将被关闭并刷新内部缓冲区时,它会调用doFinal

【讨论】:

非常感谢。它完美地工作!但是,如果我输入了错误的密码,则不会抛出异常。将创建解密文件,但人类不可读 @jollepe AES/CBC 加密本身不提供正确密码的验证,如果您需要添加加密数据的 MAC 并将其用于验证或使用 AES/GCM。必须避免向用户返回错误填充错误,否则攻击者可以在填充预言攻击中利用它。

以上是关于java中的Aes解密-填充问题的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Javascript中的AES CBC零填充进行加密并使用Java进行解密

MbedTLS AES 128 在 Java 中加密和解密

nodejs中aes-128-cbc加密和解密

AES GCM 解密绕过 JAVA 中的身份验证

python Crypto AES-256-ECB 与PHP之间完成加解密

从 Java 生成的数据中解密 PHP 中的 AES-128