pkcs5padding library getinstance example ejemplo crypto cipher cbc java exception cryptography encryption

library - java crypto



javax.crypto.BadPaddingException (5)

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

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 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?


Aquí hay una solución que pude juntar utilizando un almacén de claves jks con cifrado 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); } }


Bien, entonces el problema es que estás convirtiendo los bytes cifrados en una cadena hexadecimal (usando el método asHex ) pero no estás convirtiendo la cadena hexadecimal de nuevo en una matriz de bytes para descifrarla. No puedes usar getBytes .

Puede usar el siguiente method 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));


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 como la matriz devuelta de message.trim().getBytes() :

  1. tiene el mismo número de bytes (longitud de matriz)
  2. tiene los mismos bytes en la matriz

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

Mi problema fue que estaba leyendo un archivo en mi disco duro y lo cifré a través de un búfer, siempre llamando al método doFinal () en lugar del método update (). Así que al desencriptarlo, 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 inicio de cifrado 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 ninguna excepción BadPaddingException.

Puedo precisar que esta excepción solo aparece cuando la longitud del archivo claro original (obtenida a través de file.length ()) es más grande que el búfer. De lo contrario, no necesitamos pasar varias veces en la estructura while, y podemos cifrar en una sola pasada con una llamada doFinal (). Eso justifica el carácter aleatorio de la excepción que sigue al tamaño del archivo que intenta cifrar.

Espero que hayas tenido una buena lectura!


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