Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android KeyStore - keys not always persisted

In my app we are using RSA key, that the app generate (using android key store) on the first launch. From unknown reason, the app failed to retrieved the key from the key store on some of the devices. I've checked the logs, and I could not find a correlation between this bug to a specific OS version or to a specific device model. Also, I know for sure the app tried to read it only after the key created. So - my question is that: As far as I know, android key store should be persistent. What can cause such a bug?

Bellow are relevant code samples.

Key generation:

try {
        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", keyStore.getProvider());

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M){
            KeyGenParameterSpec spec;
            spec = new KeyGenParameterSpec.Builder(alias, KeyProperties.PURPOSE_DECRYPT | KeyProperties.PURPOSE_ENCRYPT| KeyProperties.PURPOSE_SIGN| KeyProperties.PURPOSE_VERIFY)
                    .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA512)
                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)
                    .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1)
                    .setKeySize(2048)
                    .build();

            generator.initialize(spec);
        } else {
            Calendar start = new GregorianCalendar();
            Calendar end = new GregorianCalendar();
            end.add(Calendar.YEAR, 500);

            KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
                    .setAlias(alias)
                    .setSubject(new X500Principal("CN="+ subject))
                    .setSerialNumber(BigInteger.valueOf(new Random().nextInt(Integer.MAX_VALUE)))
                    .setStartDate(start.getTime())
                    .setEndDate(end.getTime())
                    .setKeySize(2048)
                    .build();

            generator.initialize(spec);
        }
        return generator.generateKeyPair();
    } catch (Exception e) {
        logger.warn("Failed to create private key in store", e);
        return null;
    }

The keystore itself intialized using the following code:

KeyStore androidKeyStore = KeyStore.getInstance("AndroidKeyStore");
            androidKeyStore.load(null);
            return androidKeyStore;

And we use the following code to retrieve the key, the bug is that on some devices the keystore returns null:

        try {
        Key key = keyStore.getKey(alias, null);

        if (key == null){
            logger.warn("Key not found in key store");
            return null;
        }

        if (key instanceof PrivateKey) {
            // Get certificate of public key
            Certificate cert = keyStore.getCertificate(alias);

            // Get public key
            PublicKey publicKey = cert.getPublicKey();

            // Return a key pair
            return new KeyPair(publicKey, (PrivateKey) key);
        } else {
            logger.warn("Key found, but not from current type. type found: " + key.getClass().getSimpleName());
        }
        return null;
    }catch (Exception e){
        logger.warn("Failed to get private key in store", e);
        return null;
    }

Thanks, Omer

like image 584
Omer Levi Hevroni Avatar asked Oct 31 '22 01:10

Omer Levi Hevroni


1 Answers

Just in case someone will run into the same problem: I've found out that Azure Active Directory library for android suffer from similar issue, and from reading the code I've saw they linked to two issues that are similar to this problem and to another issue we have. Because of that I am planing to use keystore based on p12 file, stored in the app private storage.

like image 90
Omer Levi Hevroni Avatar answered Nov 15 '22 07:11

Omer Levi Hevroni