Je reçois une erreur de déchiffrement en classe Java:
javax.crypto.IllegalBlockSizeException :
Input length must be multiple of 16 when decrypting with padded cipher.
Que puis-je faire pour résoudre ce problème?
METTRE À JOUR:
J'ai oublié de mentionner qu'il fonctionne une fois et lorsque la deuxième fois, j'essaie de l'exécuter à nouveau en jetant l'erreur susmentionnée.
package com.tb.module.service;
import Java.security.Key;
import Java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import Sun.misc.*;
/**
* This class is used for encrypt and decrypt the password field.
*
*/
public class PswdEnc {
private static final String ALGO = "AES";
private static final byte[] keyValue = new byte[] { 'T', 'h', 'e', 'B', 'e', 's', 't','S', 'e', 'c', 'r','e', 't', 'K', 'e', 'y' };
public static String encrypt(String Data) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public static String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGO);
return key;
}
}
L'algorithme que vous utilisez, "AES", est un raccourci pour "AES/ECB/NoPadding". Cela signifie que vous utilisez le algorithme AES avec une taille de clé de 128 bits et taille du bloc , avec le ECBmode de fonctionnement et pas de remplissage .
En d'autres termes: vous ne pouvez crypter des données que par blocs de 128 bits ou 16 octets. C'est pourquoi vous obtenez cette exception IllegalBlockSizeException
.
Si vous souhaitez chiffrer des données dans des tailles qui ne sont pas multiples de 16 octets, vous devrez soit utiliser un type de remplissage, soit un flux de chiffrement. Par exemple, vous pouvez utiliser mode CBC (un mode de fonctionnement qui transforme efficacement un chiffrement par bloc en un chiffrement par flux ) en spécifiant "AES/CBC/NoPadding" comme algorithme, ou Rembourrage PKCS5 en spécifiant "AES/ECB/PKCS5", qui ajoutera automatiquement quelques octets à la fin de vos données dans un format très spécifique pour rendre la taille du texte chiffré multiple de 16 octets, et de telle sorte comprendre qu'il doit ignorer certaines données.
Dans tous les cas, je vous suggère fortement d'arrêter maintenant ce que vous faites et d'aller étudier des informations très introductives sur la cryptographie. Par exemple, vérifiez Crypto I on Coursera . Vous devez très bien comprendre les implications du choix d’un mode ou d’un autre, quels sont leurs points forts et surtout leurs faiblesses. Sans cette connaissance, il est très facile de construire des systèmes très faciles à détruire.
Mise à jour: en fonction de vos commentaires sur la question, ne chiffrez jamais les mots de passe lorsque vous les stockez dans une base de données !!!!! Vous ne devriez jamais, jamais faire cela. Vous devez HACHER les mots de passe, correctement salés, ce qui est complètement différent du cryptage. Vraiment, s'il vous plaît, ne faites pas ce que vous essayez de faire ... En chiffrant les mots de passe, ils peuvent être déchiffrés. Cela signifie que vous, en tant que gestionnaire de base de données et connaissant la clé secrète, pourrez lire tous les mots de passe stockés dans votre base de données. Soit vous le saviez et faites quelque chose de très très mauvais ou vous ne le saviez pas et vous devriez être choqué et l'arrêter.
Quelques commentaires:
import Sun.misc.*;
Ne faites pas ça. C'est non standard et il n'est pas garanti que ce soit la même chose entre les implémentations. Il existe d'autres bibliothèques avec conversion Base64 disponibles.
byte[] encVal = c.doFinal(Data.getBytes());
Vous utilisez le codage de caractères par défaut ici. Spécifiez toujours le codage de caractères que vous utilisez: byte[] encVal = c.doFinal(Data.getBytes("UTF-8"));
Les valeurs par défaut peuvent être différentes selon les endroits.
Comme @thegrinner l'a souligné, vous devez vérifier explicitement la longueur de vos tableaux d'octets. S'il y a une différence, comparez-les octet par octet pour voir où la différence se faufile.
Eh bien c'est à cause de
vous ne pouvez crypter des données que par blocs de 128 bits ou 16 octets. C'est pourquoi vous obtenez cette exception IllegalBlockSizeException… .. et l'un des moyens consiste à chiffrer ces données directement dans la chaîne.
regarde ça. Essayez et vous pourrez résoudre ce problème
public static String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
String decordedValue = new BASE64Decoder().decodeBuffer(encryptedData).toString().trim();
System.out.println("This is Data to be Decrypted" + decordedValue);
return decordedValue;
}
espérons que cela aidera.