Android KeyStore 系统 - 保存密钥对?

Android KeyStore System - Saving a KeyPair?

我目前正在尝试在我的 Android 应用程序中组合一个正常运行的 KeyStore 实现。我目前正在构建至少 API 18,这样我就可以充分利用我的应用程序的私有 KeyStore。我正在尝试生成 nKeyPair 对象,并将它们保存在 KeyStore 中以供以后检索。我看过 this question, however it seems a bit outdated (2012) and does not really answer anything all that well. Honestly, most of the questions I've found on Stack Overflow seem to be incredibly outdated, like here and here.

所以我的预期流程是这样的:

  1. 尝试从与适当别名相关的证书中检索 public 密钥。
  2. 如果此 public 键为空,则创建一个新键。
  3. 利用KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
  4. 生成密钥对。

到目前为止,一切都非常简单,并且工作正常。接下来是毛茸茸的地方。

  1. 保存密钥对。通过 KeyStore.getInstance("AndroidKeyStore");
  2. 初始化 KeyStore
  3. 尝试通过 X509V3CertificateGenerator 生成 X509Certificate。该证书是自签名的。对于证书,我将签名算法设置为 "SHA1WithRSAEncryption".
  4. 最后,调用keyStore.setKeyEntry

最后一步似乎有两个选择:

keyStore.setKeyEntry(String alias, byte[] key, Certificate[] chain);

keyStore.setKeyEntry(String alias, Key key, char[] password, Certificate[] chain);

我从两者中的第二个开始,但收到 java.security.KeyStoreException: entries cannot be protected with passwords .... 好吧,这很奇怪,为什么会有一个保证抛出异常的方法?让我们试试 1 号门。

此时,当我调用 setKeyEntry 并将 keyPair.getPrivate().getEncoded() 作为第二个参数传递时,我从系统收到 java.security.KeyStoreException: Operation not supported because key encoding is unknown

所以我有点不知所措。像这样的加密对我来说是相对较新的,所以我希望有人可以阐明 Android KeyStore 系统这个非常混乱的情况。

所以我找到了答案 - 希望这将有助于为未来的用户解决一些问题,因为文档中没有明确列出。

KeyPairGeneratorSpec.Builder 有一个方法 setAlias。生成密钥后,它会自动存储在该别名下的 KeyStore 中。不需要额外的储蓄来让它发挥作用。然后,您可以通过使用与 KeyPairGenerator 相同的 String provider 实例化 KeyStore 来轻松检索这些密钥。

我试图将 PKCS12 文件(比如用户手动下载的)导入 AndroidKeyStore。好像

keyStore.setKeyEntry(String alias, byte[] key, Certificate[] chain);

未由 AndroidKeyStore 实现,它总是抛出以下异常:

KeyStoreException("Operation not supported because key encoding is unknown")

参考: https://android.googlesource.com/platform/frameworks/base.git/+/android-5.1.1_r19/keystore/java/android/security/AndroidKeyStore.java

@Override
    public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain)
            throws KeyStoreException {
        throw new KeyStoreException("Operation not supported because key encoding is unknown");
    }

所以,我尝试使用

keyStore.setKeyEntry(String alias, Key key, char[] password, Certificate[] chain);

通过将密码传递为空。它对我来说很好。