简体   繁体   English

Java使用aes256 / CBC / PKCS7Padding加密文件

[英]Java Encrypt a file using aes256/ CBC/PKCS7Padding

I'm trying to encrypt a file using aes256- CBC-PKCS7Padding . 我正在尝试使用aes256-CBC-PKCS7Padding加密文件。 I'm using bouncy castle library , but I get exception 我正在使用充气城堡图书馆,但我得到例外

java.lang.IllegalArgumentException: invalid parameter passed to AES init - org.bouncycastle.crypto.params.ParametersWithIV
at org.bouncycastle.crypto.engines.AESEngine.init(Unknown Source)
at org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher.init(Unknown Source)

Here the source code : 这里的源代码:

public class Crypto {

    public static final int AES_Key_Size = 256;
    public static int blockSize = 16;
    private final BlockCipher AESCipher = new AESEngine();
    private PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(AESCipher, new PKCS7Padding());
    private byte[] IV;
    private KeyParameter key;

    public Crypto() throws NoSuchAlgorithmException {
        KeyGenerator kg = KeyGenerator.getInstance("AES");
        kg.init(AES_Key_Size);
        SecretKey sk = kg.generateKey();
        key = new KeyParameter(sk.getEncoded());


    }
    public void CryptoZip(File plikZip, File plikAES) throws IOException, DataLengthException, IllegalStateException, InvalidCipherTextException {

        byte[] input = Files.readAllBytes(plikZip.toPath());
        byte[] cryptOut = encrypt(input);
        FileOutputStream fos = new FileOutputStream(plikAES);
        fos.write(cryptOut);
        fos.close();



    }


    private byte[] encrypt(byte[] input) throws DataLengthException, IllegalStateException, InvalidCipherTextException {



        IV = new byte[blockSize];
        SecureRandom random = new SecureRandom();
        random.nextBytes(IV);

        cipher.init(true, new ParametersWithIV(key, IV)); // problem here


        byte[] output = new byte[cipher.getOutputSize(input.length)];
        int bytesWrittenOut = cipher.processBytes(
            input, 0, input.length, output, 0);

        cipher.doFinal(output, bytesWrittenOut);

        return output;

    }
}

Any suggestion how to fix it and explanation what I'm doing wrong will be really helpful. 任何建议如何解决它并解释我做错了什么将是非常有帮助的。

What you're missing is the indication of the mode. 你缺少的是模式的指示。 If that is missing then ECB mode is assumed, and ECB mode doesn't take an IV. 如果缺少那么则假定ECB模式,并且ECB模式不采用IV。 So PaddedBufferedBlockCipher does do buffering, but for ECB mode. 所以PaddedBufferedBlockCipher确实做了缓冲,但对于ECB模式。 So the init mode simply passes the parameters to AESEngine , and AESEngine rejects the IV as it only accepts keys. 所以init模式只是将参数传递给AESEngineAESEngine拒绝IV,因为它只接受密钥。

In your code, the following would be a direct fix for the problem: 在您的代码中,以下内容将直接解决问题:

private final CBCBlockCipher AESCipherCBC = new CBCBlockCipher(AESCipher);
private final PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(AESCipherCBC, new PKCS7Padding());

I'll include the following rewrite to show you a different way of writing this down. 我将包括以下重写,以向您展示一种不同的写法。 Note that I didn't touch upon handling the IV or the exceptions correctly. 请注意,我没有触及正确处理IV或异常。 Obviously, for large files, you may want to stream the contents and/or to map your files. 显然,对于大型文件,您可能希望流式传输内容和/或映射文件。

// renamed as crypto is a horrible name
public class FileEncryptor {

    // lets use all uppercase constant names
    public static final int AES_KEY_SIZE = 256;

    // only field needed, the rest can be generated on the fly
    private final KeyParameter key;

    public FileEncryptor() throws NoSuchAlgorithmException {
        key = generateKey();
    }

    private static KeyParameter generateKey() {
        // removed KeyGenerator as that's dependent on JCA crypto-API 
        SecureRandom keyRNG = new SecureRandom();
        byte[] keyData = new byte[AES_KEY_SIZE / Byte.SIZE];
        keyRNG.nextBytes(keyData);
        return new KeyParameter(keyData);
    }

    // the code doesn't do anything with zip itself, so no need to include it in the method name
    public void encryptFile(File plaintextFile, File ciphertextFile) throws IOException, DataLengthException, IllegalStateException, InvalidCipherTextException {
        byte[] plaintext = Files.readAllBytes(plaintextFile.toPath());
        byte[] ciphertext = encrypt(plaintext);
        // try and be symmetric, use Files functionality for reading *and writing*
        Files.write(ciphertextFile.toPath(), ciphertext);
    }


    private byte[] encrypt(byte[] plaintext) throws DataLengthException, IllegalStateException, InvalidCipherTextException {
        // create cipher
        final BlockCipher aes = new AESFastEngine();
        CBCBlockCipher aesCBC = new CBCBlockCipher(aes);
        PaddedBufferedBlockCipher aesCBCPadded =
                new PaddedBufferedBlockCipher(aesCBC, new PKCS7Padding());

        // create IV
        byte[] iv = new byte[aes.getBlockSize()];
        SecureRandom random = new SecureRandom();
        random.nextBytes(iv);

        // initialize cipher with IV
        ParametersWithIV paramsWithIV = new ParametersWithIV(key, iv);
        aesCBCPadded.init(true, paramsWithIV); // problem here

        // encrypt
        byte[] ciphertext = new byte[aesCBCPadded.getOutputSize(plaintext.length)];
        int bytesWrittenOut = aesCBCPadded.processBytes(
            plaintext, 0, plaintext.length, ciphertext, 0);
        aesCBCPadded.doFinal(ciphertext, bytesWrittenOut);

        // that's great, but where is your IV now? you need to include it in the returned ciphertext!
        return ciphertext;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM