1

由于 ICS Android 支持通过 KeyChain API 对系统密钥库和可信 CA 的统一访问。

这很好,但是当我尝试使用来自该来源的私钥进行客户端证书身份验证时,给我带来了麻烦。

我在这里检查了一些答案,发现最好的结果是:Android 4.0 SSL Authentication

它引用4.0并提供以下编码:

更新 - 这个编码是错误的 - 它在 4.1+ 中不起作用

String alias = "test";
KeyStore memoryKeyStore = KeyStore.getInstance("BKS");
memoryKeyStore.load(null);
X509Certificate[] chain = KeyChain.getCertificateChain(getApplicationContext(),alias);
PrivateKey key = KeyChain.getPrivateKey(getApplicationContext(),alias);
memoryKeyStore.setKeyEntry(alias, key.getEncoded(), chain);

但是,这在 4.1 中不起作用,因为当调用 getEncoded() 方法并且无法初始化 KeyStore 时,由 KeyChain.getPrivateKey() 返回的 PrivateKey 对象返回 null。

在 4.1 中还有其他方法可以做到这一点吗?

更新 - 这里是定义您自己的 KeyStore 和 KeyStoreSpi 实现的正确方法这里是 KeyStore 和 KeyStoreSpi 的示例实现:

KeyStoreSpi 实现:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Key;
import java.security.KeyStoreException;
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.List;

import java.security.PrivateKey;

public class KeyChainProxy extends KeyStoreSpi {


  private String alias = null;
  private PrivateKey privateKey = null;
  private Certificate[] certChain = null;

  public KeyChainProxy(String alias, PrivateKey privateKey, Certificate[] certChain) {
    this.alias = alias;
    this.privateKey = privateKey;
    this.certChain = certChain;
  }

  @Override
  public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException, UnrecoverableKeyException {
    return privateKey;
  }

  @Override
  public Certificate[] engineGetCertificateChain(String alias) {
    return certChain;
  }

  @Override
  public Certificate engineGetCertificate(String alias) {
    return certChain[0];
  }

  @Override
  public Date engineGetCreationDate(String alias) {
    return new Date();
  }

  @Override
  public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) throws KeyStoreException {
    throw new KeyStoreException("Not Implemented");

  }

  @Override
  public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) throws KeyStoreException {
    throw new KeyStoreException("Not Implemented");

  }

  @Override
  public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
    throw new KeyStoreException("Not Implemented");

  }

  @Override
  public void engineDeleteEntry(String alias) throws KeyStoreException {
    throw new KeyStoreException("Not Implemented");

  }

  @Override
  public Enumeration<String> engineAliases() {
    List<String> list = new ArrayList<String>();
    list.add(alias);
    return Collections.enumeration(list);
  }

  @Override
  public boolean engineContainsAlias(String alias) {
    return alias != null && alias.equals(this.alias);
  }

  @Override
  public int engineSize() {
    return 1;
  }

  @Override
  public boolean engineIsKeyEntry(String alias) {
    return true;
  }

  @Override
  public boolean engineIsCertificateEntry(String alias) {
    return false;
  }

  @Override
  public String engineGetCertificateAlias(Certificate cert) {
    return null;
  }

  @Override
  public void engineStore(OutputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {

  }

  @Override
  public void engineLoad(InputStream stream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException {

  }

}

密钥库实现:

import java.security.KeyStore;
import java.security.KeyStoreSpi;
import java.security.Provider;

public class KeyChainKeystore extends KeyStore {

  public KeyChainKeystore(KeyStoreSpi keyStoreSpi, Provider provider, String type) {
    super(keyStoreSpi, provider, type);
    try {
      load(null, null);
    } catch (Exception e) {
      // ignore - our spi doesn't do anything
    }
  }

}

谢谢

瓦西尔

4

1 回答 1

3

KeyChain 旨在保护您的私钥。

因此,您可以获得对私钥的引用,并在您的应用程序中使用该私钥进行身份验证、加密……但您永远无法访问实际的私钥数据。

因此,您无法导出私钥 - 这是您正在尝试做的事情。

于 2012-11-14T15:28:11.107 回答