Grant Carlisle
Grant Carlisle

Reputation: 173

Getting SecretKey back from Android Keystore and using with Realm IO

I am using Realm as my local database and need it to be encrypted. I am trying to use the Android Keystore to store a SecretKey and it appears to be storing it in the KeyStore but when I then try and use SecretKey.getEncoded() it always returns null. Here's the code:

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
        Enumeration<String> aliases = keyStore.aliases();

        while(aliases.hasMoreElements()) {
            Log.v("KEY ALIAS",aliases.nextElement());
        }


        SecretKey keyStoreKey = (SecretKey) keyStore.getKey(ALIAS, null);

        if(keyStoreKey == null) {
            Log.v("NO KEY","USING NEW KEY");
            KeyGenParameterSpec.Builder builder = new KeyGenParameterSpec.Builder(ALIAS,
                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT);
            KeyGenParameterSpec keySpec = builder
                    .setKeySize(512)
                    .setRandomizedEncryptionRequired(true)
                    .setUserAuthenticationRequired(true)
                    .setUserAuthenticationValidityDurationSeconds(5 * 60)
                    .build();

            KeyGenerator kg = KeyGenerator.getInstance("HmacSHA1", "AndroidKeyStore");
            kg.init(keySpec);
            keyStoreKey = kg.generateKey();

            keyStore.setEntry(ALIAS,
                    new KeyStore.SecretKeyEntry(keyStoreKey),
                    new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
                            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
                            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
                            .build());
        } else {
            Log.v("GOT KEY","USING OLD KEY");
        }

        //THIS IS THE LINE THAT RETURNS NULL WHEN USING A KEY FROM KEYSTORE
        byte[] key = keyStoreKey.getEncoded();

I then will use the byte array 'key' in realm. The code works fine on first launch (when creating the key) but if it finds it in the keystore it just returns null when getting the bytes of the key.

Upvotes: 0

Views: 1097

Answers (1)

Christian Melchior
Christian Melchior

Reputation: 20126

That is intentional. The Android KeyStore does not expose the key material once it has been saved, you can only ask the KeyStore to perform actions on your behalf..

One solution is using a double layered key. It works roughly this way:

  1. Generate the key you want to use to unlock the Realm (keyA).
  2. Generate a 2nd random key (keyB).
  3. Save keyB in the KeyStore.
  4. Encrypt keyA using keyB. This is now a random string can you can save anywhere.
  5. Save the encrypted version of keyA in SharedPreferences.
  6. When opening the Realm, decrypt the encrypted keyA from SharedPreferences in the KeyStore (using KeyB) and give it to Realm.

We are working on a sample project demonstrating it here (still work-in-progress).

Upvotes: 2

Related Questions