AES File decrypting “given final block not properly padded”

做~自己de王妃 提交于 2019-12-05 07:32:44

问题


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.


回答1:


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.




回答2:


You are under the false assumption that the length of the encrypted data equals the length of the plain data, but the encrypted AES data is always a multiple of the AES block size (16 bytes) and can have an additional full padding block.

The most efficient way of dealing with stream encryption would be to use JCE's CipherOutputStream and CipherInputStream (http://docs.oracle.com/javase/7/docs/api/javax/crypto/CipherInputStream.html). These classes do all the work for you.

Also, make sure you always save the newly generated IV in your encryption method to be able to use it for the decryption.



来源:https://stackoverflow.com/questions/31474283/aes-file-decrypting-given-final-block-not-properly-padded

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!