Android AES 256-bit Encrypt data

匿名 (未验证) 提交于 2019-12-03 02:49:01

问题:

So I've seen a lot of examples, and done a lot of googling, and looked at examples on Stack Overflow... and I need help. I've got an Android application and I'm storing username and passwords on the device, and I need to encrypt them AES 256. From looking at examples, this is what I have so far:

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'm trying to make it password based, so a user will create an account the first time using the username and password needed to communicate back to the server, and create a PIN that will be used as the key for these credentials stored in the database.

What I'm mainly concerned about is does this look secure? I know a fixed salt is bad, how do I fix that?

I know there's been like a billion questions about this, but I want someone to just come out and say "THIS IS SECURE" or "THIS IS NOT SECURE, CHANGE THIS"

Thanks!


EDIT:

So this is the code I have so far, and it seems to be working...

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

I used this code to test it:

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

So I don't need to worry about an initialization vector? Or specifically hardcode a Cipher algorithm?

Thanks again!

回答1:

EDIT: While the code below is correct, what you have is doing basically the same thing, with the IV derived from the password, so you don't have to store it separately.

Does your code work as expected? For the actual encryption/decryption you would want to use AES, most probably in CBC mode. Then you would need an IV, so it becomes something like this:

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

Whether it is secure depends on what you are using this for. The purpose of the salt is to make it harder to brute force the passphrase: if it's random the attacker cannot use pre-generated passphrase tables (passphrase->key). If you are not too worried about this sort of attack, you might leave it fixed. If you decide to make it random, just store it with the encrypted data. Same with the IV.



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!