2011-06-11 44 views
6

estoy usando este fragmento de código para cifrar/descifrar los datos en la base de datos de mi aplicación:javax.crypto funciona de manera diferente en las diferentes versiones del sistema operativo Android?

http://www.androidsnippets.com/encryptdecrypt-strings

Parece ser que el (funcionamiento javax.crypto.KeyGenerator.generateKey) funciona de forma diferente en Android 2.3.3 OS que en otras versiones (¿anteriores?). Naturalmente, esto presenta un problema importante para mis usuarios cuando actualizan su dispositivo de 2.2 a 2.3.3 y la aplicación comienza a arrojar errores al descifrar la base de datos.

¿Es esto un problema conocido? ¿Estoy usando la biblioteca de cifrado de forma incorrecta? ¿Alguien tiene alguna sugerencia sobre cómo abordar esto para que los datos cifrados en 2.2 puedan descifrarse en 2.3.3?

Creé una aplicación de prueba que alimenta valores a través de la función de cifrado. Cuando lo ejecuto en un 2.2 AVD, obtengo un resultado. Cuando lo ejecuto en un 2.3.3 AVD, obtengo un resultado diferente.

import java.security.SecureRandom; 

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

    import android.app.Activity; 
    import android.os.Bundle; 
    import android.widget.TextView; 

    public class main extends Activity { 
     TextView tvOutput; 
     static String out; 
     String TEST_STRING = "abcdefghijklmnopqrstuvwxyz"; 
     String PASSKEY = "ThePasswordIsPassord"; 

     /** Called when the activity is first created. */ 
     @Override 
     public void onCreate(Bundle savedInstanceState) { 
      super.onCreate(savedInstanceState); 
      setContentView(R.layout.main); 
      tvOutput = (TextView) findViewById(R.id.tvOutput); 
     } 

     @Override 
     public void onResume() { 
      super.onResume(); 
      out = ""; 
      runTest(); 
      tvOutput.setText(out); 
     } 

     private void runTest() { 
      out = "Test string: " + TEST_STRING + "\n"; 
      out += "Passkey: " + PASSKEY + "\n"; 
      try { 
       out += "Encrypted: " + encrypt(PASSKEY, TEST_STRING) + "\n"; 
      } catch (Exception e) { 
       out += "Error: " + e.getMessage() + "\n"; 
       e.printStackTrace(); 
      } 

     } 

     public static String encrypt(String seed, String cleartext) 
     throws Exception { 
      byte[] rawKey = getRawKey(seed.getBytes()); 
      byte[] result = encrypt(rawKey, cleartext.getBytes()); 
      return toHex(result) + "\n" + "Raw Key: " + String.valueOf(rawKey) 
        + "\n"; 
     } 

     private static byte[] getRawKey(byte[] seed) throws Exception { 
      KeyGenerator kgen = KeyGenerator.getInstance("AES"); 
      SecureRandom sr = SecureRandom.getInstance("SHA1PRNG"); 
      sr.setSeed(seed); 
      kgen.init(128, sr); // 192 and 256 bits may not be available 
      SecretKey skey = kgen.generateKey(); 
      byte[] raw = skey.getEncoded(); 
      return raw; 
     } 

     private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception { 
      SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES"); 
      Cipher cipher = Cipher.getInstance("AES"); 
      cipher.init(Cipher.ENCRYPT_MODE, skeySpec); 
       byte[] encrypted = cipher.doFinal(clear); 
      return encrypted; 
     } 

     public static String toHex(String txt) { 
      return toHex(txt.getBytes()); 
     } 

     public static String fromHex(String hex) { 
      return new String(toByte(hex)); 
     } 

     public static byte[] toByte(String hexString) { 
      int len = hexString.length()/2; 
      byte[] result = new byte[len]; 
      for (int i = 0; i < len; i++) 
       result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 
         16).byteValue(); 
      return result; 
     } 

     public static String toHex(byte[] buf) { 
      if (buf == null) 
       return ""; 
      StringBuffer result = new StringBuffer(2 * buf.length); 
      for (int i = 0; i < buf.length; i++) { 
       appendHex(result, buf[i]); 
      } 
      return result.toString(); 
     } 

     private final static String HEX = "ABCDEF"; 

     private static void appendHex(StringBuffer sb, byte b) { 
      sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); 
     } 
    } 

Mi diseño main.xml se ve así:

<?xml version="1.0" encoding="utf-8"?> 
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
     android:orientation="vertical" android:layout_width="fill_parent" 
     android:layout_height="fill_parent"> 
     <TextView android:layout_width="fill_parent" 
      android:layout_height="wrap_content" android:id="@+id/tvOutput" /> 
    </LinearLayout> 

no puedo publicar enlaces o imágenes ya que soy un nuevo usuario, pero se puede descifrar las direcciones URL de las dos imágenes siguientes si desea ver los resultados:

Lo que obtengo de 2,2:

wct.vg/wt/droid/2.2.png

..y desde 2.3.3:

wct.vg/wt/droid/2.3.3.png

+0

Me acabo de encontrar con el mismo problema – thijs

Respuesta

5

Usted está haciendo un mal uso de un generador de números pseudo aleatorio y es la semilla como una función de derivación de claves - este es realmente muy mal estilo. El generador de números pseudoaleatorios "SHA1PRNG" no es un estándar como AES, por lo que nunca se sabe qué implementación se obtiene. Véase también Is there a SHA1PRNG standard?

