【问题标题】:Bad Padding Exception using same AES algorithm for file?对文件使用相同的 AES 算法的错误填充异常?
【发布时间】:2016-06-07 18:33:30
【问题描述】:

我正在编写一个简单的自定义加密器/解密器。
基本上,我只取一个大文件的前 1024 个字节并对其进行加密。
我使用了 RandomAccessFile,这样我就可以快速加密和解密前 1024 字节。

现在,我面临的问题是,即使我使用相同的算法进行加密和解密。
加密工作正常,但解密抛出 javax.crypto.BadPaddingException:Given final block not proper padded

无论我搜索多少,我都无法找出问题所在。对此的一些研究告诉我,由于 UTF 和 base64 等不同的格式,填充不正确。但是我不确定如果我读取如此大文件的前 1024 个字节并且加密不会引发异常,填充会如何不正确。我也没有转换成字符串。

我提供了简单的注释,代码如下

public class Encryptor {

private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES";

public void encrypt(String key, File inputFile, File outputFile) throws CryptoException {
    doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
}

public void decrypt(String key, File inputFile, File outputFile) throws CryptoException {
    doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
}    
private void doCrypto(int cipherMode, String key, File inputFile, File outputFile) throws CryptoException {
    try {

        Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
        Cipher cipher = Cipher.getInstance(TRANSFORMATION);
        cipher.init(cipherMode, secretKey);

        byte[] inputBytes = new byte[16];
        byte[] outputBytes = new byte[16];

        //Open the file in read write mode
        RandomAccessFile fileStore = new RandomAccessFile(inputFile, "rw"); 
        fileStore.seek(0); 

        //encrypt first 1024bytes
        int bytesRead = 0;
        for(int ctr=0;bytesRead!= -1 && ctr<64 ;ctr++){
            //get file pointer position
            long prevPosition = fileStore.getFilePointer();

            //read 16 bytes to array
            bytesRead = fileStore.read(inputBytes); 

            //if successful, go move back pointer and overwrite these 16 bytes with encrypted bytes
            if(bytesRead != 1){
                outputBytes = cipher.doFinal(inputBytes);
                fileStore.seek(prevPosition);
                fileStore.write(outputBytes);
            }   
        }

        fileStore.close();

    } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException | BadPaddingException
            | IllegalBlockSizeException | IOException ex) {
        throw new CryptoException(ex);
    }
}

【问题讨论】:

    标签: java algorithm encryption cryptography


    【解决方案1】:

    首先,"AES" 算法字符串由 SUN 提供程序在内部转换为 "AES/ECB/PKCS5Padding"。这意味着您使用的是不安全的 ECB 模式加密,而不是更安全的 CBC 模式。

    获得BadPaddingException 的原因很简单。当您使用 PKCS5Padding(或更准确地说是 PKCS#7 填充)时,在加密期间每 16 个字节最多填充 32 个字节。但是,您只存储未填充的 16 个字节。如果你尝试解密 unpadding 机制尝试 unpad 原始未填充的明文,这将失败。

    其次,read 方法实际上可能不会读取 16 个字节。它只读取最多 16 个字节。您需要创建一个单独的方法来始终精确读取 16 个字节。

    多次致电doFinal 不是一个好主意。您最好一口气读入 1024 个字节,然后调用 doFinal 或 - 更好的是 - update 一次。在这种情况下,您应该使用例如"AES/CBC/NoPadding" 作为算法字符串。


    注意事项:

    • 如果没有随机 IV,您仍然可以区分以相同字节开头的文件(或以相同字节开头的及时重新加密的文件);
    • 您可能需要某种协议来处理小于 1024 字节的文件;
    • 使用“try-with-resources”可能是一个非常好的主意;
    • 使用文件的内存映射实现更简洁的设计和(可能)更快的操作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-01
      • 2017-10-17
      • 1970-01-01
      • 2017-12-28
      • 2011-07-02
      • 2020-10-03
      • 2013-11-14
      • 1970-01-01
      相关资源
      最近更新 更多