使用Android的KeyChain API来交换公钥

时间:2013-12-20 12:52:31

标签: android openssl rsa keychain pkcs#12

我正在尝试编写一个应用程序,使用户能够通过蓝牙/ NFC交换他们的公共(例如RSA)密钥。要存储并稍后检索密钥,我想使用Android's KeyChain API.

到目前为止,我已阅读了在线API文档和一些教程/示例。它们都涉及从PKCS12文件导入密钥链,该文件包含私钥以及相应的公钥和证书。导入此文件后,将返回alias-String以供后续引用。到目前为止,非常好。

但是,我想要做的是接收某人的公钥,存储它,获取别名,在别处存储别名(例如联系人数据)并在用户想要加密消息时使用它来检索公钥那个人那可能吗?我对公钥加密的经验很少,并且觉得我误解了KeyChain API的整个目的。

任何帮助都会受到很多关注!感谢。

1 个答案:

答案 0 :(得分:1)

Android KeyChain API旨在存储SSL证书和密钥:安装PKCS#12或受信任的根证书颁发机构证书时自己的密钥。然后,此密钥和证书可供所有应用程序使用。

这取决于您正在开发的应用程序的目的,但您可能应该考虑使用专用于您的应用程序的KeyStore来存储您收到的密钥而不是KeyChain API。

API(KeyStore和KeyChain)的另一个限制是无法直接存储公钥。你需要有证书。我建议您在应用程序中嵌入自签名证书,并使用此证书签署包含应用程序将收到的公钥的“虚拟”证书。

带有bouncycastle库的简化代码片段,用于存储公共RSA密钥:

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);

现在您可以使用ks.getCertificateEntry(alias);

获取证书

请注意,我省略了一些非基本代码,如序列号生成和非日期计算。

您可以使用keytool创建初始KeyStore,并将其作为资源添加到您的应用中。