Android 4.2 broke my encrypt/decrypt code and the provided solutions don’t work

First a disclaimer:

DO NOT ever use SecureRandom to derive a key! This is broken and doesn’t make sense!

The following block of code from the question tries to deterministically derive a key from a password, called the “seed” as the password is used to “seed” the random number generator.

KeyGenerator keygen = KeyGenerator.getInstance("AES");
SecureRandom secrand = SecureRandom.getInstance("SHA1PRNG");
secrand.setSeed(seed.getBytes());
keygen.init(128, secrand);
SecretKey seckey = keygen.generateKey();

However, the "SHA1PRNG" algorithm is not well defined and implementations of "SHA1PRNG" may return different or even fully random keys as a result.


If you’re reading an AES key from disk, just store the actual key and don’t go through this weird dance. You can get a SecretKey for AES usage from the bytes by doing:

    SecretKey key = new SecretKeySpec(keyBytes, "AES");

If you’re using a password to derive a key, follow Nelenkov’s excellent tutorial with the caveat that a good rule of thumb is the salt size should be the same size as the key output.

The iterationCount (work factor) is of course subject to change and should be changed as CPU power progresses – generally it is recommended not to go lower than 40 to 100K as of 2018. Beware that PBKDF2 only adds a constant time delay to guessing passwords; it is not a replacement for really weak passwords.

It looks like this:

    /* User types in their password: */
    String password = "password";

    /* Store these things on disk used to derive key later: */
    int iterationCount = 1000;
    int saltLength = 32; // bytes; should be the same size as the output (256 / 8 = 32)
    int keyLength = 256; // 256-bits for AES-256, 128-bits for AES-128, etc
    byte[] salt; // Should be of saltLength

    /* When first creating the key, obtain a salt with this: */
    SecureRandom random = new SecureRandom();
    byte[] salt = new byte[saltLength];
    random.nextBytes(salt);

    /* Use this to derive the key from the password: */
    KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt,
                iterationCount, keyLength);
    SecretKeyFactory keyFactory = SecretKeyFactory
                .getInstance("PBKDF2WithHmacSHA1");
    byte[] keyBytes = keyFactory.generateSecret(keySpec).getEncoded();
    SecretKey key = new SecretKeySpec(keyBytes, "AES");

That’s it. Anything else you should not use.

Leave a Comment