当前位置: 首页 > 面试题库 >

java.security.UnrecoverableKeyException:无法获取有关私钥的信息

穆建元
2023-03-14
问题内容

我有以下几行代码可从Android上的密钥存储中获取私钥

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

// generating key pair code omitted

KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) this.keyStore.getEntry("alias", null);

一切正常,除了当操作系统从Android 5.1.1升级到Android
6.0.1时,第3行将抛出java.security.UnrecoverableKeyException: Failed to obtain information about private key第一个执行代码。但是之后它将再次正常运行。现在我的解决方法是执行该行两次。同时,我也想知道是否有更好的方法来避免该异常。

更新资料

异常跟踪

W/System.err﹕ java.security.UnrecoverableKeyException: Failed to obtain information about private key
W/System.err﹕ at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStorePublicKeyFromKeystore(AndroidKeyStoreProvider.java:217)
W/System.err﹕ at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(AndroidKeyStoreProvider.java:253)
W/System.err﹕ at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(AndroidKeyStoreProvider.java:263)
W/System.err﹕ at android.security.keystore.AndroidKeyStoreSpi.engineGetKey(AndroidKeyStoreSpi.java:93)
W/System.err﹕ at java.security.KeyStoreSpi.engineGetEntry(KeyStoreSpi.java:372)
W/System.err﹕ at java.security.KeyStore.getEntry(KeyStore.java:645)
W/System.err﹕ at com.example.keystoretest.MainActivity.onCreate(MainActivity.java:113)
W/System.err﹕ at android.app.Activity.performCreate(Activity.java:6251)
W/System.err﹕ at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1107)
W/System.err﹕ at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2369)
W/System.err﹕ at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2476)
W/System.err﹕ at android.app.ActivityThread.-wrap11(ActivityThread.java)
W/System.err﹕ at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1344)
W/System.err﹕ at android.os.Handler.dispatchMessage(Handler.java:102)
W/System.err﹕ at android.os.Looper.loop(Looper.java:148)
W/System.err﹕ at android.app.ActivityThread.main(ActivityThread.java:5417)
W/System.err﹕ at java.lang.reflect.Method.invoke(Native Method)
W/System.err﹕ at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
W/System.err﹕ at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
W/System.err﹕ Caused by: android.security.KeyStoreException: Invalid key blob
W/System.err﹕ at android.security.KeyStore.getKeyStoreException(KeyStore.java:632)
W/System.err﹕ at android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStorePublicKeyFromKeystore(AndroidKeyStoreProvider.java:218)
W/System.err﹕ ... 18 more

问题答案:

什么时候发生此错误,为什么?

回答: 加载Android密钥并从密钥库存储公共密钥时,如果状态为锁定或未初始化,则可能会发生此错误。

错误生成部分代码如下:

@NonNull
    public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
            @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
            throws UnrecoverableKeyException {
        KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
        int errorCode = keyStore.getKeyCharacteristics(privateKeyAlias, null,
                null, keyCharacteristics);
        if (errorCode != KeyStore.NO_ERROR) {
            throw (UnrecoverableKeyException) new UnrecoverableKeyException(
                    "Failed to obtain information about private key")
                    .initCause(KeyStore.getKeyStoreException(errorCode)); // this exception is generated
        }
        ......
        ......
        ......
    }

KeyStore有10个响应代码。他们是

// ResponseCodes
NO_ERROR = 1;
LOCKED = 2;
UNINITIALIZED = 3;
SYSTEM_ERROR = 4;
PROTOCOL_ERROR = 5;
PERMISSION_DENIED = 6;
KEY_NOT_FOUND = 7;
VALUE_CORRUPTED = 8;
UNDEFINED_ACTION = 9;
WRONG_PASSWORD = 10;

KeyStore具有3个状态。它们是解锁的,锁定的,未初始化的

NO_ERROR仅在状态为UNLOCKED时发生。对于您的升级情况,状态第一次为LOCKED或UNINITIALIZED,因此错误仅发生一次。

状态检查代码如下:

public State state() {
    execute('t');
    switch (mError) {
    case NO_ERROR:
        return State.UNLOCKED;
    case LOCKED:
        return State.LOCKED;
    case UNINITIALIZED:
        return State.UNINITIALIZED;
    default:
        throw new AssertionError(mError);
    }
}

