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

2023-12-27

我的 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() 以首先尝试获取条目,如果引发异常,则生成新的密钥对。

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())

我观察到,屏幕锁定密码/PIN 更改后,密钥库返回 null。其他一些人似乎也遇到过这个问题(更改密码后 KeyStore getEntry 返回 null https://stackoverflow.com/questions/22618171/keystore-getentry-return-null-after-change-password)


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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Android Keystore getEntry() 和generateKeyPair() 有时会抛出异常 的相关文章

随机推荐