2012-04-17 15 views
5

Quindi ho visto molti esempi, ho fatto un sacco di googling e ho visto esempi su Stack Overflow ... e ho bisogno di aiuto. Ho un'applicazione Android e sto memorizzare username e password sul dispositivo, e ho bisogno di cifrare loro AES 256. Guardando esempi, questo è quello che ho finora:Android AES 256-bit Encrypt data

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' Sto cercando di renderlo basato su password, quindi un utente creerà un account la prima volta utilizzando il nome utente e la password necessari per comunicare al server e creare un PIN che verrà utilizzato come chiave per queste credenziali memorizzate nel database.

Ciò di cui sono principalmente preoccupato è che questo aspetto è sicuro? So che un sale fisso è cattivo, come posso aggiustarlo?

So che c'è stato come un miliardo di domande su questo, ma voglio qualcuno a venire appena fuori e dire "QUESTO E 'SICURO" o "questo non è sicuro, cambiare questo"

Grazie!


EDIT:

Quindi questo è il codice che ho finora, e sembra funzionare ...

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

Ho usato questo codice per provarlo:

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

Quindi non devo preoccuparmi di un vettore di inizializzazione? O in particolare hardcode un algoritmo Cipher?

Grazie ancora!

+0

Grazie amico per questo aiuto .. :) – Noman

+0

puoi aiutarmi con questo? http://stackoverflow.com/questions/34061675/convert-ios-encryption-to-android :( – MetaSnarf

risposta

4

MODIFICA: Mentre il codice riportato di seguito è corretto, ciò che si sta facendo è praticamente la stessa cosa, con l'IV derivato dalla password, quindi non è necessario memorizzarlo separatamente.

Il tuo codice funziona come previsto? Per la crittografia/decrittografia attuale, si consiglia di utilizzare AES, molto probabilmente in modalità CBC. Allora si avrebbe bisogno di un IV, in modo che diventi qualcosa di simile:

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

Che si tratti di sicuro dipende da quello che si sta utilizzando questo per. Lo scopo del sale è quello di rendere più difficile la forza bruta della passphrase: se è casuale, l'attaccante non può usare le tabelle passphrase pre-generate (passphrase-> key). Se non sei troppo preoccupato per questo tipo di attacco, potresti lasciarlo fisso. Se decidi di renderlo casuale, salvalo semplicemente con i dati crittografati. Lo stesso con la IV.

+0

Suppongo che crittograferei il sale e iv prima di archiviarli con il nome utente e la password crittografati? In caso affermativo, come sarebbe Decifro? Non avrei il sale e iv per impostare il decodificatore, quindi forse sto fraintendendo? – Josh

+0

Il sale non è di per sé un segreto, non ha bisogno di essere crittografato .Non è il IV. –

+0

Ok. Questo ha un senso, grazie per avermi aiutato a capire, modificherò il mio codice e lo pubblicherò. Voglio assicurarmi di ottenere la migliore soluzione possibile Sarebbe in grado di spiegare il conteggio delle iterazioni? è importante se è casuale? Penso di averlo letto se è più alto, il codice richiede più tempo per essere eseguito, ma suppongo che sia più alto è meglio?Immagino che sia qualcosa di effetto eseguire l'algoritmo iteration_count volte prima di restituire un valore finale? – Josh