My Android app need to encrypt app secrets 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 (for API > 17)
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 to 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)
1. What am I doing wrong?
2. How do I fix it/work around it?
3. Before I generate new pair, should I delete the entry?
(KeyStore.deleteEntry())
4. Does this indicate the files (encrypted, wrapped secret key) are
tampered?
5. Does this happen on rooted devices or encrypted devices or when user
changes lock screen PIN/ password?
-----------
I tested the following
- Enable Screen lock password
- Change it to PIN
Then
final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)
ks.getEntry(
CERT_ALIAS, null);
getEntry() is returning null. But, not the above exceptions.
It looks like the key store entry gets deleted when user changes screen
lock password or PIN. Since this is application secret and not user
related, I wonder why?
Is there a way to not get affected by user security settings?
I posted this on Stack Overflow, but thought this might be better place
hence posting here.
http://stackoverflow.com/questions/23965300/android-keystore-getentry-and-generatekeypair-throw-exceptions-sometimes
--
You received this message because you are subscribed to the Google Groups
"Android Security Discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/android-security-discuss.
For more options, visit https://groups.google.com/d/optout.