135 votes

Étant donné le dernier bloc pas correctement rembourré

J'essaie d'implémenter un algorithme de chiffrement basé sur mot de passe, mais j'obtiens cette exception:

javax.crypto.BadPaddingException: Le dernier bloc n'est pas correctement rempli

Quel pourrait être le problème? (Je suis nouveau sur Java.)

Voici mon 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 (IllegalBlockSizeException e) {

            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {

            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {

            e.printStackTrace();
        } catch (NoSuchPaddingException 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(InvalidKeyException e ){
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {

            e.printStackTrace();
        } catch (BadPaddingException e) {

            e.printStackTrace();
        }  catch (NoSuchAlgorithmException e) {

            e.printStackTrace();
        } catch (NoSuchPaddingException e) {

            e.printStackTrace();
        } 


        return null;
    }
}
 

(Le test JUnit)

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

219voto

Paŭlo Ebermann Points 35526

Si vous essayez de déchiffrer PKCS5-collier de données avec la mauvaise touche, puis unpad (ce qui est fait par le chiffre qui classe automatiquement), vous allez probablement obtenir le BadPaddingException (avec probablement d'un peu moins de 255/256, autour de 99.61%).

Donc, si vous obtenez cette exception, l'attraper et de le traiter comme "mauvaise clé".

Cela dit, il y a un peu de sécurité remarques au sujet de votre régime:

  • Pour le chiffrement par mot de passe, vous devez utiliser un SecretKeyFactory et PBEKeySpec au lieu d'utiliser un SecureRandom avec KeyGenerator. La raison en est que la SecureRandom pourrait être un algorithme différent sur chaque Java mise en œuvre, vous donnant une touche différente. Le SecretKeyFactory la dérivation de clé dans une manière définie (et d'une manière qui est considéré comme sûr, si vous sélectionnez l'algorithme de droite).

  • N'utilisez pas la BCE de mode. Il crypte chaque bloc indépendamment, ce qui signifie que les mêmes plaine des blocs de texte aussi donner toujours les mêmes blocs de texte chiffré.

    De préférence, utiliser un mode de fonctionnement, comme CBC (Cipher block chaining) ou CTR (Compteur). Vous pouvez également utiliser un mode qui comprend également l'authentification, comme GCM (Galois-mode Compteur) ou CCM (Compteur avec CBC-MAC), voir le point suivant.

  • Normalement, vous ne voulez pas seulement la confidentialité, mais aussi d'authentification, qui permet de s'assurer que le message n'est pas altéré. (Cela empêche également choisi-texte chiffré attaques sur votre chiffre, c'est à dire aide de la confidentialité.) Donc, ajouter un MAC (message authentification code) de votre message, ou d'utiliser un mode de chiffrement qui inclut l'authentification (voir point précédent).

  • DES est efficace la taille de la clé de 56 bits. Cette touche espace est assez petit, il peut être brute forcé dans quelques heures, par un attaquant. Si vous générez votre clé par mot de passe, ce sera encore plus rapide. Aussi, DES a une taille de bloc de seulement 64 bits, ce qui ajoute encore des faiblesses dans le chaînage de modes. L'utilisation moderne d'un algorithme de type AES au lieu de cela, qui a une taille de bloc de 128 bits, et une taille de clé de 128 bits (pour le modèle standard).

2voto

fpacifici Points 276

selon l'algorithme de chiffrement que vous utilisez, vous pouvez avoir à ajouter des octets de remplissage à la fin avant de le chiffrer un tableau d'octets, de sorte que la longueur du tableau d'octets est multiple de la taille de bloc:

Spécifiquement dans votre cas, le rembourrage de schéma que vous avez choisi est PKCS5 qui est décrit ici: http://www.rsa.com/products/bsafe/documentation/cryptoj35html/doc/dev_guide/group_CJ_SYM__PAD.html

(Je suppose que vous avez le problème lorsque vous essayez de chiffrer)

Vous pouvez choisir votre rembourrage schéma lorsque vous instanciez le chiffre d'objet. Les valeurs prises en charge dépendent du fournisseur de services de sécurité que vous utilisez.

Par la façon êtes-vous sûr que vous voulez utiliser un mécanisme de chiffrement symétrique pour chiffrer les mots de passe? Ne serait pas une table de hachage à sens mieux? Si vous avez vraiment besoin pour être en mesure de déchiffrer les mots de passe, DES est tout à fait une solution faible, vous pourriez être intéressés par l'utilisation de quelque chose de plus fort comme AES si vous avez besoin de rester avec un algorithme symétrique.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X