gpt4 book ai didi

java - AES 文件解密 “given final block not properly padded”

转载 作者:行者123 更新时间:2023-11-29 10:11:44 25 4
gpt4 key购买 nike

我想使用 AES 加密然后解密文件。我读过很多关于错误 “给定的最终 block 未正确填充” 的主题。但我找不到适合我的解决方案。

抱歉指定我的代码的语言,我不知道编写语言 java

这是我的代码:

变量

// IV, secret, salt in the same time
private byte[] salt = { 'h', 'u', 'n', 'g', 'd', 'h', '9', '4' };
public byte[] iv;
public SecretKey secret;

创建 key

public void createSecretKey(String password){
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(spec);
secret = new SecretKeySpec(tmp.getEncoded(), "AES");
}

方法加密

public void encrypt(String inputFile){
FileInputStream fis = new FileInputStream(inputFile);
// Save file: inputFile.enc
FileOutputStream fos = new FileOutputStream(inputFile + ".enc");

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

AlgorithmParameters params = cipher.getParameters();
// Gen Initialization Vector
iv = (byte[]) ((IvParameterSpec) params
.getParameterSpec(IvParameterSpec.class)).getIV();
// read from file (plaint text) -----> save with .enc
int readByte;
byte[] buffer = new byte[1024];
while ((readByte = fis.read(buffer)) != -1) {
fos.write(cipher.doFinal(buffer), 0, readByte);
}
fis.close();
fos.flush();
fos.close();
}

方法解密

public void decrypt(String inputFile){
FileInputStream fis = new FileInputStream(inputFile);
// Save file: filename.dec
FileOutputStream fos = new FileOutputStream(inputFile.substring(0,
inputFile.length() - 4) + ".dec");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
// Read from file encrypted ---> .dec
int readByte;
byte[] buffer = new byte[1024];
while ((readByte = fis.read(buffer)) != -1) {
fos.write(cipher.doFinal(buffer), 0, readByte);
}
fos.flush();
fos.close();
fis.close();
}

更新

解决方案:编辑buffer的大小是16的倍数。使用CipherInput/Output来读/写文件。

Tks Artjom B.

最佳答案

AES 是一种 block 密码,因此仅适用于 16 字节的 block 。 CBC 等操作模式使您能够将多个 block 链接在一起。诸如 PKCS#5 填充之类的填充使您能够通过将明文填充到 block 大小的下一个倍数来加密任意长度的明文。

问题是您要分别加密每 1024 个字节。由于 1024 划分了 block 大小,因此填充在加密之前添加了一个完整 block 。因此,密文 block 的长度为 1040 字节。然后在解密过程中,您只读取 1024 缺少填充。 Java 尝试解密它,然后尝试删除填充。如果填充格式错误(因为它不存在),则抛出异常。

轻松修复

只需将用于解密的缓冲区增加到 1040 字节即可。

正确修复

不要将它加密成单独的 block ,而是使用 Cipher#update(byte[], int, int)代替 Cipher.doFinal 为您读取的每个缓冲区更新密文或使用 CipherInputStream .


其他安全注意事项:

您缺少随机 IV。如果没有它,攻击者可能仅通过观察密文就可以看到您使用相同的 key 加密了相同的明文。

您缺少密文身份验证。没有它,您将无法可靠地检测到密文中的(恶意)更改,并且可能会使您的系统受到攻击,例如填充 oracle 攻击。要么使用像 GCM 这样的身份验证模式,要么通过 HMAC 运行您创建的密文以创建身份验证标记并将其写入末尾。然后您可以在解密期间/之前验证标签。

关于java - AES 文件解密 “given final block not properly padded”,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31474283/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com