web-dev-qa-db-fra.com

java.security.UnrecoverableKeyException: impossible d'obtenir des informations sur la clé privée

J'ai les lignes suivantes pour obtenir la clé privée du magasin de clés sur Android

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

// generating key pair code omitted

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

Tout fonctionne bien sauf que lorsque le système d'exploitation passe de Android 5.1.1 à Android 6.0.1, la 3ème ligne lancera Java.security.UnrecoverableKeyException: Failed to obtain information about private key pour la toute première exécution. Mais cela fonctionnera bien à nouveau par la suite. Maintenant, ma solution consiste à exécuter la ligne 2 fois. En même temps, je me demande également s'il n'y a pas de meilleur moyen d'éviter l'exception.

Mettre à jour

La trace d'exception

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
24
Dino Tw

Quand cette erreur se produit et pourquoi?

Rép: Lors du chargement des clés Android et du stockage de la clé publique à partir du magasin de clés, cette erreur peut se produire si l'état est verrouillé ou non initialisé.

Une erreur lors de la génération du code de portion est indiquée ci-dessous:

@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 a 10 codes de réponse. Elles sont

// 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 a 3 états. Ils sont déverrouillés, verrouillés, non initialisés

NO_ERROR ne se produit que lorsque l'état est déverrouillé. Pour votre cas de mise à niveau, l'état est VERROUILLÉ ou NON INITIALISÉ pour la première fois, donc l'erreur ne s'est produite qu'une seule fois.

Le code de vérification d'état est donné ci-dessous:

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);
    }
}

Lien de ressource:

  1. AndroidKeyStoreProvider Java
  2. KeyStore Java

METTRE À JOUR:

D'après votre journal des erreurs, il est maintenant clair que

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

c'est le principal problème qui se produit lorsque l'utilisateur essaie de déverrouiller à partir de LOCK/UNINITIALIZED. Il est défini par défaut comme 30 secondes pour le chronométrage. Ce problème est un problème d'implémentation lié à l'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;

Pour le chiffrement/déchiffrement, certaines données avec la clé générée ne fonctionnent que si l'utilisateur vient de s'authentifier via les informations d'identification de l'appareil. L'erreur se produit à partir de

// 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.

Une erreur réelle est lancée à partir d'ici. Votre erreur est générée à partir de InvalidKeyException.

Solution:

Vous devez supprimer la classe InvalidKeyException de l'argument catch. Cela vous permettra toujours de vérifier InvalidKeyException. Après avoir vérifié, vous devez essayer pour la deuxième fois avec du code afin que le problème ne soit pas visible dans les yeux, mais une vérification 2 fois peut résoudre votre problème. Je n'ai pas testé le code mais devrait être comme ci-dessous:

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;
        }
    }
}

Lien de ressource:

  1. MainActivity.Java
  2. Android.security.KeyStoreException: blob de clé non valide
10
SkyWalker