AES文件解密“给定最终块未正确填充” [英] AES File decrypting “given final block not properly padded”

查看:707
本文介绍了AES文件解密“给定最终块未正确填充”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想加密然后解密文件使用AES。我已经阅读了许多有关错误的主题给定最终块不正确填充。但是我没有找到解决方案。



对不起,指定我的代码的语言,我不知道写的语言java



这是我的代码:



变量

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

createSecretKey

  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);
//保存文件:inputFile.enc
FileOutputStream fos = new FileOutputStream(inputFile +.enc);

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

AlgorithmParameters params = cipher.getParameters();
//初始化向量
iv =(byte [])((IvParameterSpec)params
.getParameterSpec(IvParameterSpec.class))。getIV();
//从文件读取(plaint text)----->保存为.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);
//保存文件:filename.dec
FileOutputStream fos = new FileOutputStream(inputFile.substring(0,
inputFile.length() - 4)+.dec);

密码密码= Cipher.getInstance(AES / CBC / PKCS5Padding);
cipher.init(Cipher.DECRYPT_MODE,secret,new IvParameterSpec(iv));
//从文件读取加密---> .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();
}

更新



解决方案:编辑大小缓冲区是16的倍数。使用CipherInput / Output进行读/写文件。



Tks Artjom B。

解决方案

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



问题是,重新加密每隔1024个字节。由于1024分割块大小,所以填充在加密之前添加一个完整块。因此,密文块长度为1040字节。然后在解密过程中,你只读取1024个填充。 Java尝试解密它,然后尝试删除填充。如果填充格式不正确(因为它不存在),则抛出异常。



轻松修复



只需将您的解密缓冲区增加到1040字节。



正确修复



不要以单独的块加密,但要么使用 密码#update(byte [],int,int) 而不是 Cipher.doFinal 来更新您阅读的每个缓冲区的密文或使用 CipherInputStream






其他安全注意事项:



你错过了一个随机的IV。没有它,攻击者可能会看到,只有通过观察密文,才能在相同的密钥下加密相同的明文。



你缺少密文验证。没有它,您无法可靠地检测(恶意)密文中的更改,并可能会打开您的系统进行攻击,如填充oracle攻击。使用像GCM这样的认证模式,或通过HMAC运行您创建的密文来创建一个认证标签,并写入到最后。然后,您可以在解密期间/之前验证标签。


I want to encrypt and then decrypt file use AES. I have read many topics about error "Given final block not properly padded". But i don't find solution for me.

Sorry about specify the language of my code, i don't know write language java

Here is my code :

Variables

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

createSecretKey

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

method Encrypt

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

method Decrypt

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

Update

Solution: edit size of buffer is multiples of 16. Use CipherInput/ Output for read/ write file.

Tks Artjom B.

解决方案

AES is a block cipher and as such only works on blocks of 16 bytes. A mode of operation such as CBC enables you to chain multiple blocks together. A padding such as PKCS#5 padding enables you to encrypt arbitrary length plaintext by filling the plaintext up to the next multiple of the block size.

The problem is that you're encrypting every 1024 bytes separately. Since 1024 divides the block size, the padding adds a full block before encryption. The ciphertext chunks are therefore 1040 bytes long. Then during decryption, you're only reading 1024 missing the padding. Java tries to decrypt it and then tries to remove the padding. If the padding is malformed (because it's not there), then the exception is thrown.

Easy fix

Simply increase your buffer for decryption to 1040 bytes.

Proper fix

Don't encrypt it in separate chunks, but either use Cipher#update(byte[], int, int) instead of Cipher.doFinal to update the ciphertext for every buffer you read or use a CipherInputStream.


Other security considerations:

You're missing a random IV. Without it, it may be possible for an attacker to see that you encrypted the same plaintext under the same key only by observing the ciphertexts.

You're missing ciphertext authentication. Without it, you can't reliably detect (malicious) changes in the ciphertexts and may open your system to attacks such as padding oracle attack. Either use an authenticated mode like GCM or run your created ciphertext through HMAC to create an authentication tag and write it to the end. Then you can verify the tag during/before decryption.

这篇关于AES文件解密“给定最终块未正确填充”的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