javax.crypto.BadPaddingException

Estoy trabajando en el algoritmo AES, y tengo esta excepción que no pude resolver.

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

la excepción ocurre en la parte de descifrado. Inicializo la clave en un lugar diferente de donde está el algoritmo de descifrado

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

luego lo paso con el texto de cifrado que leí del archivo al siguiente método

  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 

EDITAR aquí está el método de encriptación.

 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); } 

y aquí está el método 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(); } 

Aquí es donde leo el texto de cifrado del archivo

 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); } 

alguien puede ayudar?

Ok, entonces el problema es que está convirtiendo los bytes cifrados a una cadena hexadecimal (utilizando el método asHex ) pero no está convirtiendo la cadena hexadecimal de nuevo a una matriz de bytes correctamente para el descifrado. No puedes usar getBytes .

Puede usar el siguiente método para convertir una cadena hexadecimal en una matriz de bytes:

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

y luego cambie su método de descifrado para usar:

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

Tuve una excepción de Bad Padding y no he podido encontrar en Internet una solución a mi problema. Como lo encontré después de algunas horas de trabajo duro, lo doy aquí.

Mi problema era que estaba leyendo un archivo en mi disco duro y encriptado a través de un búfer, siempre llamando al método doFinal () en lugar del método update (). Entonces, al descifrarlo, tuve errores de relleno

  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(); 

Y al descifrar, con el mismo método, pero con un cifrado init con 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(); 

Con el código escrito, ya no tengo BadPaddingException.

Puedo precisar que esta excepción solo aparece cuando la longitud del archivo original claro (obtenida a través de file.length ()) es mayor que el buffer. De lo contrario, no necesitamos pasar varias veces en la estructura while, y podemos encriptar de una sola vez con una llamada doFinal (). Eso justifica el carácter aleatorio de la excepción según el tamaño del archivo que intentas encriptar.

¡Espero que hayas leído bien!

Supongo que la expresión message.trim().getBytes() no devuelve los mismos bytes que se generan al cifrar el mensaje. Especialmente, el método trim() podría eliminar los bytes que se agregaron como relleno en el mensaje cifrado.

Verifique que tanto la matriz devuelta del método doFinal() durante el cifrado y la matriz devuelta de message.trim().getBytes() :

  1. obtuve la misma cantidad de bytes (longitud de la matriz)
  2. obtuve los mismos bytes en la matriz
 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)); 

Aquí hay una solución que pude juntar utilizando un almacén de claves jks con encriptación RSA

 import javax.crypto.Cipher; import javax.xml.bind.DatatypeConverter; import java.security.Key; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.KeyStore; import java.security.cert.Certificate; public class Main { public static void main(String[] args) { byte[] txt = "This is a secret message for your own eyes only".getBytes(); byte[] encText; try{ // Load the keystore KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); char[] password = "keystorePassword".toCharArray(); java.io.FileInputStream fis = new java.io.FileInputStream("/path/to/keystore/myKeyStore.jks"); ks.load(fis, password); fis.close(); Key rsakey = ks.getKey("mykeyalias", password); Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); // Encrypt Certificate cert = ks.getCertificate("mykeyalias"); try { cipher.init(Cipher.ENCRYPT_MODE, cert.getPublicKey()); encText = cipher.doFinal(txt); System.out.println(encText.toString()); } catch (Throwable e) { e.printStackTrace(); return; } // Decrypt cipher.init(Cipher.DECRYPT_MODE, rsakey); String decrypted = new String(cipher.doFinal(encText)); System.out.println(decrypted); } catch (Exception e) { System.out.println("error" + e); } }