studio debug crear java android runtime-error android-keystore

java - debug - Android Keystore Error "no pudo generar la clave en el almacén de claves"



keystore windows (4)

Me da un error al tratar de generar una clave para ciertos dispositivos. Puedo reproducir el error en un Samsung Galaxy Note ejecutando 4.4.2.

java.lang.IllegalStateException: could not generate key in keystore at android.security.AndroidKeyPairGenerator.generateKeyPair(AndroidKeyPairGenerator.java:100) at java.security.KeyPairGenerator$KeyPairGeneratorImpl.generateKeyPair(KeyPairGenerator.java:275) at com.eric.demo.MainActivity.generateKeyPair(MainActivity.java:65) at com.eric.demo.MainActivity.onClickButton(MainActivity.java:43) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at android.view.View$1.onClick(View.java:3964) at android.view.View.performClick(View.java:4640) at android.view.View$PerformClick.run(View.java:19421) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5476) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1268) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1084) at de.robv.android.xposed.XposedBridge.main(XposedBridge.java:132) at dalvik.system.NativeStart.main(Native Method)

Creé una pequeña aplicación para generar solo una clave copiando el código línea por línea desde la página del desarrollador de Android https://developer.android.com/training/articles/keystore.html en "Generando una nueva clave privada".

public void onClickButton (View view) { try { generateKeyPair(this, "test3"); } catch (Exception e){ Log.wtf("exception", e); } } private void generateKeyPair(Context context, String alias) throws Exception { Calendar cal = Calendar.getInstance(); Date now = cal.getTime(); cal.add(Calendar.YEAR, 1); Date end = cal.getTime(); KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); kpg.initialize(new KeyPairGeneratorSpec.Builder(getApplicationContext()) .setAlias(alias) .setStartDate(now) .setEndDate(end) .setSerialNumber(BigInteger.valueOf(1)) .setSubject(new X500Principal("CN=test3")) .build()); KeyPair kp = kpg.generateKeyPair(); }

El error parece ocurrir en kpg.generateKeyPair (), dentro de AndroidKeyPairGenerator.java:

if (!mKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF, keyType, mSpec.getKeySize(), mSpec.getFlags(), args)) { throw new IllegalStateException("could not generate key in keystore"); }

y en KeyStore.java:

public boolean generate(String key, int uid, int keyType, int keySize, int flags, byte[][] args) { try { return mBinder.generate(key, uid, keyType, keySize, flags, args) == NO_ERROR; } catch (RemoteException e) { Log.w(TAG, "Cannot connect to keystore", e); return false; } }

La llamada a mBinder.generate () parece devolver 2, lo que significa que el almacén de claves está bloqueado.

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

El error puede estar relacionado de alguna manera con este problema con el almacén de claves https://code.google.com/p/android/issues/detail?id=177459&q=could%20not%20generate%20key%20in%20keystore&colspec=ID%20Type%20Status%20Owner%20Summary%20Stars

Algunas cosas que he probado individualmente y combinaciones de lo siguiente:
1. Configuración del cifrado requerido. El resultado es otro error: "Android keystore debe estar en estado inicializado y desbloqueado si se requiere cifrado"
2. Configurar una pantalla de bloqueo (patrón, PIN, NINGUNO, contraseña, deslizar). Mismo comportamiento
3. Programar programáticamente para desbloquear o restablecer el almacenamiento de credenciales con startActivity(new Intent("com.android.credentials.UNLOCK")); o startActivity(new Intent("com.android.credentials.RESET")); Intentar desbloquear muestra un mensaje de "ingresar contraseña para el almacenamiento de credenciales", en el que no funciona ninguna contraseña razonable, e incluso borrar las credenciales no ayuda.


Creo que esta es la dirección correcta: haga clic con el botón derecho en Proyecto> Herramientas de Android> Exportar paquete de aplicaciones firmadas Aparece el asistente de Exportar aplicación de Android. Seleccione el proyecto que quiero exportar, haga clic en Siguiente. Aparece la pantalla Selección del almacén de claves.


Si bien no conozco la respuesta completa, puedo ayudarlo a continuar su búsqueda. La implementación del enlazador en el otro lado de mBinder es el almacén de claves nativo . Si recuerdo bien, su comportamiento es: 1) admitir operaciones clave a nivel de software, o 2) delegar en una biblioteca de keymaster proporcionada por OEM que (presumiblemente) se conecta con el almacén de claves respaldado por hardware del OEM. Más información sobre esto here , here y here .

Nota: Renunciaré a la política habitual de SO de incluir el contenido del enlace externo en la respuesta, ya que lo vincularé a tres artículos que son todos> 1 página y parece un poco ridículo publicar una respuesta de 6 páginas; )


Si su código es correcto, recuerde que debe configurar un PIN / PW / Fingerprint (Desbloqueo seguro) para su dispositivo para que el almacén de claves comience a funcionar. Un simple deslizamiento dará ese error si intenta generar pares de claves.


public class EncryptionApi18AndAbove{ private Context context; private KeyStore keyStore; private static String alias = "alias"; public EncryptionApi18AndAbove(Context context) { this.context = context; try { keyStore = KeyStore.getInstance("AndroidKeyStore"); keyStore.load(null); } catch (Exception e) { // bla bla } } private String createNewKeys(String alias, Context context) { try { if (!keyStore.containsAlias(alias)) { Calendar start = Calendar.getInstance(); Calendar end = Calendar.getInstance(); end.add(Calendar.YEAR, 1); KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context) .setAlias(alias) .setSubject(new X500Principal("CN=Sample Name, O=Android Authority")) .setSerialNumber(BigInteger.ONE) .setStartDate(start.getTime()) .setEndDate(end.getTime()) .build(); KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore"); generator.initialize(spec); generator.initialize(spec); generator.generateKeyPair(); } } catch (Exception e) { //bla bla } return alias; } @Override public String encrypt(String text) { if (text == null || text.length() == 0) { return text; } try { KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(createNewKeys(alias, context), null); PublicKey publicKey = privateKeyEntry.getCertificate().getPublicKey(); Cipher inCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); inCipher.init(Cipher.ENCRYPT_MODE, publicKey); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); CipherOutputStream cipherOutputStream = new CipherOutputStream( outputStream, inCipher); cipherOutputStream.write(text.getBytes("UTF-8")); cipherOutputStream.close(); return Base64.encodeToString(outputStream.toByteArray(), Base64.DEFAULT); } catch (Exception e) { //bla bla } return text; } @Override public String decrypt(String text) { if (text == null || text.length() == 0) { return text; } try { KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(createNewKeys(alias, context), null); PrivateKey privateKey = privateKeyEntry.getPrivateKey(); Cipher output = Cipher.getInstance("RSA/ECB/PKCS1Padding"); output.init(Cipher.DECRYPT_MODE, privateKey); CipherInputStream cipherInputStream = new CipherInputStream( new ByteArrayInputStream(Base64.decode(text, Base64.DEFAULT)), output); ArrayList<Byte> values = new ArrayList<>(); int nextByte; while ((nextByte = cipherInputStream.read()) != -1) { values.add((byte) nextByte); } byte[] bytes = new byte[values.size()]; for (int i = 0; i < bytes.length; i++) { bytes[i] = values.get(i).byteValue(); } return new String(bytes, 0, bytes.length, "UTF-8"); } catch (Exception e) { // bla bla } return text; } }

Puedes usar esta clase Este es el mínimo SDK 18 de trabajo. Puede crear la clave de Android Keystore, descifrar y encriptar texto simple.