2012-04-17 19 views
5

Así que he visto muchos ejemplos, he hecho muchas búsquedas en Google y he visto ejemplos en Stack Overflow ... y necesito ayuda. Tengo una aplicación para Android y yo estoy almacenando nombre de usuario y contraseñas en el dispositivo, y necesito cifrar AES 256. De su análisis de ejemplos, esto es lo que tengo hasta ahora:Android AES 256-bit Cifrar datos

public class Security { 
    Cipher ecipher; 
    Cipher dcipher; 

    // 8-byte Salt 
    byte[] salt = { 
     (byte)0xA9, (byte)0x9B, (byte)0xC8, (byte)0x32, 
     (byte)0x56, (byte)0x35, (byte)0xE3, (byte)0x03 
    }; 

    // Iteration count 
    int iterationCount = 19; 

    public Security (String passPhrase) { 
     try { 
      // Create the key 
      KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount); 
      SecretKey key = SecretKeyFactory.getInstance(
       "PBEWithSHAAndAES").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) { 
      e.printStackTrace(); 
     } 
    } 

    public String encrypt(String str) { 
     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 
      return Base64.encodeToString(enc, Base64.DEFAULT); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    public String decrypt(String str) { 
     try { 
      // Decode base64 to get bytes 
      byte[] dec = Base64.decode(str, Base64.DEFAULT); 

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

      // Decode using utf-8 
      return new String(utf8, "UTF8"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 
} 

I' Estoy tratando de hacerlo basado en contraseña, por lo que un usuario creará una cuenta la primera vez usando el nombre de usuario y la contraseña necesarios para comunicarse nuevamente con el servidor, y creará un PIN que se usará como clave para estas credenciales almacenadas en la base de datos.

Lo que más me preocupa es este aspecto seguro? Sé que una sal fija es mala, ¿cómo puedo arreglar eso?

Sé que ha sido como un mil millones de preguntas sobre esto, pero quiero que alguien venga acaba de salir y decir "ESTE ES SEGURO" o "esto no es segura, cambie este"

Gracias!


EDIT:

Así que este es el código que tengo hasta ahora, y parece estar funcionando ...

public class Security { 

    Cipher ecipher; 
    Cipher dcipher; 
    byte[] salt = new byte[8]; 
    int iterationCount = 200; 

    public Security(String passPhrase) { 
     try { 
      // generate a random salt 
      SecureRandom random = new SecureRandom(); 
      random.nextBytes(salt); 

      // Create the key 
      KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount); 
      SecretKey key = SecretKeyFactory.getInstance(
       "PBEWithSHA256And256BitAES-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) { 
      e.printStackTrace(); 
     } 
    } 

    public String encrypt(String str) { 
     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 
      return Base64.encodeToString(enc, Base64.DEFAULT); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    public String decrypt(String str) { 
     try { 
      // Decode base64 to get bytes 
      byte[] dec = Base64.decode(str, Base64.DEFAULT); 

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

      // Decode using utf-8 
      return new String(utf8, "UTF8"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      return null; 
     } 
    } 

    public int getIterationCount() { 
     return iterationCount; 
    } 

    public String getSalt() { 
     return Base64.encodeToString(salt, Base64.DEFAULT); 
    } 
} 

He utilizado este código para probarlo:

Security s = new Security(pinBox.getText().toString()); 
      String encrypted = s.encrypt(passwordBox.getText().toString()); 
      String decrypted = s.decrypt(encrypted); 
      builder.setMessage("pin: " + pinBox.getText().toString() + "\n" + 
        "password: " + passwordBox.getText().toString() + "\n" + 
        "encrypted: " + encrypted + "\n" + 
        "decrypted: " + decrypted + "\n" + 
        "salt: " + s.getSalt()); 

Entonces, ¿no tengo que preocuparme por un vector de inicialización? ¿O codificar específicamente un algoritmo Cipher?

¡Gracias nuevamente!

+0

Gracias amigo por esta ayuda .. :) – Noman

+0

¿me pueden ayudar con esto? http://stackoverflow.com/questions/34061675/convert-ios-encryption-to-android :( – MetaSnarf

Respuesta

4

EDITAR: Si bien el código siguiente es correcto, lo que tiene está haciendo básicamente lo mismo, con el IV derivado de la contraseña, por lo que no tiene que almacenarlo por separado.

¿Su código funciona como se esperaba? Para el cifrado/descifrado real, usted querrá usar AES, muy probablemente en modo CBC. A continuación, se necesitaría una vía intravenosa, por lo que se convierte en algo parecido a esto:

ecipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
byte[] iv = new byte[IV_LENGTH]; 
SecureRandom random = new SecureRandom(); 
random.nextBytes(iv); 
ecipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv)); 
byte[] enc = ecipher.doFinal(utf8); 

Ya se trate de seguro depende de lo que usted está usando esto para. El propósito de la sal es dificultar la fuerza bruta de la frase de contraseña: si es aleatoria, el atacante no puede usar tablas de frase de contraseña pregeneradas (frase de contraseña-> clave). Si no está demasiado preocupado por este tipo de ataque, puede dejarlo solucionado. Si decide hacerlo al azar, simplemente guárdelo con los datos encriptados. Lo mismo con el IV.

+0

Supongo que cifraría la sal y iv antes de almacenarlas con el nombre de usuario y la contraseña cifrados. De ser así, ¿cómo lo haría? ¿Descifraría? No tendría la sal y el iv para configurar el desencriptador, así que tal vez estoy malentendido? – Josh

+0

La sal no es en sí un secreto, no necesita ser encriptada. Tampoco es el IV. –

+0

Ok. Eso tiene sentido. Gracias por ayudarme a entender. Editaré mi código y lo publicaré. Quiero asegurarme de obtener la mejor solución posible. ¿Podría explicar el recuento de iteraciones? ¿Importa si es aleatorio? Creo que lo he leído si es más alto, el código tarda más en ejecutarse, ¿pero supongo que lo mejor es mejor?Supongo que es algo a efecto de ejecutar el algoritmo iteration_count veces antes de devolver un valor final? – Josh

Cuestiones relacionadas