My Android app need to encrypt a file so that it can decrypt and read it later. This should not be decrypt-able by anybody else other than the app, even user.
Following is how I am doing the encryption and decryption. This works most of the time, but some times for some users this is failing. It is not specific to a particular handset (Nexus7, Samsung, Motorola, HTC -- all types are reporting this issue), but not all users are experiencing it. Only some users occasionally.
Here is the relevant code:
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
}
This code sometimes throws
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)
So I modified encrypt() to first try to get the entry and if it raises exception, generate new key pair.
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
}
But even this is failing sometimes with the following exception.
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)
- What am I doing wrong?
- How do I fix it/work around it?
- Does these exceptions indicate that the files are being tampered with?
- Does this happen for users with screenlock password/pin?
- Before I generate new pair, should I delete the entry? (KeyStore.deleteEntry())
I observed that the keystore returns null after screenlock password/pin change. Some others also seem to have experienced this issue (KeyStore getEntry return null after change password)