2011-01-04 12 views
10

Tengo una clase simple para tratar de ajustar el cifrado para usarlo en otro lugar de mi programa.Cómo manejar "último bloque incompleto en descifrado"

import java.security.SecureRandom; 
import javax.crypto.Cipher; 
import javax.crypto.KeyGenerator; 
import javax.crypto.spec.SecretKeySpec; 

public final class StupidSimpleEncrypter 
{ 
    public static String encrypt(String key, String plaintext) 
    { 
     byte[] keyBytes = key.getBytes(); 
     byte[] plaintextBytes = plaintext.getBytes(); 
     byte[] ciphertextBytes = encrypt(keyBytes, plaintextBytes); 
     return new String(ciphertextBytes); 
    } 

    public static byte[] encrypt(byte[] key, byte[] plaintext) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, spec); 
      return cipher.doFinal(plaintext); 
     } 
     catch(Exception e) 
     { 
      // some sort of problem, return null because we can't encrypt it. 
      Utility.writeError(e); 
      return null; 
     } 
    } 

    public static String decrypt(String key, String ciphertext) 
    { 
     byte[] keyBytes = key.getBytes(); 
     byte[] ciphertextBytes = ciphertext.getBytes(); 
     byte[] plaintextBytes = decrypt(keyBytes, ciphertextBytes); 
     return new String(plaintextBytes); 
    } 

    public static byte[] decrypt(byte[] key, byte[] ciphertext) 
    { 
     try 
     { 
      Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
      SecretKeySpec spec = new SecretKeySpec(getRawKey(key), "AES"); 
      cipher.init(Cipher.DECRYPT_MODE, spec); 
      return cipher.doFinal(ciphertext); 
     } 
     catch(Exception e) 
     { 
      // some sort of problem, return null because we can't encrypt it. 
      Utility.writeError(e); 
      return null; 
     } 
    } 

    private static byte[] getRawKey(byte[] key) 
    { 
     try 
     { 
      KeyGenerator gen = KeyGenerator.getInstance("AES"); 
      SecureRandom rand = SecureRandom.getInstance("SHA1PRNG"); 
      rand.setSeed(key); 
      gen.init(256, rand); 
      return gen.generateKey().getEncoded(); 
     } 
     catch(Exception e) 
     { 
      return null; 
     } 
    } 
} 

Parece cifrado para manejar correctamente, pero no tanto cuando el descifrado, lo que arroja una javax.crypto.IllegalBlockSizeException "último bloque incompleto en el descifrado" en la línea resaltada. Aquí está el seguimiento de la pila:

 
Location:com.xxxxxx.android.StupidSimpleEncrypter.decrypt ln:49 
last block incomplete in decryption 
javax.crypto.IllegalBlockSizeException: last block incomplete in decryption 
    at org.bouncycastle.jce.provider.JCEBlockCipher.engineDoFinal(JCEBlockCipher.java:711) 
    at javax.crypto.Cipher.doFinal(Cipher.java:1090) 
    at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:44) 
    at com.xxxxxx.android.StupidSimpleEncrypter.decrypt(StupidSimpleEncrypter.java:34) 

que he hecho una buena cantidad de golpearse la cabeza contra mi escritorio para tratar de resolver esto, pero si llego a ningún lado, que termina siendo una excepción diferente. Tampoco puedo encontrar mucho buscando.

¿Qué me estoy perdiendo? Apreciaría cualquier ayuda.

Respuesta

19

No sé si este es el problema con el IllegalBlockSizeException, pero no debe codificar la clave como String, especialmente sin especificar la codificación de caracteres. Si desea hacer esto, use algo como Base-64, que está diseñado para codificar cualquier dato "binario", en lugar de una codificación de caracteres, que solo asigna ciertos bytes a caracteres.

La clave, en general, va a contener valores de bytes que no se corresponden con un carácter en la codificación de plataforma predeterminada. En ese caso, cuando crea el String, el byte se traducirá al "carácter de reemplazo", U + FFFD (& # xFFFD;), y el valor correcto se perderá irremediablemente.

Si intenta utilizar esa representación corrupta de String de la clave más adelante evitará que se recupere el texto sin formato; es posible que pueda causar el IllegalBlockSizeException, pero sospecho que una excepción de relleno no válido sería más probable.

Otra posibilidad es que la plataforma de origen y las codificaciones de caracteres de la plataforma de destino sean diferentes, y que la "decodificación" del texto cifrado produzca muy pocos bytes. Por ejemplo, la codificación fuente es UTF-8 e interpreta dos bytes en la entrada como un solo carácter, mientras que la codificación objetivo es ISO-Latin-1, que representa ese carácter como un solo byte.

+0

Esta fue la causa de mi problema, pero fue con la carga útil y no la clave que será siempre será una cadena estándar en mi caso.Lo cambié para que en el método de cifrado de cadenas, el texto cifrado que se devuelve esté codificado en Base64 desde la matriz de bytes, y en el método de descifrado, la cadena de texto cifrado se decodifique con Base64 en una matriz de bytes. Esto significa que los datos ya no se pierden y el código ahora funciona. –

+0

Lo mismo para la cadena cifrada en sí. Debe almacenarse como byte []. – user1666456

6

Su método getKeySpec() es incorrecto. Genera una nueva clave aleatoria para cifrar y descifrar direcciones. Tienes que usar la misma clave para ambos. Deberías haber notado que no usas el argumento key para ese método.

+1

Esto era parte del problema, y ​​algo me hubiera tomado un tiempo darme cuenta. Gracias. –

1

Si está trabajando en la matriz de bytes, debe usar el mismo tamaño de búfer. Por ejemplo, hay bytearray cuyo tamaño es 1000. Después del cifrado, este tamaño se convierte en 2000. (estos no son valores reales). Si utiliza el búfer para leer todo el archivo cifrado, entonces debe elegir el búfer en el 2000. Resolví el mismo problema de esta manera.

0

Para mí, veo este problema cuando los datos que se descifrarán están dañados (falta 1 carácter). Podría haber sido debido a la transmisión de datos a través de WiFi.

4

Me estaba rasgando los pelos por esto, entre los errores "base mala 64" y "último bloque incompleto" ... Es, por supuesto, asimétrico. Aquí está la esencia como terminé haciendo lo que es de esperar añade más a la discusión que si he tratado de explicar:

public String crypto(SecretKey key, String inString, boolean decrypt){ 
    Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
    byte[] inputByte = inString.getBytes("UTF-8"); 
    if (decrypt){ 
     cipher.init(Cipher.DECRYPT_MODE, key); 
     return new String (cipher.doFinal(Base64.decode(inputByte, Base64.DEFAULT))); 
    } else { 
     cipher.init(Cipher.ENCRYPT_MODE, key); 
     return new String (Base64.encode(cipher.doFinal(inputByte), Base64.DEFAULT)); 
    } 
} 
Cuestiones relacionadas