无法恢复的密钥异常:无法获取私钥信息,密钥库异常:无效的密钥数据块。

28
在我们的应用程序中,我们遇到了Android Keystore中的数据突然无法访问的问题。我们看到的具体异常如下:
java.security.UnrecoverableKeyException: Failed to obtain information about private key
 at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStorePublicKeyFromKeystore(AndroidKeyStoreProvider.java:223)
 at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(AndroidKeyStoreProvider.java:259)
 at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(AndroidKeyStoreProvider.java:269)
 at android.security.keystore.AndroidKeyStoreSpi.engineGetKey(AndroidKeyStoreSpi.java:94)
 at java.security.KeyStoreSpi.engineGetEntry(KeyStoreSpi.java:474)
 at java.security.KeyStore.getEntry(KeyStore.java:1560)
 at <PACKAGE_NAME>.EncryptionInteractor.generateKeys(EncryptionInteractor.java:104)
 at <PACKAGE_NAME>.EncryptionInteractor.generateKeys(EncryptionInteractor.java:100)
 at <PACKAGE_NAME>.EncryptionInteractor.init(EncryptionInteractor.java:93)
 at <PACKAGE_NAME>.EncryptionInteractor.<init>(EncryptionInteractor.java:80)
 at <PACKAGE_NAME>.EncryptionInteractor.init(EncryptionInteractor.java:65)
 at <PACKAGE_NAME>.<APPLICATION_CLASS>.onCreate(APPLICATION_CLASS.java:17)
 at android.app.Instrumentation.callApplicationOnCreate(Instrumentation.java:1118)
 at android.app.ActivityThread.handleBindApplication(ActivityThread.java:5791)
 at android.app.ActivityThread.-wrap1(Unknown Source:0)
 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1661)
 at android.os.Handler.dispatchMessage(Handler.java:105)
 at android.os.Looper.loop(Looper.java:164)
 at android.app.ActivityThread.main(ActivityThread.java:6541)
 at java.lang.reflect.Method.invoke(Native Method)
 at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
Caused by: android.security.KeyStoreException: Invalid key blob
 at android.security.KeyStore.getKeyStoreException(KeyStore.java:695)
 at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStorePublicKeyFromKeystore(AndroidKeyStoreProvider.java:224)
  ... 21 more

我们还没有找到一种可靠的方法来复现这个问题。有几篇文章提到可能会导致密钥库“忘记”密钥或被锁定的可能状态,比如这里。然而,据我所知,我们并没有遇到这些边缘情况中的任何一种。看起来这种情况发生在首次设置密钥后让设备静置一段时间之后。我们发现这种情况发生在多个模拟器和设备上,从21到26不等。此外,这些设备使用滑动解锁或PIN码。更改PIN码或安全方法似乎不会导致这个问题。再次强调,这个问题似乎发生在设备闲置数天后。
我还在这里找到了另外两个SOs这里这里,以及一个Google问题。如果我理解正确的话,这两个链接中的答案似乎都依赖于调用者在创建密钥时调用了setUserAuthenticationValidityDurationSeconds,而我们并没有这样做。此外,给出的解决方案似乎依赖于仅删除密钥并生成一个新的密钥。
以下是我们针对版本>= API 23的密钥设置。由于我们主要在API >= 23上遇到了这个问题,所以我省略了我们在旧版本中的密钥生成部分。
private static final int RSA_KEY_SIZE = 2048;
private static final String CERT_SUBJECT_STRING = "CN=<COMPANY_NAME> Android App O=<COMPANY_NAME>";
private static final String ANDROID_KEY_STORE = "AndroidKeyStore";

try {
        String alias = KEY_NAME;
        KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE);

        Calendar start = Calendar.getInstance();
        Calendar end = Calendar.getInstance();
        end.add(Calendar.YEAR, 1);
        KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
            .setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(RSA_KEY_SIZE, RSAKeyGenParameterSpec.F4))
            .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
            .setBlockModes(KeyProperties.BLOCK_MODE_ECB)
            .setCertificateNotAfter(end.getTime())
            .setCertificateNotBefore(start.getTime())
            .setCertificateSerialNumber(BigInteger.ONE)
            .setCertificateSubject(new X500Principal(CERT_SUBJECT_STRING))
            .build();
        generator.initialize(spec);
        generator.generateKeyPair();
    } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    }

我们随后尝试通过keyStore.getEntry(KEY_NAME, null)来访问密钥。同样,这在一段时间内是有效的,但后来会开始抛出上述异常。

5
你找到任何解决方案了吗? - David Miguel
1个回答

0

我在KeyStore的稳定性方面也遇到了问题。

解决方案是使用私钥

PrivateKey privKey = ks.getKey(alias, password)

并将其转换为公钥

PublicKey pubKey = ks.getCertificate(alias).getPublicKey();

使用getEntry代替

ks.getEntry(alias, password)

问题不在于您创建密钥的方式,而是您读取密钥的方式。

一年多以来,再也没有遇到过这个问题。


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