java - Android Keystore getEntry() 和 generateKeyPair() 有时会抛出异常

标签 java android security

我的 Android 应用需要加密文件,以便稍后解密和读取。这不应该被应用程序以外的任何人解密,甚至是用户。

以下是我如何进行加密和解密。这在大多数情况下都有效,但有时对于某些用户来说这是失败的。它不是特定于特定手机(Nexus7、三星、摩托罗拉、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() 以首先尝试获取条目,如果引发异常,则生成新的 key 对。

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)
  1. 我做错了什么?
  2. 我该如何解决/解决它?
  3. 这些异常是否表明文件被篡改?
  4. 具有锁屏密码/pin 的用户会发生这种情况吗?
  5. 在生成新对之前,我应该删除该条目吗? (KeyStore.deleteEntry())

我观察到 keystore 在屏幕锁定密码/pin 更改后返回 null。其他一些人似乎也遇到过这个问题 (KeyStore getEntry return null after change password)

最佳答案

我的一个应用程序遇到了 could not generate key in keystore 问题,在使用其中一部受影响的手机深入研究后,我发现某些设备设置了手机的解锁图案/密码/密码与实际解锁 key 存储的密码不同。如果您想仔细检查这是否也是您的问题,您可以使用此处的工作:http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html要获取实际的私有(private)系统 api,公共(public) KeyPairGenerator 对象正在调用并检查其返回码。我不知道为什么 Google 决定将返回码隐藏在 boolean 值后面,但是你有它。

您可以通过调用 startActivity(new Intent("com.android.credentials.UNLOCK")); 手动触发 keystore 的解锁,但这可能并没有太大帮助。从我所看到的手机是否处于这种状态,这是因为某些设备管理员应用程序在后台锁定了 keystore ,因此它可以设置 VPN 或电子邮件凭据。这意味着用户实际上并不知道密码。我仍在寻找一种解决方法(可能会找出设备管理员应用程序如何访问 keystore ,以便我可以通过这种方式解锁它),但至少可以说这是一个棘手的问题。如果我在探索中发现更多信息,我会尝试更新此内容,希望这至少可以为某些人指明正确的方向。

关于java - Android Keystore getEntry() 和 generateKeyPair() 有时会抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23965300/

相关文章:

Java实时改变多个JFrame的不透明度

php - 阻止人们入侵Flash游戏的基于PHP的高分表的最好方法是什么

ios - XCode 项目中的文件安全性

java - 如何在 Eclipse 插件中获取对当前项目的引用?

Java 用递归填充 3D 链表

java - 客户端服务器应用程序不工作

security - 完整性检查 : SSL+ POST vs. 未加密的 GET

android - 数据库测试失败 Robolectric 2.4 + Ubuntu 14 + GradleWrapper 2.4

java - ScrollView 总是滚动到底部

java - EditText OnClick 异常