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

时间:2014-04-03 06:17:45

标签: java encryption aes bouncycastle

我正在创建一个程序,允许用户上传和下载加密文件,如果他们具有正确的权限,则解密它们。加密和上传很好,下载也是如此,但是当我尝试解密时,我收到“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;
}

加密:

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);

解密:

   ...     

   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;

2 个答案:

答案 0 :(得分: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 );

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

同时检查您是否可以重复使用javax.crypto.CipherInputStreamjavax.crypto.CipherOutputStream类,这样您就不必直接使用密码。

答案 1 :(得分:0)

如果目标只是加密和解密文件,以下程序将有所帮助。

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.Security;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import com.fiberlink.security.crypto.CryptoUtils;

public class DecryptDocsController {

    static {
        Security.addProvider(new BouncyCastleProvider());
    }
    public static final String PKCS7_PADDING = "AES/CBC/PKCS7Padding";
    public static final int CHUNK_SIZE = 16;
    public static final int STARTING_LOCATION = 0;
    public static final int STREAM_FINISH_LOCATION = -1;
    public void encryptFile() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, BadPaddingException 
        {
        FileInputStream fis = new FileInputStream(DECRYPTED_FILE_LOCATION_1);
        FileOutputStream fos = new FileOutputStream(ENC_FILE_LOCATION_1);
        Cipher cipher = Cipher.getInstance(PKCS7_PADDING);
        SecretKeySpec skeySpec = new SecretKeySpec(getEcryptionByte(FILE_ENCRYPION_KEY), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
        CipherInputStream inputStream = new CipherInputStream(fis, cipher);
        int count =0;
        byte[] data = new byte[CHUNK_SIZE];
        while((count=(inputStream.read(data, STARTING_LOCATION, CHUNK_SIZE))) != STREAM_FINISH_LOCATION) {
            fos.write(data, STARTING_LOCATION, count);
        }
        fis.close();
        fos.close();
        inputStream.close();
       }

    public void decryptFile() throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IOException, IllegalBlockSizeException, BadPaddingException 
        {
        FileInputStream fis = new FileInputStream(ENC_FILE_LOCATION_2);
        FileOutputStream fos = new FileOutputStream(DECRYPTED_FILE_LOCATION_2);
        Cipher cipher = Cipher.getInstance(PKCS7_PADDING);
        SecretKeySpec skeySpec = new SecretKeySpec(getEcryptionByte(FILE_ENCRYPION_KEY), "AES");
        cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec(new byte[16]));
        CipherInputStream inputStream = new CipherInputStream(fis, cipher);
        int count =0;
        byte[] data = new byte[CHUNK_SIZE];
        while((count=(inputStream.read(data, STARTING_LOCATION, CHUNK_SIZE))) != STREAM_FINISH_LOCATION) {
            fos.write(data, STARTING_LOCATION, count);`enter code here`
        }
        fis.close();
        fos.close();
        inputStream.close();
        }
}