Java使用aes256/CBC/PKCS7Padding加密文件
我正在尝试使用aes256-CBC-PKCS7Padding对文件进行加密。我用的是bouncy castle图书馆,但有个例外Java使用aes256/CBC/PKCS7Padding加密文件,java,encryption,aes,bouncycastle,Java,Encryption,Aes,Bouncycastle,我正在尝试使用aes256-CBC-PKCS7Padding对文件进行加密。我用的是bouncy castle图书馆,但有个例外 java.lang.IllegalArgumentException: invalid parameter passed to AES init - org.bouncycastle.crypto.params.ParametersWithIV at org.bouncycastle.crypto.engines.AESEngine.init(Unknown Sour
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)
下面是源代码:
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;
}
}
任何关于如何修复它和解释我做错了什么的建议都会非常有用。您缺少的是模式指示。如果没有,则假定ECB模式,ECB模式不接受IV。因此
PaddedBufferedBlockCipher
执行缓冲,但对于ECB模式。因此,init模式只是将参数传递给AESEngine
,而AESEngine
拒绝IV,因为它只接受按键
在您的代码中,以下是该问题的直接修复方法:
private final CBCBlockCipher AESCipherCBC = new CBCBlockCipher(AESCipher);
private final PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(AESCipherCBC, new PKCS7Padding());
我将包括下面的重写,以向您展示一种不同的书写方式。请注意,我没有提到正确处理IV或异常。显然,对于大型文件,您可能希望流式传输内容和/或映射文件
// 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;
}
}
尝试在自己的行上初始化ParametersWithIV对象,例如:“var params=new ParametersWithIV(key,IV);”并查看是否获得有效的ParametersWithIV对象如果可能(关于导入/导出规则)使用Oracle Java的标准AES实现,它能够使用许多x64 CPU提供的AES-NI。非常感谢您指出所有错误,以及关于更好名称的提示