Given final block not properly padded
Asked Answered
V

7

154

I am trying to implement password based encryption algorithm, but I get this exception:

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

What might be the problem?

Here is my code:

public class PasswordCrypter {

    private Key key;

    public PasswordCrypter(String password)  {
        try{
            KeyGenerator generator;
            generator = KeyGenerator.getInstance("DES");
            SecureRandom sec = new SecureRandom(password.getBytes());
            generator.init(sec);
            key = generator.generateKey();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public byte[] encrypt(byte[] array) throws CrypterException {
        try{
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.ENCRYPT_MODE, key);

            return cipher.doFinal(array);
        } catch (Exception e) { 
            e.printStackTrace();
        }
        return null;
    }

    public byte[] decrypt(byte[] array) throws CrypterException{
        try{
            Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, key);

            return cipher.doFinal(array);
        } catch(Exception e ){
            e.printStackTrace();
        }
        return null;
    }
}

(The JUnit Test)

public class PasswordCrypterTest {

    private static final byte[] MESSAGE = "Alpacas are awesome!".getBytes();
    private PasswordCrypter[] passwordCrypters;
    private byte[][] encryptedMessages;

    @Before
    public void setUp() {
        passwordCrypters = new PasswordCrypter[] {
            new PasswordCrypter("passwd"),
            new PasswordCrypter("passwd"),
            new PasswordCrypter("otherPasswd")
        };

        encryptedMessages = new byte[passwordCrypters.length][];
        for (int i = 0; i < passwordCrypters.length; i++) {
            encryptedMessages[i] = passwordCrypters[i].encrypt(MESSAGE);
        }
    }

    @Test
    public void testEncrypt() {
        for (byte[] encryptedMessage : encryptedMessages) {
            assertFalse(Arrays.equals(MESSAGE, encryptedMessage));
        }

        assertFalse(Arrays.equals(encryptedMessages[0], encryptedMessages[2]));
        assertFalse(Arrays.equals(encryptedMessages[1], encryptedMessages[2]));
    }

    @Test
    public void testDecrypt() {
        for (int i = 0; i < passwordCrypters.length; i++) {
            assertArrayEquals(MESSAGE, passwordCrypters[i].decrypt(encryptedMessages[i]));
        }

        assertArrayEquals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[1]));
        assertArrayEquals(MESSAGE, passwordCrypters[1].decrypt(encryptedMessages[0]));

        try {
            assertFalse(Arrays.equals(MESSAGE, passwordCrypters[0].decrypt(encryptedMessages[2])));
        } catch (CrypterException e) {
            // Anything goes as long as the above statement is not true.
        }

        try {
            assertFalse(Arrays.equals(MESSAGE, passwordCrypters[2].decrypt(encryptedMessages[1])));
        } catch (CrypterException e) {
            // Anything goes as long as the above statement is not true.
        }
    }
}
Verisimilar answered 8/11, 2011 at 11:45 Comment(0)
G
236

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).

Goral answered 8/11, 2011 at 16:8 Comment(10)
I just want to confirm. I'm new to encryption and this is my scenario, I'm using AES encryption. in my encrypt/decrypt function, I'm using an encryption key. I used a wrong encryption key in decrypt and I got this javax.crypto.BadPaddingException: Given final block not properly padded. Should I treat this as a wrong key?Anthea
Just to be clear, this can also happen when providing the wrong password for a key store file, such as a .p12 file, which is what just happened to me.Caitiff
@WarrenDew "Wrong password for a key store file" is just a special case of "wrong key".Coranto
@Anthea sorry, I saw your comment just now ... yes, a wrong key almost always causes this effect. (Of course, corrupted data is another possibility.)Coranto
@PaŭloEbermann I agree, but I don't think that's necessarily immediately obvious, since it's different than the situation in the original post where the programmer has control over the key and decryption. I did find your answer useful enough to upvote it, though.Caitiff
FYI. This is also a popular error to get when you have converted an Android signing key to PKCS12 format using keytool.Larios
Is there any possibilities of using different random.generateSeed(16) for encryption and decryption. Because we got same error while decryption @PaŭloEbermann.Atalie
@Atalie I have no clue what you are doing, but decryption should not depend on any randomness.Coranto
I've encrypt the pwd using random.generateSeed(16) and stored it property file. While starting the application, we are calling decryption method using different random number. That time we got this padding error. Is there any possibilities for encrypt and decrypt using different random number? @PaŭloEbermannAtalie
Encryption and decryption need to use the same key. If it would work with different (or even arbitrary) keys, the cryptosystem is broken.Coranto
K
25

