Storing a hmac key in Android keystore

2020-06-06 04:14发布

问题:

I am using the below code to create a hmac key and returning it as a string.

KeyGenerator keyGen = null;
    try {
        keyGen = KeyGenerator.getInstance("HmacSHA256");
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    SecretKey key = keyGen.generateKey();
    byte[] encoded = key.getEncoded();
    String s=Base64.encodeToString(encoded, Base64.DEFAULT);
    Log.i("Hmac key before encrypt",s);

    try {
        KeyStore keystore = KeyStore.getInstance("AndroidKeyStore");
        keystore.load(null, null);
        KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keystore.getEntry("temp", null);
        RSAPublicKey publicKey = (RSAPublicKey) privateKeyEntry.getCertificate().getPublicKey();

        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] cipherBytes = cipher.doFinal(encoded);

        return Base64.encodeToString(cipherBytes,Base64.DEFAULT);


    } catch (UnrecoverableEntryException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }

How can I store this in the android keystore?. I have tried using the below code:

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);

        KeyStore.ProtectionParameter param = new KeyStore.PasswordProtection("test".toCharArray());
        keyStore.setEntry("key1",hmacKey,param);

I get an errors no matter what format hmacKey is in: String/Bytes or javax.crypto.SecretKey. Below are the errors: In case of passing Key hmacKey:

Wrong 2nd argument type. Found: 'java.security.Key', required: 'java.security.KeyStore.Entry'

Same in cases where I pass a string or byte array.

If I typecast the parameter to java.security.KeyStore.Entry, it still doesn't work.

Is this the correct way of doing so? Can anyone give pointers as to how the HMAC key can be stored in the keystore using an alias. How can convert the hmack key to java.security.KeyStore.Entry format?

回答1:

The Android key store was created to allow you to use asymmetric keys and symmetric keys outside your application code. As specified in the training material:

Key material never enters the application process. When an application performs cryptographic operations using an Android Keystore key, behind the scenes plaintext, ciphertext, and messages to be signed or verified are fed to a system process which carries out the cryptographic operations. If the app's process is compromised, the attacker may be able to use the app's keys but will not be able to extract their key material (for example, to be used outside of the Android device).

So the idea of generating the key inside the application code - and thus outside the key store - is not a good idea. How to generate a secret key inside the key store is defined for HMAC keys in the API for the KeyGenParameterSpec class:

KeyGenerator keyGenerator = KeyGenerator.getInstance(
         KeyProperties.KEY_ALGORITHM_HMAC_SHA256, "AndroidKeyStore");
keyGenerator.initialize(
         new KeyGenParameterSpec.Builder("key2", KeyProperties.PURPOSE_SIGN).build());
SecretKey key = keyGenerator.generateKey();
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(key);
...

// The key can also be obtained from the Android Keystore any time as follows:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
key = (SecretKey) keyStore.getKey("key2", null);

Other key types can be found in the KeyProperties class