2010-10-17 114 views
20

Tengo el siguiente programa para encriptar datos.Encriptar y desencriptar con codificación AES y Base64

import java.security.Key; 

import javax.crypto.Cipher; 
import javax.crypto.spec.SecretKeySpec; 

import org.apache.commons.codec.binary.Base64; 

public class Test { 

    private static final String ALGORITHM = "AES"; 
    private static final byte[] keyValue = "ADBSJHJS12547896".getBytes(); 

    public static void main(String args[]) throws Exception { 
     String encriptValue = encrypt("dude5"); 
     decrypt(encriptValue); 

    } 

    /** 
    * @param args 
    * @throws Exception 
    */ 

    public static String encrypt(String valueToEnc) throws Exception { 

     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGORITHM); 
     c.init(Cipher.ENCRYPT_MODE, key); 

     System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length); 
     byte[] encValue = c.doFinal(valueToEnc.getBytes()); 
     System.out.println("encValue length" + encValue.length); 
     byte[] encryptedByteValue = new Base64().encode(encValue); 
     String encryptedValue = encryptedByteValue.toString(); 
     System.out.println("encryptedValue " + encryptedValue); 

     return encryptedValue; 
    } 

    public static String decrypt(String encryptedValue) throws Exception { 
     Key key = generateKey(); 
     Cipher c = Cipher.getInstance(ALGORITHM); 
     c.init(Cipher.DECRYPT_MODE, key); 

     byte[] enctVal = c.doFinal(encryptedValue.getBytes()); 
     System.out.println("enctVal length " + enctVal.length); 

     byte[] decordedValue = new Base64().decode(enctVal); 

     return decordedValue.toString(); 
    } 

    private static Key generateKey() throws Exception { 
     Key key = new SecretKeySpec(keyValue, ALGORITHM); 
     return key; 
    } 

} 

Aquí recibo lo siguiente con excepción?

valueToEnc.getBytes().length 5 
encValue length16 
encryptedValue [[email protected] 
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher 
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 
    at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..) 

¿Puede alguien explicarme la causa? ¿Por qué solo dice al descifrar esa longitud debe ser 16. No se convierte a 16 como al igual que el cifrado con el método doFinal.

Y como la excepción dice "cómo descifrar sin cifrado acolchado?"

+0

Usted tenía razón, excepto 2 puntos. Mencioné en otra respuesta .. –

Respuesta

44

su orden para cifrar:getBytes, cifrar, codificar, toString
su pedido de descifrar:getBytes, descifrar, decodificar, toString

dos problemas:

  1. Como alguien ya ha mencionado, debe invertir el orden de las operaciones para d ecryption. No estás haciendo eso.
  2. encrypt le da 16 bytes, codifica 24 bytes, pero toString da 106 bytes. Algo relacionado con los caracteres inválidos que ocupan espacio adicional.

Nota: Además, no es necesario que llame al generateKey() dos veces.

Solucione el problema n. ° 1 utilizando el orden inverso para el descifrado. orden correcto:getBytes, decodificar, descifrar, toString
problema de la reparación # 2 mediante la sustitución de xxx.toString() con new String(xxx). Haga esto en las funciones de cifrado y descifrado.

Su descifrar debería tener este aspecto:

c.init(Cipher.DECRYPT_MODE, key) 
val decodedValue = new Base64().decode(encryptedValue.getBytes()) 
val decryptedVal = c.doFinal(decodedValue) 
return new String(decryptedVal) 

Esto debe darle la espalda "dude5"

+1

en la parte superior de su respuesta se le da el orden de descifrado como: getBytes, descifrar, decodificar, toString. Luego, más adelante, das el orden correcto como: getBytes, decodificar, descifrar, toString. Creo que el segundo pedido es correcto. – Magnus

+2

Magnus, en la parte superior de mi respuesta, cuando mencioné "Su orden ...", ese es el orden en que OP estaba ejecutando la secuencia. El "Tu" se refiere a OP. Esa no es 'mi' orden. –

+2

También es importante tener en cuenta que siempre se debe usar un juego de caracteres específico al crear una cadena desde byte [] y viceversa: p. 'new String (bytes," UTF-8 ")' y 'string.getBytes (" UTF-8 ")'. Esto garantiza que si el cifrado y el descifrado se ejecutan en diferentes sistemas con diferentes conjuntos de caracteres del sistema, esto no dará como resultado un error. –

0

Fundamentalmente, existe una asimetría entre su función de cifrado y su función de descifrado. Cuando cifra, realiza un cifrado AES y luego una codificación base64; al descifrar, no debe deshacer primero el paso de codificación base64.

