2012-04-17 104 views
5

所以我見過很多例子,並做了大量的Google搜索,並看了堆棧溢出的例子......我需要幫助。我有一個Android應用程序,我在設備上存儲的用戶名和密碼,我需要加密AES他們從256看的例子,這是我到目前爲止有:Android AES 256位加密數據

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

我m試圖使其基於密碼,所以用戶將首次使用用於與服務器通信所需的用戶名和密碼創建一個帳戶,並創建一個PIN作爲存儲在數據庫中的憑證的密鑰。

我主要關心的是這看起來安全嗎?我知道固定鹽是不好的,我該如何解決這個問題?

我知道有許多人喜歡這個一十億的問題,但我希望有人剛出來,並說「這是安全」或「這是不是安全的,改變這一現狀」

謝謝!


編輯:

所以這是我到目前爲止的代碼,它似乎是工作...

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

我用這個代碼來測試它:

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

所以我不需要擔心初始化向量?或者專門硬編碼密碼算法?

再次感謝!

+0

感謝隊友的幫助.. :) – Noman 2013-10-31 11:26:54

+0

你能幫我解決這個問題嗎? http://stackoverflow.com/questions/34061675/convert-ios-encryption-to-android :( – MetaSnarf 2015-12-04 04:07:42

回答

4

編輯:雖然下面的代碼是正確的,你有什麼基本上是一樣的事情,與從密碼派生的IV,所以你不必分開存儲它。

您的代碼是否按預期工作?對於實際的加密/解密,您希望使用AES,最有可能是CBC模式。那麼你需要一個IV,所以它變成這樣的:

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

是否安全取決於你使用的是什麼。這個鹽的目的是使得強制密碼變得更難:如果它是隨機的,攻擊者不能使用預先生成的密碼錶(密碼短語>密鑰)。如果你不太擔心這種攻擊,你可以修改它。如果您決定將其隨機存儲,請將其與加密數據一起存儲。與IV一樣。

+0

我假設我會加密鹽和iv之前存儲他們與加密的用戶名和密碼?如果是這樣,如何我解密了?我不會有salt和iv來設置解密器,所以也許我誤解了? – Josh 2012-04-18 12:16:33

+0

鹽本身不是祕密,它不需要加密,也不是IV。 – 2012-04-18 12:20:55

+0

好的。這很有道理,謝謝你幫助我理解,我將編輯我的代碼,並將其發回。我想確保我獲得最佳解決方案。 你能解釋迭代計數嗎?它是否隨機很重要?我認爲如果它更高,它會讀取它,代碼需要更長時間才能執行,但是我認爲越高越好?我猜這是在返回最終值之前運行算法iteration_count次的效果。 – Josh 2012-04-18 12:32:56