【问题标题】:Getting exception while trying to get the private key from certificate尝试从证书中获取私钥时出现异常
【发布时间】:2016-04-27 05:28:46
【问题描述】:

我正在我的应用程序中进行 RSA 加密和解密。我在 assets 文件夹中放置了两个文件,用于加密的 public_key.cer 和用于解密的 private_key.cer。从文件 I 中获取公钥就像下面那样。

CertificateFactory certFactory = CertificateFactory.getInstance(X.509, BC);
InputStream is = context.getAssets().open("public_Key.cer");
X509Certificate cert = (X509Certificate) certFactory.generateCertificate(is);
publicKey = cert.getPublicKey();

RSA 加密工作正常,而我在尝试从证书中获取私钥时遇到问题。下面是用于获取私钥的代码

InputStream is = context.getAssets().open("private_key.cer");
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(is));
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
PrivateKey privateKey = keyFactory.generatePrivate(privSpec);

我遇到了异常。

    com.android.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException: unable to process key spec: java.lang.IllegalArgumentException: unknown object in getInstance: com.android.org.bouncycastle.asn1.DERApplicationSpecific
 at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePrivate(KeyFactorySpi.java:105)
 at java.security.KeyFactory.generatePrivate(KeyFactory.java:186)
 at com.teknospire.ndasenda_agent.utils.Conversion.decryptUsingPrivateKey(Conversion.java:111)
 at com.teknospire.ndasenda_agent.utils.Conversion.getDecryptedSkey(Conversion.java:243)
 at com.teknospire.ndasenda_agent.json.JsonCreationAndExtraction.readLoginParams(JsonCreationAndExtraction.java:40)
 at com.mockUp.ndasenda.LoginActivity$LoginRequest.doInBackground(LoginActivity.java:283)
 at com.mockUp.ndasenda.LoginActivity$LoginRequest.doInBackground(LoginActivity.java:1)
 at android.os.AsyncTask$2.call(AsyncTask.java:288)
 at java.util.concurrent.FutureTask.run(FutureTask.java:237)
 at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
 at java.lang.Thread.run(Thread.java:848)
 Caused by: java.lang.IllegalArgumentException: unknown object in getInstance: com.android.org.bouncycastle.asn1.DERApplicationSpecific
 at com.android.org.bouncycastle.asn1.ASN1Sequence.getInstance(ASN1Sequence.java:50)
 at com.android.org.bouncycastle.asn1.ASN1Sequence.getInstance(ASN1Sequence.java:33)
 at com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo.getInstance(PrivateKeyInfo.java:45)
 at com.android.org.bouncycastle.jcajce.provider.asymmetric.rsa.KeyFactorySpi.engineGeneratePrivate(KeyFactorySpi.java:91)
 ... 12 more
 java.lang.NullPointerException
 at org.bouncycastle.crypto.params.KeyParameter.<init>(KeyParameter.java:13)
 at com.teknospire.ndasenda_agent.utils.Conversion.decryptUsingSessionKey(Conversion.java:145)
 at com.teknospire.ndasenda_agent.utils.Conversion.getDecryptionData(Conversion.java:185)
 at com.teknospire.ndasenda_agent.json.JsonCreationAndExtraction.readLoginParams(JsonCreationAndExtraction.java:41)
 at com.mockUp.ndasenda.LoginActivity$LoginRequest.doInBackground(LoginActivity.java:283)
 at com.mockUp.ndasenda.LoginActivity$LoginRequest.doInBackground(LoginActivity.java:1)
 at android.os.AsyncTask$2.call(AsyncTask.java:288)
 at java.util.concurrent.FutureTask.run(FutureTask.java:237)
 at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
 at java.lang.Thread.run(Thread.java:848)

谁能帮助我,如何从 .cer 文件中读取私钥。

提前致谢。

【问题讨论】:

  • 私钥有多种可能的格式;您的代码需要 PKCS8 格式,但您没有说明 private_key.cer 的格式。

