Android :: java.security.KeyStoreException: Failed to store private key
Asked Answered
R

2

8

We have generate AndroidKeystore and it's working fine but randomly facing below issue.

After App reinstall its working fine.

java.security.KeyStoreException: Failed to store private key

Below is the code where we are facing the issue

    public boolean generateKeyStore() {
    try {
        Calendar startCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+05:30"));
        Calendar endCal = Calendar.getInstance(TimeZone.getTimeZone("GMT+05:30"));
        endCal.add(Calendar.MINUTE, 15 * 24 * 60); // 15 days

        Date notBefore = startCal.getTime();
        Date notAfter = endCal.getTime();

        KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");
        generator.initialize(2048);
        KeyPair keyPair = generator.generateKeyPair();

        X500Name issuerName = new X500Name("CN=test, OU=test, O=test, L=test, ST=test, C=test, [email protected]");
        X500Name subjectName = new X500Name("CN=test, OU=test, O=test, L=test, ST=test, C=test, [email protected]");
        BigInteger serial = BigInteger.valueOf(Calendar.getInstance().getTimeInMillis());

        X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(issuerName, serial, notBefore, notAfter,
                subjectName, keyPair.getPublic());
        ContentSigner signer = new JcaContentSignerBuilder("SHA1WithRSAEncryption")
                .setProvider(BouncyCastleProvider.PROVIDER_NAME).build(keyPair.getPrivate());
        X509Certificate cert = new JcaX509CertificateConverter().setProvider(
                BouncyCastleProvider.PROVIDER_NAME).getCertificate(builder.build(signer));

        Certificate[] chain = new Certificate[1];
        chain[0] = cert;
        KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
        keyStore.load(null);
        keyStore.setKeyEntry("Test", keyPair.getPrivate(), null, chain); // --> This line raise exception

        return true;
    } catch (Exception e) {
        Log.e("Error", "generateKeyStore", e);
        return false;
    }
}
Reminisce answered 21/8, 2019 at 13:6 Comment(3)
do you know what line raised the exception? the stack trace should tellRye
keyStore.setKeyEntry("Test", keyPair.getPrivate(), null, chain); This line in raise exception. @RyeReminisce
try thread here: devops.datenkollektiv.de/…Lowkey
A
1

Try casting the value to key object

keyStore.setKeyEntry("Test", (Key) keyPair.getPrivate(), null, chain);

also you can use this method which has no password parameter

keyStore.setKeyEntry("Test", (Key) keyPair.getPrivate(), chain);

also try adding a value to password instead of null

String pwd = "password";
keyStore.setKeyEntry("Test", (Key) keyPair.getPrivate(), pwd, chain);

If you still fail on these two trying using encoded keys as the parameter

keyPair.getPrivate().getEncoded() 
Abhenry answered 22/8, 2019 at 5:18 Comment(3)
KeyPair store in AndroidKeystore default path. Password set on raise exception. "entries cannot be protected with passwords".Reminisce
Yes, I have try both solution but password protected not working and type casting in working but its raise randomly exception.Reminisce
@JigarShekh could you please try the updated answerAbhenry
L
0

I guess it is because you have not set all required properties in initilize() for creating key-pair correctly. As an example, you need to specify key purpose.

Following code works just fine, for creating a key-pair in order to encrypt/decrypt data (maybe sing/verify is more suitable for you):

    public boolean createKey() {
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(
                    KeyProperties.KEY_ALGORITHM_RSA,
                    "AndroidKeyStore"
            );

            mKeyStore.load(null);
            KeyGenParameterSpec.Builder builder =
                    new KeyGenParameterSpec.Builder(
                            FINGERPRINT_CIPHER_KEY,
                            KeyProperties.PURPOSE_DECRYPT).
                            setKeySize(2048).
                            setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_OAEP).
                            setDigests(KeyProperties.DIGEST_SHA256);

            keyPairGenerator.initialize(builder.build());
            keyPairGenerator.generateKeyPair();
        } catch (NoSuchAlgorithmException | CertificateException | IOException |
                InvalidAlgorithmParameterException | NoSuchProviderException e) {
            return false;
        }

        return true;
    }

If you need user validation for private key use too, use setUserAuthenticationRequired(true); method on builder too.

If you want to create certificates, I guess it is better to create your key-pair first in keystore. Then create certificate from them easily.

Update:

I saw something similar to what you want to do here.

Lowkey answered 22/8, 2019 at 5:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.