2012-04-17 110 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