Given Final Block Not Properly Padded

Given final block not properly padded

If you try to decrypt PKCS5-padded data with the wrong key, and then unpad it (which is done by the Cipher class automatically), you most likely will get the BadPaddingException (with probably of slightly less than 255/256, around 99.61%), because the padding has a special structure which is validated during unpad and very few keys would produce a valid padding.

So, if you get this exception, catch it and treat it as "wrong key".

This also can happen when you provide a wrong password, which then is used to get the key from a keystore, or which is converted into a key using a key generation function.

Of course, bad padding can also happen if your data is corrupted in transport.

That said, there are some security remarks about your scheme:

  • For password-based encryption, you should use a SecretKeyFactory and PBEKeySpec instead of using a SecureRandom with KeyGenerator. The reason is that the SecureRandom could be a different algorithm on each Java implementation, giving you a different key. The SecretKeyFactory does the key derivation in a defined manner (and a manner which is deemed secure, if you select the right algorithm).

  • Don't use ECB-mode. It encrypts each block independently, which means that identical plain text blocks also give always identical ciphertext blocks.

    Preferably use a secure mode of operation, like CBC (Cipher block chaining) or CTR (Counter). Alternatively, use a mode which also includes authentication, like GCM (Galois-Counter mode) or CCM (Counter with CBC-MAC), see next point.

  • You normally don't want only confidentiality, but also authentication, which makes sure the message is not tampered with. (This also prevents chosen-ciphertext attacks on your cipher, i.e. helps for confidentiality.) So, add a MAC (message authentication code) to your message, or use a cipher mode which includes authentication (see previous point).

  • DES has an effective key size of only 56 bits. This key space is quite small, it can be brute-forced in some hours by a dedicated attacker. If you generate your key by a password, this will get even faster.
    Also, DES has a block size of only 64 bits, which adds some more weaknesses in chaining modes.
    Use a modern algorithm like AES instead, which has a block size of 128 bits, and a key size of 128 bits (for the most common variant, variants for 196 and 256 also exist).

Given final block not properly padded exception

There are many things that can cause a "Bad Padding" exception. Basically anything that causes the end of the last block not to match the expected padding will throw the error. Possible causes include: incorrect padding setting, incorrect key, corrupted cyphertext and others.

To try and diagnose the problem, set the decryption side to NoPadding. This will accept anything, and allow you to examine the output:

  • complete garbage: you probably have an error in the key or the wrong mode setting.

  • first block garbage: you may have a key error or an IV error.

  • last block garbage: likely a corrupt end to the cyphertext file.

  • a correct decryption with some strange bytes at the end: the strange bytes are the padding.

If it really is just the padding, then set the decryption function to expect that sort of padding. Otherwise check that the key/IV/cyphertext are byte-for-byte the same for both encryption and decryption.

It is vital that you set a padding mode after diagnosis. NoPadding is insecure.

error decrjavax.crypto.BadPaddingException: Given final block not properly padded. Such issues can arise if a bad key is used during decryption

Your error is the way to use your streams when encrypting:

For a CipherOutputStream it is essential to be closed at the end because only when it is closed the final padding can be written.

In your code however the cipherOutputStream instance is never closed. hence the padding is never written to the encrypted file.

Of course when decrypting the file there is no padding where a padding should be and you are getting the BadPaddingException.

Therefore you should change the encyrption to this:

public void encryptFile(File src, File dest) {
try (InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest)) {

try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, ecipher)) {

// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);

System.out.println("key 0x" + new BigInteger(1, secretKey.getEncoded()).toString(16));
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;

// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) >= 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
}

} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {

System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}

public void decryptFile(File srcFile, File destFile) {
try (InputStream is = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile)) {
try (CipherInputStream cis = new CipherInputStream(is, dcipher)) {
// Extract IV
byte[] iv = is.readNBytes(IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);

// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;

while ((bytesRead = cis.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {

System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}

java - javax.crypto.BadPaddingException: Given final block not properly padded

You should use the cipher.update(...) methods when you stream through the file, and only use the cipher.doFinal(...) as the last call. The doFinal flushes the buffers + do padding etc, that you don't want to do more than one time.

If you do a doFinal(...) in your decrypt prematurely, it will (very likely) fail as a correct padding is missing in the data.

Edit:

Don't use ECB mode it's insecure. Take a look here and scroll down to the penguin.

Don't generate your keys by a simple Sha-1 - use a proper key deriviation function like PBKDF2WithHmacSHA256.

BadPaddingException: Given final block not properly padded

You're trying to decrypt ciphertext with a random number generator created using a specific seed. However, you don't specify the algorithm, and the algorithm may change internally as well. Android is even known to generate a fully random value instead for some versions.

You need to use a SecretKeyFactory not a KeyGenerator. And you will of course need the 8-byte key data. The only way to retrieve this in your case is to find the SecureRandom algorithm/implementation before and re-calculate the key.

Now any ciphertext will decrypt with any key. DES ECB only provides (some sort of) confidentiality, not integrity. The problem is that it will decrypt into garbage. Now if you try to remove the padding from garbage you will likely get a padding error.

If you're "lucky" - once in about 256 times - you will get a result. This happens when the decrypted block ends with 01 or 0202, that's valid padding. The result will - of course - be garbage as well, but it will not end with a BadPaddingException. In your case the SecureRandom instance is likely to return the same incorrect value over and over though, so this may never happen.

In the future, please use PBKDF2 and feed it the encoded password. Clearly note the character encoding used, Java SE uses the lowest 8 bits of the char array. Never ever use String.getBytes() as the default encoding may differ between systems.

javax.crypto.BadPaddingException: Given final block not properly padded...tried using getbytes(UTF)

When you call encrypt() you replace the password by its hash, and then use the hash as a key.

Then you call decrypt(), and rehash the hash, and use the hashed hash as the key. So you're not using the same key for encryption and decryption.

Generate the key once in main(), and pass it as parameter to encrypt() and decrypt(). Make keyValue final. Or even better, make it a local variable of main.

javax.crypto.BadPaddingException: Given final block not properly padded - AES/CBC/PKCS5PADDING

You prepend your IV to the ciphertext on encryption, but on decryption you copy the last 16 bytes as your IV.

Whatever you do on encryption you must undo on decryption.



Related Topics



Leave a reply



Submit