【问题标题】:Android 9 - KeyStore exception android.os.ServiceSpecificExceptionAndroid 9 - KeyStore 异常 android.os.ServiceSpecificException
【发布时间】:2019-02-12 19:47:16
【问题描述】:

如果我在 Android 9 上运行此代码,我会收到以下异常:

private static KeyStore.PrivateKeyEntry getPrivateKeyEntry(String alias) {
        try {
            KeyStore ks = KeyStore
                    .getInstance(SecurityConstants.KEYSTORE_PROVIDER_ANDROID_KEYSTORE);
            ks.load(null);
            KeyStore.Entry entry = ks.getEntry(alias, null);

            if (entry == null) {
                Log.w(TAG, "No key found under alias: " + alias);
                Log.w(TAG, "Exiting signData()...");
                return null;
            }

            if (!(entry instanceof KeyStore.PrivateKeyEntry)) {
                Log.w(TAG, "Not an instance of a PrivateKeyEntry");
                Log.w(TAG, "Exiting signData()...");
                return null;
            }
            return (KeyStore.PrivateKeyEntry) entry;
        } catch (Exception e) {
            Log.e(TAG, e.getMessage(), e);
            return null;
        }
    }

例外:

KeyStore 异常 android.os.ServiceSpecificException:(代码 7) 在 android.os.Parcel.createException(Parcel.java:1956) 在 android.os.Parcel.readException(Parcel.java:1910) 在 android.os.Parcel.readException(Parcel.java:1860) 在 android.security.IKeystoreService$Stub$Proxy.get(IKeystoreService.java:786) 在 android.security.KeyStore.get(KeyStore.java:195) 在 android.security.keystore.AndroidKeyStoreSpi.engineGetCertificateChain(AndroidKeyStoreSpi.java:118) 在 java.security.KeyStoreSpi.engineGetEntry(KeyStoreSpi.java:484) 在 java.security.KeyStore.getEntry(KeyStore.java:1560) 在 com.phenodev.testenc.KeyStoreHelper.getPrivateKeyEntry(KeyStoreHelper.java:151) 在 com.phenodev.testenc.KeyStoreHelper.encrypt(KeyStoreHelper.java:173) 在 com.phenodev.testenc.KeyStoreEncryptor.encrypt(KeyStoreEncryptor.java:19)

请帮忙解决。

【问题讨论】:

  • 我也有同样的问题 :-(

标签: java android keystore android-keystore


【解决方案1】:

终于找到了解决办法。看起来因为 Android P (KeyStore.PrivateKeyEntry) keyStore.getEntry("alias", null) 不是获取私钥的正确方法。

通过这种方式访问​​私钥/公钥,我能够摆脱这个警告

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

PrivateKey privateKey = (PrivateKey) keyStore.getKey("alias", null);
PublicKey publicKey = keyStore.getCertificate("alias").getPublicKey();

【讨论】:

  • 虽然我目前正在以这种方式提取密钥,但在具有 API 29 的模拟器中,当我第一次尝试获取密钥时(仅是第一次),我仍然会收到警告。如果我终止进程并再次启动应用程序,警告就消失了。
  • 为了清楚起见,我在 API 级别 21 上对其进行了测试(看看我们是否需要在 API 版本上使用不同的逻辑条件),但它似乎也可以正常工作。
  • 它没有解决问题,至少在 Android Q,beta 2 上。
  • 此外,异常仍然存在,因此不仅会在您第一次启动应用程序时发生(请参阅上述注释)。
  • 这不是最终的解决方案,即使使用此代码,在 Android 9 中仍会不时抛出异常(根据我的测试,应用程序打开的 7 次中有 1 次)。这不仅仅是一个警告,因为它总是伴随着这个 NPE,这会导致没有数据被加密或解密:尝试调用虚拟方法 'java.security.PublicKey java.security.cert.Certificate.getPublicKey() ' 在空对象引用上。
【解决方案2】:

我在从 AndroidKeyStore 检索非对称密钥时遇到了同样的问题

我基于 Dr Glass 回答获取密钥的解决方案如下:(aliasKey 是您的别名字符串)

公钥:

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

val asymmetricPublicKey = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    keyStore.getCertificate(aliasKey).publicKey
} else {
    val asymmetricKey = keyStore.getEntry(aliasKey, null) as KeyStore.PrivateKeyEntry
    asymmetricKey.certificate.publicKey
}

私钥:

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

val asymmetricPrivateKey = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    keyStore.getKey(aliasKey, null) as PrivateKey
} else {
    val asymmetricKey = keyStore.getEntry(aliasKey, null) as KeyStore.PrivateKeyEntry
    asymmetricKey.privateKey
}

并且使用此代码,我在模拟器和/或带有 Android P 的设备中没有警告

【讨论】:

    【解决方案3】:

    我找到了如何删除警告的解决方案,如果您也可以测试它,那就太好了。实际上调用方法的顺序是问题所在。

    val privateKey = keyStore.getKey(alias, null)
    val publicKey = if (privateKey != null) keyStore.getCertificate(alias).publicKey else null
    
    if (privateKey != null && publicKey != null) {
        KeyPair(publicKey, privateKey as PrivateKey)
    }
    

    这是调用方法的正确顺序。

    当你这样做时:

    val privateKey = keyStore.getKey(alias, null)
    val certificate = keyStore.getCertificate(alias)
    
    if (privateKey != null && certificate != null) {
        KeyPair(certificate.publicKey, privateKey as PrivateKey)
    }
    

    您将收到以下警告(因为 keyStore.getCertificate(alias):

    KeyStore exception
    android.os.ServiceSpecificException:  (code 7)
        at android.os.Parcel.createException(Parcel.java:2085)
        at android.os.Parcel.readException(Parcel.java:2039)
        at android.os.Parcel.readException(Parcel.java:1987)
        at android.security.keystore.IKeystoreService$Stub$Proxy.get(IKeystoreService.java:978)
        at android.security.KeyStore.get(KeyStore.java:236)
        at android.security.KeyStore.get(KeyStore.java:225)
        at android.security.keystore.AndroidKeyStoreSpi.engineGetCertificate(AndroidKeyStoreSpi.java:160)
        at java.security.KeyStore.getCertificate(KeyStore.java:1120)
    

    这意味着,没有私钥,您应该首先创建并存储一个密钥对然后在密钥存储中搜索它。

    现在 MatPag 的答案应该是这样的:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val privateKey = keyStore.getKey(alias, null)
            val publicKey = if (privateKey != null) keyStore.getCertificate(alias).publicKey else null
    
            return if (privateKey != null && publicKey != null) {
                KeyPair(publicKey, privateKey as PrivateKey)
            } else {
                null
            }
    } else {
            val asymmetricKey = keyStore.getEntry(alias, null) as KeyStore.PrivateKeyEntry
            val privateKey = asymmetricKey.privateKey
            val publicKey = if(privateKey != null) asymmetricKey.certificate.publicKey else null
    
            return if(privateKey != null && publicKey != null) {
                KeyPair(publicKey, privateKey as PrivateKey)
            } else {
                null
            }
    }
    

    【讨论】:

      猜你喜欢
      • 2021-11-12
      • 2019-11-14
      • 1970-01-01
      • 2015-10-09
      • 1970-01-01
      • 1970-01-01
      • 2018-04-30
      • 1970-01-01
      相关资源
      最近更新 更多