Подтвердить что ты не робот

Android Keystore getEntry() и generateKeyPair() throw Исключения иногда

Моему Android-приложению нужно зашифровать файл, чтобы он мог расшифровать и прочитать его позже. Это не должно быть расшифровывается любым другим, кроме приложения, даже пользователем.

Вот как я делаю шифрование и дешифрование. Это работает большую часть времени, но несколько раз для некоторых пользователей это не работает. Он не специфичен для конкретного телефона (Nexus7, Samsung, Motorola, HTC - все типы сообщают об этой проблеме), но не все пользователи испытывают это. Только некоторые пользователи иногда.

Вот соответствующий код:

encrypt() {
   KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
   final KeyStore.PrivateKeyEntry entry;
   if (!ks.containsAlias(CERT_ALIAS)) {
       Calendar cal = Calendar.getInstance();
       Date now = cal.getTime();
       cal.add(Calendar.YEAR, 50);
       Date end = cal.getTime();
       KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
       kpg.initialize(new KeyPairGeneratorSpec.Builder(getApplicationContext())
              .setAlias(CERT_ALIAS)
              .setStartDate(now)
              .setEndDate(end)
              .setSerialNumber(BigInteger.valueOf(1))
              .setSubject(new X500Principal("CN=" + CERT_ALIAS))
              .build());
       KeyPair kp = kpg.generateKeyPair();
   }
   entry = (KeyStore.PrivateKeyEntry) ks.getEntry(
                     CERT_ALIAS, null);
   pub = entry.getCertificate().getPublicKey();
   // use the pub key to encrypt
}
decrypt() {
    KeyStore ks = KeyStore.getInstance("AndroidKeyStore");
    ks.load(null);

    final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) ks.getEntry(
            CERT_ALIAS, null);
    PrivateKey key1 = entry.getPrivateKey();
    // use the private key decrypt
}

Этот код иногда бросает

java.lang.RuntimeException: error:0D07207B:asn1 encoding routines:ASN1_get_object:header too long
at com.android.org.conscrypt.NativeCrypto.ENGINE_load_private_key(Native Method)
at com.android.org.conscrypt.OpenSSLEngine.getPrivateKeyById(OpenSSLEngine.java:66)
at android.security.AndroidKeyStore.engineGetKey(AndroidKeyStore.java:86)
at java.security.KeyStoreSpi.engineGetEntry(KeyStoreSpi.java:372)
at java.security.KeyStore.getEntry(KeyStore.java:644)

Итак, я модифицировал encrypt(), чтобы сначала попытаться получить запись, и если она вызывает исключение, создайте новую пару ключей.

final KeyStore.PrivateKeyEntry entry = null;
if (ks.containsAlias(CERT_ALIAS)) {
    try {
        entry = (KeyStore.PrivateKeyEntry) ks.getEntry(
                      CERT_ALIAS, null);
    } catch (Exception e) {
    }
}
if (entry == null) {
    //generate new key pair
}

Но даже это иногда не срабатывает со следующим исключением.

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)
  • Что я делаю неправильно?
  • Как мне его исправить/обойти?
  • Указывает ли эти исключения, что файлы подделываются?
  • Это случается для пользователей с паролем/штифтом для блокировки экрана?
  • Прежде чем я создам новую пару, должен ли я удалить запись? (KeyStore.deleteEntry())

Я заметил, что хранилище ключей возвращает значение null после изменения пароля/смены блокировки. Некоторые другие также, похоже, столкнулись с этой проблемой (KeyStore getEntry возвращает null после смены пароля)

4b9b3361

Ответ 1

Я столкнулся с проблемой could not generate key in keystore с одним из моих приложений, и после глубокого углубления в него одним из затронутых телефонов я обнаружил, что на некоторых устройствах он настроил, что шаблон разблокировки телефона/пропуск/вывод отличается от пароль, который фактически разблокирует хранилище ключей. Если вы хотите дважды проверить, что это ваша проблема, вы можете использовать эту работу здесь: http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html, чтобы получить фактическую частную систему api публичные объекты KeyPairGenerator вызывают и проверяют код возврата на нем. Я не уверен, почему Google решил скрыть код возврата за булевым, но там у вас есть.

Вы можете вызвать разблокировку хранилища ключей вручную, вызвав startActivity(new Intent("com.android.credentials.UNLOCK"));, но это может сильно не помочь. Из того, что я видел, если телефон находится в этом состоянии, это связано с тем, что приложение Device Administrator заблокировало хранилище ключей в фоновом режиме, чтобы настроить учетные данные VPN или электронной почты. Это означает, что пользователь фактически не знает пароль. Я все еще ищу обходное решение (возможно, узнайте, как приложения Device Administrator получают доступ к хранилищу ключей, чтобы я мог разблокировать его таким образом), но это, по меньшей мере, волосатая проблема. Я попытаюсь обновить это, если узнаю больше в моих исследованиях, надеюсь, это, по крайней мере, указывает на некоторых людей в правильном направлении.