标签: java android rsa public-key-encryption private-key


【解决方案1】:

查看this 了解基本实现

网站摘录

Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());

    byte[] input = new byte[] { (byte) 0xbe, (byte) 0xef };
    Cipher cipher = Cipher.getInstance("RSA/None/NoPadding", "BC");

    KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
    RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(new BigInteger(
        "12345678", 16), new BigInteger("11", 16));
    RSAPrivateKeySpec privKeySpec = new RSAPrivateKeySpec(new BigInteger(
        "12345678", 16), new BigInteger("12345678",
        16));

    RSAPublicKey pubKey = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);
    RSAPrivateKey privKey = (RSAPrivateKey) keyFactory.generatePrivate(privKeySpec);

    cipher.init(Cipher.ENCRYPT_MODE, pubKey);

    byte[] cipherText = cipher.doFinal(input);
    System.out.println("cipher: " + new String(cipherText));

    cipher.init(Cipher.DECRYPT_MODE, privKey);
    byte[] plainText = cipher.doFinal(cipherText);
    System.out.println("plain : " + new String(plainText));

【讨论】:

  • 感谢您的回复,但是这段代码会生成新的密钥,对吧?我已经有了可用的密钥,我只想知道如何从证书中读取私钥。
  • 检查您的问题是否与二进制编码有关。 newsgroups.derkeiler.com/Archive/Comp/comp.lang.java.security/…
  • 是的,我没有删除 BEGIN-END 标签,现在删除它们后,我遇到了异常 java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0D0680A8:asn1编码例程:ASN1_CHECK_TLEN:wrong tag
【解决方案2】:

从文件中获取私钥的代码:

    private KeyStore.PrivateKeyEntry getKeyFromFile(String keyStoreFile,
    String Password, Context cntx) {
    KeyStore.PrivateKeyEntry entry = null;
    try {
        AssetManager am = cntx.getAssets();
        char[] keyStorePassword = Password.toCharArray();
        // Load the KeyStore and get the signing key and certificate.
        KeyStore ks = KeyStore.getInstance("PKCS12");

        ks.load(am.open(keyStoreFile), keyStorePassword);
        String alias = ks.aliases().nextElement();

        Entry entry1 = ks.getEntry(alias, new KeyStore.PasswordProtection(
                keyStorePassword));
        entry = (KeyStore.PrivateKeyEntry) entry1;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return entry;
}

您可以使用以下方法解密您的数据:

  public byte[] decryptUsingPrivateKey(String encryptedData, Context cntx) {

    byte[] utf8 = null;
    try {
        KeyStore.PrivateKeyEntry privateKey = getKeyFromFile(
                "PrivateKeyFile.pfx", "privatekeypassword", cntx);

        Cipher rsa;
        rsa = Cipher.getInstance("RSA/ECB/PKCS1Padding");
        rsa.init(Cipher.DECRYPT_MODE, privateKey.getPrivateKey());
        utf8 = rsa.doFinal(Base64.decode(encryptedData));

    } catch (Exception e) {
        System.out.println(e);
    }

    return utf8;
}

注意:

  1. 要使用它,您必须在应用程序中编译库“bcprov-jdk15on-152.jar”
  2. 在 android 中使用私钥文件不是一个好习惯。希望您在测试服务器中使用它。

【讨论】:

  • 感谢您的回复,我在使用您的代码时遇到异常 java.security.KeyStoreException: java.security.NoSuchAlgorithmException: KeyStore PKCS implementation not found, .cer typr 的算法是什么文件?
  • 试试这个链接:programcreek.com/java-api-examples/…。我会就 .cer 类型的文件回复你。
猜你喜欢
  • 1970-01-01
  • 2016-06-22
  • 2014-08-19
  • 2014-03-21
  • 1970-01-01
  • 1970-01-01
  • 2016-03-01
  • 2021-09-13
  • 1970-01-01
相关资源
最近更新 更多