Question

I am trying to write an application that enables users to exchange their public (e.g. RSA) keys via Bluetooth/NFC. To store and later retrieve the keys, I would like to use Android's KeyChain API.

I have read the online API documentation and some tutorials/examples so far. They all involve importing a keychain from a PKCS12 file which contains a private key and the corresponding public key and certificate. Once this file is imported, an alias-String is returned for subsequent reference. So far, so good.

However, what I want to do is receive someone's public key, store it, get back an alias, store that alias somewhere (e.g. contacts data) and use it to retrieve back the public key when the user wants to encrypt a message to that person. Is that possible? I have very little experience with Public-key cryptography and have the feeling that I have misunderstood the whole purpose of the KeyChain API.

Any help would be much apprechiated! Thanks.

Was it helpful?

Solution

The Android KeyChain API is designed to store SSL certificates and keys: your own keys when installing a PKCS#12 or a trusted root certification authorities certificates. This keys and certificate are then available to all applications.

It depends on the purpose of the application you are developing but you maybe should consider using a KeyStore dedicated to your application to store the keys you received instead of the KeyChain API.

Another limitation of both API (KeyStore and KeyChain) is taht it is not possible to directly store public keys. You need to have a certificate. I suggest you to embedded a self-signed certificate in your application and use this certificate to sign "dummy" certificates containing the public keys the application will receive.

A simplified code snippet with the bouncycastle library to store a public RSA key:

public void storeRSAPublicKey(String alias, BigInteger modulus, BigInteger exponent) 
{
    /** Load the key to generate the certificate */
    KeyStore ks = getApplicationKeyStore();
    KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry)ks.getEntry(MY_PRIVATE_KEY, null);
    X509Certificate issuerCert = (X509Certificate)entry.getCertificate();
    PrivateKey skey = entry.getPrivateKey();

    /** Prepare the certificate template */
    RSAKeyParameters params = new RSAKeyParameters(false, modulus, exponent);
    SubjectPublicKeyInfo pkInfo = SubjectPublicKeyInfoFactory.SubjectPublicKeyInfo(params);
    X500Name issuer = new X500Name(issuerCert.getIssuerX500Principal().getName());
    X500Name subject = new X500Name("CN=alias");
    X509v3CertificateBuilder builder = new X509v3CertificateBuilder(issuer, randomSeriaNumber(), new Date(), dateIn20years(), subject, pkInfo);

    /** Generate the certificate */
    JcaContentSignerBuilder csBuilder = new JcaContentSignerBuilder("SHA256withRSA");
    ContentSigner signer = csBuilder.build(skey);
    X509CertificateHolder holder = builder.build(signer);

    /** Store the certificate in the KeyStore */
    JcaX509CertificateConverter conv = new JcaX509CertificateConverter();
    X509Certificate cert = conv.getCertificate(holder);
    ks.setCertificateEntry(alias, cert);
    pushKeyStoreToPersistentStorage(ks);

Now you can get the certificate with ks.getCertificateEntry(alias);

Note that I omitted some non fundamental code like serial number generation and not-after date computation.

You can create the initial KeyStore with keytool and add it to you app as a resource.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top