No me sorprende que obtengas resultados diferentes. Obtener un resultado determinista basado en una semilla determinada no es una propiedad que se pueda esperar de las funciones numéricas pseudoaleatorias.

Si desea derivar una clave criptográfica de una contraseña, utilice un Key Derivation Function como PKCS # 5/PBKDF2. Una implementación de PBKDF2 es AFAIR incluida en Bouncy Castle.

+1

Así la muestra/fragmento que usamos no es muy bien. Ahora uso un algoritmo de generación de clave diferente y todo está bien. (PBEWITHSHAAND256BITAES-CBC-BC, con un olor a sal y algunos iv en el costado) – thijs

1

Me gustaría agradecer a todos los que contribuyeron a esta pregunta.

Esto es lo que finalmente me ocurrió como un ejemplo de cómo cifrar/descifrar usando una contraseña, que parece consistente entre Android 2.2 y 2.3.3.

Actividad principal:

package cc.ndl.testencryption; 

import android.app.Activity; 
import android.os.Bundle; 
import android.widget.TextView; 

public class main extends Activity { 
    TextView tvOutput; 
    static String out; 
    String TEST_STRING = "abcdefghijklmnopqrstuvwxyz"; 
    static String PASSKEY = "ThePasswordIsPassord"; 
    static byte[] SALT = { 1, 2, 4, 5 }; 
    static int ITERATIONS = 1979; 

    /** Called when the activity is first created. */ 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     tvOutput = (TextView) findViewById(R.id.tvOutput); 
    } 

    @Override 
    public void onResume() { 
     super.onResume(); 
     out = ""; 
     runTest(); 
     tvOutput.setText(out); 
    } 

    private void runTest() { 
     out = "Test string: " + TEST_STRING + "\n"; 
     out += "Passkey: " + PASSKEY + "\n"; 
     try { 
      Crypto crypto = new Crypto(PASSKEY); 
      String encryptedData = crypto.encrypt(TEST_STRING); 
      out += "Encrypted: " + encryptedData + "\n"; 
      out += "Decrypted: " + crypto.decrypt(encryptedData); 
     } catch (Exception e) { 
      out += "Error: " + e.getMessage() + "\n"; 
      e.printStackTrace(); 
     } 

    } 
} 

principal Diseño:

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="vertical" android:layout_width="fill_parent" 
    android:layout_height="fill_parent"> 
    <TextView android:layout_width="fill_parent" 
     android:layout_height="wrap_content" android:id="@+id/tvOutput" /> 
</LinearLayout> 

objeto Crypto:

package cc.ndl.testencryption; 

import java.security.spec.AlgorithmParameterSpec; 
import java.security.spec.KeySpec; 

import javax.crypto.Cipher; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 
import javax.crypto.spec.PBEParameterSpec; 

public class Crypto { 

    Cipher ecipher; 
    Cipher dcipher; 

    // 8-byte Salt 
    byte[] salt = { 1, 2, 4, 5, 7, 8, 3, 6 }; 

    // Iteration count 
    int iterationCount = 1979; 

    Crypto(String passPhrase) { 
     try { 
      // Create the key 
      KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, 
        iterationCount); 
      SecretKey key = SecretKeyFactory.getInstance(
        "PBEWITHSHA256AND128BITAES-CBC-BC").generateSecret(keySpec); 
      ecipher = Cipher.getInstance(key.getAlgorithm()); 
      dcipher = Cipher.getInstance(key.getAlgorithm()); 

      // Prepare the parameter to the ciphers 
      AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, 
        iterationCount); 

      // Create the ciphers 
      ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec); 
      dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec); 
     } catch (Exception e) { 
     } 
    } 

    public String encrypt(String str) { 
     String rVal; 
     try { 
      // Encode the string into bytes using utf-8 
      byte[] utf8 = str.getBytes("UTF8"); 

      // Encrypt 
      byte[] enc = ecipher.doFinal(utf8); 

      // Encode bytes to base64 to get a string 
      rVal = toHex(enc); 
     } catch (Exception e) { 
      rVal = "Error encrypting: " + e.getMessage(); 
     } 
     return rVal; 
    } 

    public String decrypt(String str) { 
     String rVal; 
     try { 
      // Decode base64 to get bytes 
      byte[] dec = toByte(str); 

      // Decrypt 
      byte[] utf8 = dcipher.doFinal(dec); 

      // Decode using utf-8 
      rVal = new String(utf8, "UTF8"); 
     } catch (Exception e) { 
      rVal = "Error encrypting: " + e.getMessage(); 
     } 
     return rVal; 
    } 

    private static byte[] toByte(String hexString) { 
     int len = hexString.length()/2; 
     byte[] result = new byte[len]; 
     for (int i = 0; i < len; i++) 
      result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 
        16).byteValue(); 
     return result; 
    } 

    private static String toHex(byte[] buf) { 
     if (buf == null) 
      return ""; 
     StringBuffer result = new StringBuffer(2 * buf.length); 
     for (int i = 0; i < buf.length; i++) { 
      appendHex(result, buf[i]); 
     } 
     return result.toString(); 
    } 

    private final static String HEX = "ABCDEF"; 

    private static void appendHex(StringBuffer sb, byte b) { 
     sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f)); 
    } 
} 
Cuestiones relacionadas