使用AES解密文件时,密码doFinal pad块损坏

Tim*_*Tim 0 java encryption bouncycastle aes

我正在创建一个程序,允许用户上传和下载加密文件,如果他们具有正确的权限,则解密它们.加密和上传很好,下载也是如此,但是当我尝试解密时,我得到"pad block corrupted"错误.

我想要做的是获取加密文件,然后制作一个未加密的副本

我缩短了我的意思所以请不要评论它看起来不完整.

注册机:

public static SecretKey genGroupSecretKey() {
    try {
        KeyGenerator keyGen = KeyGenerator.getInstance("AES", "BC");
        keyGen.init(128);
        return keyGen.generateKey();
    } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
        System.err.println("Error: " + e.getMessage());
        e.printStackTrace(System.err);
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

加密:

try (FileInputStream fis = new FileInputStream(sourceFile)) {
    response = Utils.decryptEnv((byte[]) tempResponse.getObjContents().get(0), fsSecretKey, ivSpec);

    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
    cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);

    do {
        byte[] buf = new byte[4096];

        int n = fis.read(buf); // can throw an IOException
        else if (n < 0) {
            System.out.println("Read error");
            fis.close();
            return false;
        }

        byte[] cipherBuf = cipher.doFinal(buf);

        // send through socket blah blah blah

    } while (fis.available() > 0);
Run Code Online (Sandbox Code Playgroud)

解密:

   ...     

   Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
   cipher.init(Cipher.DECRYPT_MODE, secKey, ivSpec);

    File file = new File("D_" + filename); // D_ for decrypted
    FileOutputStream fos = null;
    if (!file.exists()) {
        file.createNewFile();
        fos = new FileOutputStream(file);
    }

    try (FileInputStream fis = new FileInputStream(filename)) {
        do {
            byte[] buf = new byte[4096];
            int n = fis.read(buf);
            if (n < 0) {
                System.out.println("Read error");
                fis.close();
                return false;
            }

            byte[] cipherBuf = cipher.doFinal(buf);  // ERROR HERE
            System.out.println("IS THIS WORKING WTF: " + new String(cipherBuf));
            fos.write(cipherBuf, 0, n);

        } while (fis.available() > 0);
        fis.close();
        fos.close();
        return true;
Run Code Online (Sandbox Code Playgroud)

Ole*_*hin 5

你应该Cipher.doFinal()只为最后一块数据.您应该修改加密和解密代码以Cipher.update()用于所有中间数据,并Cipher.doFinal()在最后使用单个调用.允许Cipher.update()用于所有中间数据块,并在最后调用Cipher.doFinal()带有空数组.

此外,您忽略了fis.read(buf)将从流中读取的数据传递给密码时的返回值.

此外,您正在使用InputStream.available()条件来结束循环.即使循环中的代码是正确的,由于循环条件的虚假触发,您也会得到不可预测的结果.

使用以下模式处理密码:

Cipher cipher = ...
InputStream in = ...
OutputStream out = ...

byte[] inputBuffer = new byte[ BUFFER_SIZE ];
int r = in.read(inputBuffer);
while ( r >= 0 ) {
    byte[] outputUpdate = cipher.update( inputBuffer, 0, r );
    out.write( outputUpdate );
    r = in.read(inputBuffer);
}
byte[] outputFinalUpdate = cipher.doFinal();
out.write( outputFinalUpdate );
Run Code Online (Sandbox Code Playgroud)

检查其他变体Cipher.update()- 可以使用两个预先分配的缓冲区并最小化其他分配.

还要检查是否可以重用javax.crypto.CipherInputStreamjavax.crypto.CipherOutputStream分类,这样就不必直接使用密码.