web-dev-qa-db-fra.com

javax.crypto.BadPaddingException

Je travaille sur l'algorithme AES et j'ai cette exception que je n'ai pas pu résoudre.

javax.crypto.BadPaddingException: Given final block not properly padded
at com.Sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.Sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.Sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)

l'exception se produit dans la partie de décryptage. J'initialise la clé dans un endroit différent de celui où l'algorithme de décryptage est

KeyGenerator kgen = KeyGenerator.getInstance("AES");//key generation for AES
kgen.init(128); // 192 and 256 bits may not be available

puis je le passe avec le texte chiffré que je lis du fichier à la méthode suivante

 public String decrypt(String message, SecretKey skey) {

    byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
    // Instantiate the cipher
    Cipher cipher;

    byte[] original = null;
    try {
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.DECRYPT_MODE, skeySpec);
        System.out.println("Original string: "
                + message);
        original = cipher.doFinal(message.trim().getBytes());  //here where I got the exception
        String originalString = new String(original);
       }
 //catches

MODIFIER voici la méthode de cryptage.

public String encrypt(String message, SecretKey skey) {
    byte[] raw = skey.getEncoded();
    SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");

    // Instantiate the cipher

    Cipher cipher;
    byte[] encrypted = null;
    try {
        cipher = Cipher.getInstance("AES");

        cipher.init(Cipher.ENCRYPT_MODE, skeySpec);

        encrypted = cipher.doFinal(message.getBytes());
        System.out.println("raw is " + encrypted);

    } catches
    return asHex(encrypted);
}

et voici la méthode asHex

  public static String asHex(byte buf[]) {
    StringBuffer strbuf = new StringBuffer(buf.length * 2);
    int i;

    for (i = 0; i < buf.length; i++) {
        if (((int) buf[i] & 0xff) < 0x10) {
            strbuf.append("0");
        }

        strbuf.append(Long.toString((int) buf[i] & 0xff, 16));
    }

    return strbuf.toString();
}

Voici où je lis le texte chiffré du fichier

static public String readFile(String filePath) {
    StringBuilder file = new StringBuilder();
    String line = null;
    try {
        FileReader reader = new FileReader(filePath);
        BufferedReader br = new BufferedReader(reader);
        if (br != null) {
            line = br.readLine();
            while (line != null) {
                file.append(line);
                //      System.out.println("line is " + line);
                line = br.readLine();

            }
        }
        br.close();
        reader.close();
    } catch (IOException ex) {
        Logger.getLogger(FileManagement.class.getName()).log(Level.SEVERE, null, ex);
    }
    System.out.println("line is " + file.toString());
    return String.valueOf(file);

}

quelqu'un peut-il aider?

19
palAlaa

Ok, donc le problème est que vous convertissez les octets chiffrés en une chaîne hexadécimale (en utilisant la méthode asHex) mais que vous ne reconvertissez pas correctement la chaîne hexadécimale en un tableau d'octets pour le déchiffrement. Vous ne pouvez pas utiliser getBytes.

Vous pouvez utiliser la méthode suivante pour convertir une chaîne hexadécimale en un tableau d'octets:

public static byte[] fromHexString(String s) {
    int len = s.length();
    byte[] data = new byte[len / 2];
    for (int i = 0; i < len; i += 2) {
        data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                             + Character.digit(s.charAt(i+1), 16));
    }
    return data;
}

puis changez votre méthode de décryptage à utiliser:

original = cipher.doFinal(fromHexString(message));
14
dogbane

J'ai eu une exception de mauvais rembourrage et je n'ai pas pu trouver sur Internet une solution à mon problème. Depuis que je l'ai trouvé après quelques heures de travail acharné, je le donne ici.

Mon problème était que je lisais un fichier sur mon disque dur et que je le chiffrais via un tampon, en appelant toujours la méthode doFinal () au lieu de la méthode update (). Donc, lors du décryptage, j'ai eu des erreurs de remplissage

    input = new FileInputStream(file);
    output = new FileOutputStream(newFile);

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.ENCRYPT_MODE, mySecretKey);

    byte[] buf = new byte[1024];

    count = input.read(buf);
    while (count >= 0) {
        output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method
        count = input.read(buf);
    }
    output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
    output.flush();

Et lors du décryptage, avec la même méthode, mais avec un init de chiffrement avec DECRYPT_MODE

    input = new FileInputStream(file);
    output = new FileOutputStream(newFile);

    Cipher cipher = Cipher.getInstance("DES");
    cipher.init(Cipher.DECRYPT_MODE, mySecretKey);

    byte[] buf = new byte[1024];

    count = input.read(buf);

    while (count >= 0) {
        output.write(cipher.update(buf, 0, count)); // HERE I WAS DOING doFinal() method

        //AND HERE WAS THE BadPaddingExceotion -- the first pass in the while structure

        count = input.read(buf);
    }
    output.write(cipher.doFinal()); // AND I DID NOT HAD THIS LINE BEFORE
    output.flush();

Avec le code écrit, je n'ai plus aucune BadPaddingException.

Je peux préciser que cette exception n'apparaît que lorsque la longueur du fichier clair d'origine (obtenue via file.length ()) est supérieure à la mémoire tampon. Sinon, nous n'avons pas besoin de passer plusieurs fois dans la structure while, et nous pouvons chiffrer en un seul passage avec un appel doFinal (). Cela justifie le caractère aléatoire de l'exception suivant la taille du fichier que vous essayez de crypter.

J'espère que vous avez bien lu!

4
Mav3656

Je suppose que l'expression message.trim().getBytes() ne renvoie pas les mêmes octets qui sont générés lorsque vous avez chiffré le message. En particulier, la méthode trim() pourrait supprimer les octets qui ont été ajoutés comme remplissage dans le message crypté.

Vérifiez que le tableau renvoyé de la méthode doFinal() pendant le chiffrement et le tableau renvoyé de message.trim().getBytes():

  1. a obtenu le même nombre d'octets (longueur du tableau)
  2. a obtenu les mêmes octets dans le tableau
1
Progman
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair rsaKeyPair = kpg.genKeyPair();
byte[] txt = "This is a secret message.".getBytes();
System.out.println("Original clear message: " + new String(txt));

// encrypt
Cipher cipher;
try
{
    cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.ENCRYPT_MODE, rsaKeyPair.getPublic());
    txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
    e.printStackTrace();
    return;
}
System.out.println("Encrypted message: " + new String(txt));

// decrypt
try
{
    cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
    cipher.init(Cipher.DECRYPT_MODE, rsaKeyPair.getPrivate());
    txt = cipher.doFinal(txt);
}
catch (Throwable e)
{
    e.printStackTrace();
    return;
}
System.out.println("Decrypted message: " + new String(txt));
0
Jaya shree