'Calling .getEncoded() on SecretKey returns null

I use the following code to generate an AES key:

KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder("db_enc_key", KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);

        KeyGenParameterSpec keySpec = builder
                .setKeySize(256)
                .setBlockModes("CBC")
                .setEncryptionPaddings("PKCS7Padding")
                .setRandomizedEncryptionRequired(true)
                .setUserAuthenticationRequired(true)
                .setUserAuthenticationValidityDurationSeconds(5 * 60)
                .build();

        KeyGenerator keyGen = KeyGenerator.getInstance("AES", "AndroidKeyStore");
        keyGen.init(keySpec);

        SecretKey sk = keyGen.generateKey();

but everytime I try to get the byte[] version of the key via sk.getEncoded(), the method returns null. The documentation says that it should return the encoded key, or null if the key does not support encoding, but I don't think that the key doesn't support encoding.

I need the byte[] because I want to encrypt a realm database (for which I need to combine 2 AES-256 keys as byte-arrays) [https://realm.io/docs/java/latest/#encryption]

The official documentation uses SecureRandom, but also states that this is a silly way of doing this and that the key is never stored. Therefore, I wanted to use the KeyStore to securely store the two separate AES-256 keys.

P.S.: The code is only a test code and not the final product, so any comment on coding style is useless. I'm currently just trying to get a working version going.

edit: So I tried the following code, which successfully generates an AES key (though only 16 bytes of length):

SecretKey sk1 = KeyGenerator.getInstance("AES").generateKey();

When I use the getEncoded() method on it, I'll even get the byte array, so naturally I went on and saved it to the KeyStore with the following code:

KeyStore.SecretKeyEntry entry = new KeyStore.SecretKeyEntry(sk1);
KeyStore.ProtectionParameter pp = new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT).build();
keyStore.setEntry("db_enc_key_test", entry, pp);

Which also works. So I tried to read the key from the keystore via KeyStore.Entry entry2 = keyStore.getEntry("db_enc_key_test", null); which worked as well. But when I call entry2.getEncoded() the method returns null again. Is this a keystore problem?

edit2: So I just found out, that symmetric keys generated in (and apparently saved to) the keystore are unexportable in Android M, which seems to be intended, which puts me in a bit of a problem, as I need the key itself to encrypt the realm database.

Some realm-developer here to recommend a best-practice?



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source