This can also be a issue when you enter wrong password for your sign key.

Katzenjammer answered 5/1, 2020 at 11:26 Comment(4)
This is really a comment, not an answer. With a bit more rep, you will be able to post comments.Damek
this is not an answerNecklace
SPOILER ALERT: This was the answer. I made a typo in one of the passwords.Romans
was heplful in my case, thanks a lot !Stream
M
2

depending on the cryptography algorithm you are using, you may have to add some padding bytes at the end before encrypting a byte array so that the length of the byte array is multiple of the block size:

Specifically in your case the padding schema you chose is PKCS5 which is described here: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_CJ_SYM__PAD.html

(I assume you have the issue when you try to encrypt)

You can choose your padding schema when you instantiate the Cipher object. Supported values depend on the security provider you are using.

By the way are you sure you want to use a symmetric encryption mechanism to encrypt passwords? Wouldn't be a one way hash better? If you really need to be able to decrypt passwords, DES is quite a weak solution, you may be interested in using something stronger like AES if you need to stay with a symmetric algorithm.

Mande answered 8/11, 2011 at 11:57 Comment(4)
so could you please post the code which tries to encrypt/decrypt ? (and check that the byte array you try to decrypt is not bigger than the block size)Mande
I am very new to Java and also Cryptography so I still don't know better ways to do encryption. I just want to get this one done than probably look for better ways to implement it.Verisimilar
can you update the link because it doesn't work @Mande and I updated my post I included the JUnit test that tests the encryption and decryptionVerisimilar
Corrected (sorry copy paste error). Anyway, indeed your issue happens since you decrypt with a key which is not the same as the one used for encryption as explained by Paulo. This happens since the method annotated with @Before in junit is executed before every test method, thus regenerating the key every time. since the key is initialized randomly it will be different each time.Mande
N
1

I met this issue due to operation system, simple to different platform about JRE implementation.

new SecureRandom(key.getBytes())

will get the same value in Windows, while it's different in Linux. So in Linux need to be changed to

SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(key.getBytes());
kgen.init(128, secureRandom);

"SHA1PRNG" is the algorithm used, you can refer here for more info about algorithms.

Nicodemus answered 10/12, 2018 at 3:14 Comment(0)
R
1

If you get this warning when generating a keystore

Warning:  Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified -keypass value.
Generating 3,072 bit RSA key pair and self-signed certificate (SHA384withRSA) with a validity of 90 days

you may need to remove the property secret in your application properties file.

Just these properties are enough

encrypt:
  keyStore:
    location: <yourFileLocation>
    password: <yourPassword>
    alias: <yourAlias>

It works for me.

Raven answered 17/3, 2023 at 5:33 Comment(1)
Thanks it helped, I was getting this warning, so recreated keystore with both passwords same and it worked :) although in properties used both key-password and key-store-passwordOrgandy
T
0

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

Such issues can arise if a bad key is used during decryption.

For myself this happens when I used wrong key for decrypting. It is always case sensitive.So make sure you have used the same key when you used when encrypting.... :)

Taddeo answered 29/8, 2021 at 7:33 Comment(0)
W
0

If you sure all configurations are right, so that may you get this exception due to sending a null value as a ciphered to decript or a plane text to encript.

Weese answered 7/6, 2022 at 12:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.