Java.security.UnrecoverableKeyException: Error al obtener información acerca de la clave privada

Tengo las siguientes líneas para obtener la clave privada del almacén de claves en Android

KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); // generating key pair code omitted KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) this.keyStore.getEntry("alias", null); 

Todo funciona bien, excepto que cuando el sistema operativo actualiza desde Android 5.1.1 a Android 6.0.1, la tercera línea lanzará java.security.UnrecoverableKeyException: Failed to obtain information about private key para la primera ejecución. Pero funcionará bien de nuevo después. Ahora mi solución es ejecutar la línea por 2 veces. Al mismo tiempo, también me pregunto si hay mejor manera de evitar la excepción.

Actualizar

El rastro de excepción

 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 

¿Cuándo ocurre este error y por qué?

Respuesta: Al cargar las claves de Android y almacenar la clave pública de Keystore, este error puede ocurrir si el estado está bloqueado o no inicializado.

Error que genera el código de la porción se da a continuación:

 @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 tiene 10 código de respuesta. Son

 // 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 tiene 3 estados. Están DESBLOQUEADOS, LOCKED, UNINITIALIZED

NO_ERROR sólo ocurre cuando el estado se desbloquea. Para su caso de actualización, el estado es LOCKED o UNINITIALIZED por primera vez, por lo que el error se produce sólo una vez.

El código de comprobación de estado se da a continuación:

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

Enlace de recursos:

  1. AndroidKeyStoreProvider java class
  2. Clase de java de KeyStore

ACTUALIZAR:

De su registro de errores, ahora está claro que

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

Este es el problema principal que se produce cuando el usuario intenta DESBLOQUEAR desde LOCK / UNINITIALIZED. Por defecto se define como 30 segundos para la temporización. Este problema es su problema de implementación relacionada con la 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; 

Para el cifrado / descifrado algunos datos con la clave generada sólo funcionan si el usuario acaba de autenticarse a través de las credenciales del dispositivo. El error se produce desde

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

El error real se produce desde aquí. Su error se genera a partir de InvalidKeyException .

Solución:

InvalidKeyException quitar la clase InvalidKeyException del argumento catch. Esto todavía le permitirá comprobar InvalidKeyException . Después de comprobar que tiene que intentar por segunda vez con el código para que el problema no se muestra en el ojo, pero haciendo 2 veces comprobar que puede resolver su problema. No he probado el código pero debería ser como a continuación:

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

Enlace de recursos:

  1. MainActivity.java
  2. Android.security.KeyStoreException: Bloc de clave no válido
FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.