在Android上是否可以将私钥和证书添加到KeyChain而不使用P12文件?

huangapple go评论61阅读模式
英文:

Is it possible to add a Private Key + Certificate to the KeyChain on Android without a P12?

问题

以下代码允许我将PKCS12文件添加到KeyChain,效果非常好:

val pkcs12Bytes = pkcs12Location.readBytes()
val installIntent = KeyChain.createInstallIntent()
installIntent.putExtra(KeyChain.EXTRA_PKCS12, pkcs12Bytes)
startActivity(installIntent)

然而,出于安全原因,我希望在不将P12文件存储在设备上的情况下将私钥和证书添加到KeyChain。私钥在通过keyGen.generateKeyPair()创建后存储在内存中。

这是在使用P12实现时我收到的弹出窗口(请注意“one user key”):

在Android上是否可以将私钥和证书添加到KeyChain而不使用P12文件?

到目前为止,我已经成功使用以下代码将证书添加到KeyChain

val installIntent = KeyChain.createInstallIntent()
installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, x509Certificate)
startActivity(installIntent)

但是我无法在文档中找到一种方法来包含私钥。在Android上是否有可能在不使用P12的情况下将私钥和证书添加到Keychain?

这是在使用证书实现时我收到的弹出窗口(请注意仅有证书):

在Android上是否可以将私钥和证书添加到KeyChain而不使用P12文件?

英文:

The following code allows me to add a PKCS12 file to the KeyChain which works great:

val pkcs12Bytes = pkcs12Location.readBytes()
val installIntent = KeyChain.createInstallIntent()
installIntent.putExtra(KeyChain.EXTRA_PKCS12, pkcs12Bytes)
startActivity(installIntent)

However, for security reasons, I wish to add a Private Key and Certificate to the KeyChain without ever storing a P12 on the device. The Private Key is stored in memory after being created by keyGen.generateKeyPair().

This is the popup that I get when using the P12 implementation (notice "one user key"):

在Android上是否可以将私钥和证书添加到KeyChain而不使用P12文件?


So far I've been able to add a certificate to the KeyChain with this code

val installIntent = KeyChain.createInstallIntent()
installIntent.putExtra(KeyChain.EXTRA_CERTIFICATE, x509Certificate)
startActivity(installIntent)

but I can't find a way to include the Private Key in the documentation. Is it possible to add a Private Key + Certificate to the Keychain on Android without a P12?

This is the popup that I get when using the Certificate implementation (notice only a certificate):

在Android上是否可以将私钥和证书添加到KeyChain而不使用P12文件?

答案1

得分: 1

在创意发挥之后,答案是 有点

似乎无法完全绕过 KeyChain.EXTRA_PKCS12 方法,但我找到了一种方法将 P12 存储在内存中,从而不会存储在 Android 文件系统中。这种方式比将其存储在文件系统上更安全,但仍然不像如果我们能够直接将私钥和证书添加到 KeyChain 中那样安全。

这是我用来在内存中创建 PKCS12 而不是在文件系统上创建的方法:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public static byte[] createPKCS12InMemory(byte[] x509AsPEM, PrivateKey privKey, String pkcs12Password) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
    InputStream stream = new ByteArrayInputStream(x509AsPEM);
    CertificateFactory fact = CertificateFactory.getInstance("X.509");
    X509Certificate cert = (X509Certificate) fact.generateCertificate(stream);
    KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
    pkcs12.load(null, null);
    pkcs12.setKeyEntry("device_certificate", privKey, pkcs12Password.toCharArray(), new Certificate[] {cert});
    ByteArrayOutputStream p12 = new ByteArrayOutputStream();
    pkcs12.store(p12, pkcs12Password.toCharArray());
    return p12.toByteArray();
}

一旦你将 PKCS12 作为字节存储在内存中,你可以直接将其传递给 installIntent,从而有效地不在文件系统上存储 p12!

英文:

After getting creative, the answer is kind of.

It doesn't seem to be possible to completely bypass the KeyChain.EXTRA_PKCS12 method, but I did find a way to store the P12 in memory so that it's never stored on the Android's file system. This way is more secure than storing it on the file system, but still not as secure as if we were able to add the private key and certificate directly into the KeyChain.

This is the method that I used to create the PKCS12 in memory instead of on the file system:

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

public static byte[] createPKCS12InMemory(byte[] x509AsPEM, PrivateKey privKey, String pkcs12Password) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
    InputStream stream = new ByteArrayInputStream(x509AsPEM);
	CertificateFactory fact = CertificateFactory.getInstance("X.509");
	X509Certificate cert = (X509Certificate) fact.generateCertificate(stream);
	KeyStore pkcs12 = KeyStore.getInstance("PKCS12");
	pkcs12.load(null, null);
	pkcs12.setKeyEntry("device_certificate", privKey, pkcs12Password.toCharArray(), new Certificate[] {cert});
	ByteArrayOutputStream p12 = new ByteArrayOutputStream();
	pkcs12.store(p12, pkcs12Password.toCharArray());
	return p12.toByteArray();
}

Once you have the PKCS12 as bytes in memory, you can pass it directly into the installIntent, effectively never storing a p12 on the file system!

huangapple
  • 本文由 发表于 2020年7月31日 03:53:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/63180430.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定