在Android密钥库中存储HMAC密钥

3
我正在使用以下代码创建HMAC密钥并将其返回为字符串。
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();
    }

我该如何将此存储在Android密钥库中?我尝试使用以下代码:
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);

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

无论以何种格式(hmacKey是字符串/字节还是javax.crypto.SecretKey),我都会得到错误。下面是错误提示: 如果传递的密钥为 hmacKey
Wrong 2nd argument type. Found: 'java.security.Key', required: 'java.security.KeyStore.Entry'

同样适用于当我传递字符串或字节数组的情况。

如果我将参数强制转换为java.security.KeyStore.Entry,它仍然无法正常工作。

这是正确的方法吗?有人可以指点如何使用别名将HMAC密钥存储在密钥库中。如何将hmack密钥转换为java.security.KeyStore.Entry格式?


抱歉表述不清楚,已经编辑了问题。 - Sid
你不能只是存储上面生成的“key”吗?我在问题中看到了很多废话。这似乎不是MCSE。 - Maarten Bodewes
不,它不能被直接存储。我目前正在使用共享首选项来存储此密钥。不确定其安全性方面,这就是为什么我想将其存储在密钥库中的原因。代码的第一部分完全正常,我也可以创建一个HMAC密钥并返回它。问题出在我试图使用别名将其存储在Android密钥库中的那一部分。 - Sid
1个回答

3
Android密钥库的创建旨在使您能够在应用程序代码之使用非对称密钥和对称密钥。如培训材料所指定:

密钥材料永远不会进入应用程序进程。当应用程序使用Android Keystore密钥执行加密操作时,明文、密文和要签名或验证的消息将在系统进程中传递,该进程执行加密操作。如果应用程序进程受到攻击者的攻击,攻击者可能能够使用该应用程序的密钥,但无法提取其密钥材料(例如,用于在Android设备之外使用)。

因此,在应用程序代码内部生成密钥 - 因此在密钥库之外 - 不是一个好主意。如何在密钥库内部生成秘密密钥已在KeyGenParameterSpec类的API中定义,适用于HMAC密钥。
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);

其他关键类型可以在KeyProperties类中找到(链接)


问题在于我从服务器接收到加密的hmack密钥,因此我只需要将其存储在设备上可用的最安全选项中。稍后我会提取它,使用私钥解密并根据需要使用它。我认为密钥库比共享首选项更安全,因此希望使用它来存储密钥。这就是我卡住的地方,所以现在我正在使用共享首选项。您有什么想法可以将外部生成的hmac保存在密钥库中吗?同时感谢Maarten不断关注此事。 - Sid
将该密钥与存储中的密钥进行包装,怎么样? - Maarten Bodewes
不确定如何做到这一点,如果您的意思是将其强制转换为密钥库条目,则无法实现。此外,在任何时候,我只会在我的密钥库中拥有公钥/私钥对。除此之外,我还想存储hmac密钥。 - Sid
3
你需要做的是从服务器获取HMAC密钥并将其导入到Android KeyStore中。不要自己尝试加密,Android KeyStore能更好地保护它。查看KeyProtection文档(https://developer.android.com/reference/android/security/keystore/KeyProtection.html)以获取将HMAC密钥导入到Android KeyStore和使用它的示例。 - divegeek
这里需要注意:包装密钥是一种加密操作,可从Java密码类(Cipher.WRAP)中使用。 - Maarten Bodewes
如果您能够用代码构建出一个答案,那么我肯定会点赞。我没有准备好Android环境,如果可以通过这种方式存储HMAC密钥,那么这绝对是最直接的答案。 - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接