资源链接:

  1. AndroidKeyStoreProvider Java类
  2. KeyStore Java类

更新:

从您的错误日志中,现在很清楚

W/System.err﹕ Caused by: android.security.KeyStoreException: Invalid key blob

这是当用户尝试从LOCK / UNINITIALIZED解锁时引起的主要问题。默认情况下,它被定义为30秒计时。 这个问题是与API相关的实现问题。

/**
 * If the user has unlocked the device Within the last this number of seconds,
 * it can be considered as an authenticator.
 */
private static final int AUTHENTICATION_DURATION_SECONDS = 30;

对于加密/解密,仅当用户刚刚通过设备凭据进行身份验证时,带有生成的密钥的某些数据才有效。错误发生于

// Try encrypting something, it will only work if the user authenticated within
// the last AUTHENTICATION_DURATION_SECONDS seconds.
cipher.init(Cipher.ENCRYPT_MODE, secretKey); // error is generated from here.

从这里抛出实际错误。您的错误是由产生的InvalidKeyException

解:

您必须InvalidKeyException从catch参数中删除该类。这样仍然可以检查InvalidKeyException。检查后,您必须再次尝试使用代码,以便该问题不会立即出现在眼睛中,但进行两次检查可能可以解决您的问题。我尚未测试代码,但应如下所示:

try {
....
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) this.keyStore.getEntry("alias", null);
....
} catch (final Exception e) {
    e.printStackTrace();
    if (e instanceof InvalidKeyException) { // bypass InvalidKeyException
        .......
        // You can again call the method and make a counter for deadlock situation or implement your own code according to your situation
        if (retry) {
            keyStore.deleteEntry(keyName);
            return getCypher(keyName, false);
        } else {
            throw e;
        }
    }
}

资源链接:

  1. MainActivity.java


 类似资料:
  • 问题内容: 我记得很久以前使用OpenSSL进行过此操作,但是我想知道是否可行以及如何进行,我从未在Java上使用过密码学。 问题答案: 您不能直接从另一个生成任何一个密钥。从数学上讲这是不可能的。如果你有一个含有密钥团 两者 的公钥和私钥,你可以提取它们的相对轻松的任何一个。 编辑,2017年: 多年之后,人们对加密技术有了更深入的了解,现在我很清楚这个答案并不正确。 引用维基百科: 公用密钥由

  • 问题内容: 我有一个.key文件,当我这样做时 我懂了 我也有一个.cer文件,当我这样做时 我懂了 但是,如果按照的指示运行,则应执行以下命令: 我懂了 但这似乎不适用于该键,因为当我运行时 我懂了 如何获得私钥及其证书? 问题答案: 看来您有格式为的证书,而不是。这就是为什么当您提供命令行参数(告诉openssl期望什么样的输入格式)时它可以正常工作的原因。 您的私钥可能使用了相同的编码。看起

  • 我有一本书。密钥文件,当我这样做时 我得到 我也有一个朋友。cer文件,当我这样做时 我明白了 但是如果像这里指出的那样,我运行这样的命令: 我得到 但这似乎对钥匙不起作用,因为当我跑的时候

  • a.从存储区提取现有证书密钥: b.从导出的证书中提取私钥: 没有证书与私钥匹配 我错过了什么?为什么我的最后一个命令不合法? 我计划执行“keytool-importkeystore”文件。p12(应该在最后一步中生成)来替换“keystore”中的“一个”privateKeyEntry。正如在如何导入Java keystore中现有的x509证书和私钥以便在SSL中使用中所建议的?。基本上,我

  • 我有一个私钥文件(PEM BASE64编码)。我想用它来解密一些其他数据。使用Java我试着读取文件并解码其中的BASE64编码数据。这是我尝试的代码片段.... 我得到以下错误 类似的问题已经贴在这里,但那些对我没有用。几乎所有的人都建议使用Bouncycastle provider,而Bouncycastle provider并不愿意使用FIPS兼容的provider,并且不确定BC prov

  • 问题内容: 我有一个私钥文件(PEM BASE64编码)。我想在其他地方使用它解密其他数据。使用Java,我尝试读取文件并解码其中的BASE64编码数据。这是我尝试的代码段。 import java.io.; import java.nio.ByteBuffer; import java.security. ; import java.security.spec.PKCS8EncodedKeySp