30

Androidのキーストアから秘密鍵を取得するための次の行があります

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

// generating key pair code omitted

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

OS が Android 5.1.1 から Android 6.0.1 にアップグレードされると、3 行目がjava.security.UnrecoverableKeyException: Failed to obtain information about private key最初の実行でスローされることを除いて、すべて正常に動作します。しかし、その後は再び正常に動作します。私の回避策は、この行を 2 回実行することです。同時に、例外を回避するためのより良い方法があるかどうかも疑問に思っています。

アップデート

例外トレース

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
4

3 に答える 3

13

このエラーがいつ発生し、その理由は?

回答: 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 であるため、エラーは 1 回だけ発生します。

状態チェック コードを以下に示します。

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. キーストア Java クラス

アップデート:

エラーログから、次のことは明らかです

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

これは、ユーザーが LOCK/UNINITIALIZED から UNLOCK しようとしたときに発生する主な問題です。デフォルトでは、タイミングのために 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ます。

解決:

InvalidKeyExceptioncatch 引数からクラスを削除する必要があります。これにより、引き続きチェックすることができますInvalidKeyException。チェック後、問題が目に見えないようにコードをもう一度試す必要がありますが、2回チェックすると問題が解決する場合があります。私はコードをテストしていませんが、以下のようになるはずです:

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
  2. android.security.KeyStoreException: 無効なキー blob
于 2016-04-20T14:52:30.187 に答える
2

実際、Android キーストアはスレッドセーフではありません。私たちもEncryptedSharedPreferencesスレッドセーフではありません。Google はこのドキュメントで明確に伝えています。

注: EncryptedFile クラスと EncryptedSharedPreferences クラスの両方のメソッドは、スレッドセーフではありません。

複数のスレッドが Android キーストアにアクセスしようとすると、例外が発生する可能性があります。上記の例外は、あるスレッドがキーを使用しているときに、別のスレッドがキーを再度取得しようとした場合に発生します。

synchronizedすべての Android キーストア操作をブロックする必要があります。

于 2020-09-06T05:33:16.053 に答える