【问题标题】:Cipher doFinal pad block corrupted while decrypting file with AES使用 AES 解密文件时密码 doFinal 垫块损坏
【发布时间】:2014-05-14 19:01:53
【问题描述】:

我正在创建一个程序,该程序允许用户上传和下载加密文件,并在他们拥有正确权限的情况下对其进行解密。加密和上传都很好,下载也很好,但是当我尝试解密时,我得到“pad block损坏”错误。

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

我尽可能地缩短了,所以请不要评论它看起来不完整。

密钥生成:

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;

【问题讨论】:

    标签: java encryption aes bouncycastle


    【解决方案1】:

    你应该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 类,这样您就不必直接使用密码。

    【讨论】:

    • 感谢您的回复!总是很高兴看到不是链接的答案。现在我只是在测试只有 2 行长的文本文件,绝对不足以填满我的缓冲区。有什么想法吗?
    • 缓冲区是否被填满并不重要。切不可忽略InputStream.read(byte[])的返回值,在将数据传递给下一个类时必须使用它。
    • 好的,我会在完成更改后报告。
    • 我一直收到一个错误,提示字节数组:outputUpdate = null,不确定为什么会这样
    • 没关系,这是因为块太小了。我现在正在使用更大的文档进行测试。但是,如果块太小,您将如何处理?
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-17
      相关资源
      最近更新 更多