Creo que hay algo mal con la codificación base64, así como [ no debería aparecer en una cadena codificada en base64.

En cuanto a la documentación para org.apache.commons.codec.binary.Base64 usted debería ser capaz de hacer esto en codificar:

String encryptedValue = Base64.encodeBase64String(encValue); 

y esto de decodificación:

byte[] encValue = Base64.decodeBase64(encryptedValue); 
+0

thers no es un método como encodeBase64String charles – Harshana

+0

@Harshana: ¿Qué es esto, entonces? http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html#encodeBase64String%28byte[]%29 –

3

La línea

String encryptedValue = encryptedByteValue.toString(); 

es el problema. El tipo de encryptedByteValue es byte [] y llamar a String no es lo que quieres hacer allí. En lugar de tratar

String encryptedValue = Base64.getEncoder().encodeToString(encValue); 

A continuación, utilice Base64.decodeBase64(encryptedValue) en descifrar. Debe hacer eso antes de intentar descifrar sin embargo. Debe deshacer las operaciones en el orden inverso al método de cifrado.

+0

es solo agregar allí para devolver una cadena del método ... también en Base64 no existe dicho método encodeToString – Harshana

+0

Con respecto a toString, llamar a ese método en una matriz casi nunca es lo que desea hacer. Devuelve la dirección en memoria del objeto, no una útil representación de Cadena. En cuanto a Base64, ¿no estás usando esto? http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html Vea el método aquí: http://commons.apache.org/codec/apidocs/org/apache/commons/codec/binary/Base64.html#encodeToString%28byte[]%29 – laz

+0

ive put commons-codec-1.2 y también intente con 1.3 jar, pero parece que el método no se muestra. – Harshana

2

¿Dónde obtiene una versión del códec de Apache que tiene encodeToString o encodeBase64String?

He descargado 1.5 del sitio apache y, aunque dice en la documentación que estos métodos existen, no aparecen cuando se completa el código y crean un método desconocido cuando se los proporciona.

que era capaz de hacer:

byte raw[] = md.digest(); //step 4 
byte hashBytes[] = Base64.encodeBase64(raw); //step 5 
StringBuffer buffer = new StringBuffer(); 
for(int i=0; i<hashBytes.length; i++) 
    buffer.append(hashBytes[i]); 
return buffer.toString(); //step 6 

Y a continuación, la cadena que obtuve fue muy largo, pero se descifra correctamente.

No creo que esta sea la forma "correcta" de hacer las cosas, pero no puedo encontrar los métodos que la documentación dice que están ahí.

0

tengo sustituye a la línea en el ejemplo:

String encryptedValue = encryptedByteValue.toString(); 

con una próxima:

String encryptedValue = new String(encryptedByteValue); 

¡Todo funciona bien!

+1

Tengo serias dudas de que esto solucione la excepción de relleno; es más probable que esté ejecutando una JVM diferente. –

0

Eso estaba bien, sólo necesita para

1) Utilice nueva cadena en lugar de toString() desde toString() no devuelve lo que necesita aquí (en ambos casos, el cifrado y descifrado)

2) primero necesita descodificar, ya que el valor se codifica en base64.

Me encontré con este hilo, pero me llevó un tiempo descubrir el punto real. Estoy publicando mi código para el resto de las personas que se encuentran con este problema.

public abstract class EncryptionDecryption { 
static byte[] key = "[email protected]#[email protected]#$%^&**&^%".getBytes(); 
final static String algorithm="AES"; 

public static String encrypt(String data){ 

    byte[] dataToSend = data.getBytes(); 
    Cipher c = null; 
    try { 
     c = Cipher.getInstance(algorithm); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    SecretKeySpec k = new SecretKeySpec(key, algorithm); 
    try { 
     c.init(Cipher.ENCRYPT_MODE, k); 
    } catch (InvalidKeyException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    byte[] encryptedData = "".getBytes(); 
    try { 
     encryptedData = c.doFinal(dataToSend); 
    } catch (IllegalBlockSizeException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (BadPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    byte[] encryptedByteValue = new Base64().encode(encryptedData); 
    return new String(encryptedByteValue);//.toString(); 
} 

public static String decrypt(String data){ 

    byte[] encryptedData = new Base64().decode(data); 
    Cipher c = null; 
    try { 
     c = Cipher.getInstance(algorithm); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    SecretKeySpec k = 
      new SecretKeySpec(key, algorithm); 
    try { 
     c.init(Cipher.DECRYPT_MODE, k); 
    } catch (InvalidKeyException e1) { 
     // TODO Auto-generated catch block 
     e1.printStackTrace(); 
    } 
    byte[] decrypted = null; 
    try { 
     decrypted = c.doFinal(encryptedData); 
    } catch (IllegalBlockSizeException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (BadPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return new String(decrypted); 
} 

public static void main(String[] args){ 
    String password=EncryptionDecryption.encrypt("password123"); 
    System.out.println(password); 
    System.out.println(EncryptionDecryption.decrypt(password)); 
} 
} 
Cuestiones relacionadas