Android Java更新证书和Android KeyStore中的私钥
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Android Java更新证书和Android KeyStore中的私钥,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含5898字,纯文字阅读大概需要9分钟。
内容图文
![Android Java更新证书和Android KeyStore中的私钥](/upload/InfoBanner/zyjiaocheng/805/2aa539d1e8b04011be18e20701c3db81.jpg)
我有一个使用HTTPS客户端证书进行身份验证的系统,但根据以下过程生成证书本身:
>客户端设备生成证书(包括公钥和私钥)
>客户端设备将公钥发送到服务器,该服务器对公钥进行签名,并将其作为签名证书返回
>客户端以安全的方式存储证书,然后将其用作HTTPS客户端证书
我们有这个系统在iOS上工作,我正在尝试移植到android,但遇到了很多问题,因为Android的文档记录不清,安全API混乱.
我的代码大致如下:
生成证书
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
Date startDate = new Date();
Date endDate = new Date(startDate.getTime() + FORTY_YEARS_IN_MILLISECONDS);
KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(context)
.setAlias(alias)
.setKeySize(2048)
.setKeyType(KeyProperties.KEY_ALGORITHM_RSA)
.setSubject(new X500Principal("CN=" + alias))
.setSerialNumber(BigInteger.TEN)
.setStartDate(startDate)
.setEndDate(endDate)
.build();
KeyPairGenerator generator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEYSTORE);
generator.initialize(spec);
KeyPair keyPair = generator.generateKeyPair(); // this will put a certificate and key pair in the keyStore.
dumpKeyStore(keyStore);
byte[] entireKey = keyPair.getPublic().getEncoded();
// chop off first 24 bytes; the java key pair generator puts an object ID of 1.2.840.113549.1.1.1 RSA (RSA_SIGN) before the key which gets mangled when the server signs and sends back the certificate
byte[] publicKeyBytes = Arrays.copyOfRange(entireKey, 24, entireKey.length);
dumpKeyStore是一个实用程序方法,它迭代密钥库,调用keyStore.getEntry来获取每个条目,并且只记录事物.
此时,它报告存在具有给定别名的单个条目,并且其类型为KeyStore.PrivateKeyEntry.它有一个关联的证书和公钥,可以从PrivateKeyEntry中重新获得.
发送到服务器
publicKeyBytes被发送到服务器,服务器将其作为新的签名x509证书的公钥,该证书将在响应中发回.我没有放入代码,它只是基本的网络.返回的证书加载,看起来很好.
保存并关联证书
我试图用相同的别名将它放入keyStore,因此它(理论上)可以与之前的正确私钥相关联.到目前为止我的代码是这样的:
KeyStore keyStore;
try {
keyStore = KeyStore.getInstance(ANDROID_KEYSTORE);
keyStore.load(null);
}catch (IOException | NoSuchAlgorithmException | CertificateException e) {
Log.wtf(TAG, e);
throw new FatalError(TAG, e);
}
CertificateFactory certificateFactory;
try {
certificateFactory = CertificateFactory.getInstance("X.509");
} catch (CertificateException e) {
Log.wtf(TAG, e);
throw new FatalError(TAG, e);
}
Certificate cert = certificateFactory.generateCertificate(new ByteArrayInputStream(certificateFromServer));
// find the existing certificate, copy it's private key out, then replace the certificate with the one from the server but keeping the private key
try {
KeyStore.PrivateKeyEntry existingPrivateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(alias, null);
KeyStore.PrivateKeyEntry newEntry = new KeyStore.PrivateKeyEntry(existingPrivateKeyEntry.getPrivateKey(), new Certificate[]{ cert });
keyStore.setEntry(alias, newEntry, null);
} catch (Exception e) {
Log.wtf(TAG, e);
throw new FatalError(TAG, e);
}
dumpKeyStore(keyStore);
此时,最终的dumpKeyStore指示存在具有正确别名的条目,但是当它尝试调用keyStore.getEntry时会引发“NoSuchAlgorithmException:Unknown key entry”异常.
我想在android中做什么(替换证书但保留私钥)?如果是这样,我该怎么做?看起来这不是真的有效
谢谢
猎户座
解决方法:
事实证明,我做错了.您不需要替换或修改KeyStore中的证书,只需在初始化HttpsURLConnection使用的SSLContext时使用自定义KeyManager,并且KeyManager可以选择您想要的任何证书或私钥.
这极大地简化了KeyStore管理.我的情景现在
>使用KeyPairGenerator生成公钥/私钥对,别名为X.
>将公钥发送到服务器,该服务器从该公钥生成新的签名证书,然后将其发回
>使用带有别名X-Signed的setCertificateEntry将此签名证书放入KeyStore
当我建立HttpsURLConnection时,它是这样的:
KeyStore androidKeyStore = KeyStore.getInstance(LocalKeyStore.ANDROID_KEYSTORE);
androidKeyStore.load(null);
X509Certificate signedClientCertificate = (X509Certificate)androidKeyStore.getCertificate("X-Signed");
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)androidKeyStore.getEntry("X", null);
X509ExtendedKeyManager keyManager = new X509ExtendedKeyManager() {
@Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
return clientCertificateAlias;
}
@Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
return null; // different if you're validating the server's cert
}
@Override
public X509Certificate[] getCertificateChain(String alias) {
return new X509Certificate[] { signedClientCertificate };
}
@Override
public String[] getClientAliases(String keyType, Principal[] issuers) {
return new String[]{ "X" };
}
@Override
public String[] getServerAliases(String keyType, Principal[] issuers) {
return null; // different if you're validating server's cert
}
@Override
public PrivateKey getPrivateKey(String alias) {
if(alias != clientCertificateAlias) {
Log.e(TAG, String.format("X509ExtendedKeyManager is asking for privateKey with unknown alias %s. Expecting it to ask for %s", alias, clientCertificateAlias));
return null;
}
return privateKeyEntry.getPrivateKey();
}
};
X509TrustManager trustServerCertificates = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
// do nothing, this method doesn't get called
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType)
// code to validate server's cert in here
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return null; // any issuer
}
};
m_sslContext = SSLContext.getInstance("TLS");
m_sslContext.init(new KeyManager[]{ keyManager }, new TrustManager[] { trustServerCertificates }, null);
// later on
conn = (HttpURLConnection)url.openConnection();
SSLContext sslContext = m_sslContext;
if(conn instanceof HttpsURLConnection && sslContext != null) {
((HttpsURLConnection)conn).setSSLSocketFactory(sslContext.getSocketFactory());
}
这对我很有用,我可以继续使用AndroidKeyStore,它的每个应用程序隐私和硬件支持的存储
内容总结
以上是互联网集市为您收集整理的Android Java更新证书和Android KeyStore中的私钥全部内容,希望文章能够帮你解决Android Java更新证书和Android KeyStore中的私钥所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。