Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android AES 256-bit Encrypt data

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!

like image 394
joshkendrick Avatar asked Apr 17 '12 20:04

joshkendrick


People also ask

Does Android use AES 256?

AES-256 is supported by android.

Does Android use AES encryption?

Android offers storage encryption using the Advanced Encryption Standard (AES). And most new Android devices provide AES via Arm's version 8 processor cryptography extensions. However, Android runs on a wide range of devices.

Do Android phones Encrypt data?

Virtually all Android devices on the market now come with encryption enabled by default. This is because Google required manufacturers to enable full-disk encryption starting with Android 6.0 Marshmallow, which debuted all the way back in 2015.

Is 256-bit AES encryption secure?

Out of 128-bit, 192-bit, and 256-bit AES encryption, 256-bit AES encryption is technically the most secure because of its key length size. Some go as far as to label 256-bit AES encryption overkill because it, based on some estimations, would take trillions of years to crack using a brute-force attack.


1 Answers

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.

like image 151
Nikolay Elenkov Avatar answered Oct 03 '22 17:10

Nikolay Elenkov