我的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)
- 我做错了什么?
- 我如何修复它/围绕它工作?
- 这些异常是否表明文件被篡改了?
- 这是否发生在用户的屏幕锁密码/pin?
- 在生成新的配对之前,我应该删除条目吗?(KeyStore.deleteEntry ())
我观察到在屏幕锁密码/pin更改后密钥存储库返回null。其他一些似乎也遇到了这个问题(KeyStore getEntry在更改密码后返回null)
我在我的一个应用程序中遇到了could not generate key in keystore
问题,在用其中一个受影响的手机深入研究之后,我发现一些设备设置了手机的解锁模式/通行证/pin与实际解锁密钥存储的密码不同。如果你想再次检查这是否是你的问题,你可以使用这里的工作:http://nelenkov.blogspot.com/2012/05/storing-application-secrets-in-androids.html获取公共KeyPairGenerator对象正在调用的实际私有系统api,并检查它的返回代码。我不知道为什么谷歌决定隐藏返回代码后面的布尔值,但你有它。
您可以通过调用startActivity(new Intent("com.android.credentials.UNLOCK"));
手动触发密钥存储库的解锁,但这可能没有太大帮助。从我所看到的情况来看,如果手机处于这种状态,那是因为某些设备管理员应用程序在后台锁定了密钥库,因此它可以设置VPN或电子邮件凭据。这意味着用户实际上并不知道密码。我仍在寻找一种解决方法(可能找出设备管理员应用程序如何访问密钥库,以便我可以通过这种方式解锁它),但至少可以说这是一个棘手的问题。如果我在探索中发现了更多,我会尝试更新这篇文章,希望这至少能给一些人指明正确的方向。