KeyStore "unsupported protection parameter"

Viewed 496

I'm trying to store a SecretKey in the Android KeyStore, and I'm even directly following the documentation found here: KeyProtection: AES Key for Encryption / Description in GCM Mode, which still doesn't work.

I seem to get the following exception when I run this:

java.security.KeyStoreException: unsupported protection parameter

This exception is specifically raised when I call keyStore.setEntry(...).

I'm running Android 10 on a Samsung Galaxy S10, if that makes any difference.

@RequiresApi(23)
private static KeyStore.ProtectionParameter getProtectionParameter() {
    return new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .build();
}

@RequiresApi(23)
private static SecretKey getSecretKey() throws Exception {
    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(null);

    if (keyStore.containsAlias(KEY_ALIAS)) {
        final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore
                .getEntry(KEY_ALIAS, null);
        return secretKeyEntry.getSecretKey();
    }

    final KeyGenerator keyGenerator = KeyGenerator
            .getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
    final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS,
            KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .build();

    keyGenerator.init(keyGenParameterSpec);
    SecretKey k = keyGenerator.generateKey();

    keyStore.setEntry(
        KEY_ALIAS,
        new KeyStore.SecretKeyEntry(k),
        getProtectionParameter()
    );

    return getSecretKey();
}
1 Answers

It turns out the issue I had was in my KeyStore.getInstance and KeyGenerator.getInstance lines. One of them was using KeyStore.getDefaultType() where as the other one was using AndroidKeyStore. Changing this got rid of the unsupported protection parameter issue.

Additionally, after fixing that I ran into an issue with updating the Protection Parameter.

It turns out, that the following section of the code is incorrect

SecretKey k = keyGenerator.generateKey();

keyStore.setEntry(
    KEY_ALIAS,
    new KeyStore.SecretKeyEntry(k),
    getProtectionParameter()
);

It tries to insert the key into the keystore twice, since generateKey() already inserts it into the KeyStore.

The fully working code would look like this

@RequiresApi(23)
private static SecretKey getSecretKey() throws Exception {
    KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
    keyStore.load(null, null);

    final KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore
                .getEntry(KEY_ALIAS, null);
    if (secretKeyEntry != null) {
        return secretKeyEntry.getSecretKey();
    }

    final KeyGenerator keyGenerator = KeyGenerator
            .getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore");
    final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEY_ALIAS,
            KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
            .build();

    keyGenerator.init(keyGenParameterSpec);
    SecretKey k = keyGenerator.generateKey();
    return getSecretKey();
}
Related