从ASN1加密pem证书获取公钥和私钥

时间:2015-05-22 08:41:16

标签: java security ssl encryption asn.1

我正在尝试用私钥签名一个特定字符串,我将从pem证书中获取。此证书使用密码加密。证书格式(.pem文件)是这样的:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,A60C80692F0FEB16

Fq/awhS....
+..
+..
+..
+..
+....detSug=
-----END RSA PRIVATE KEY-----

我写这篇从该证书中获取公钥和私钥的代码是:

import java.io.FileReader;
import java.io.IOException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;

import org.bouncycastle.asn1.ASN1Generator;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.PEMDecryptorProvider;
import org.bouncycastle.openssl.PEMEncryptedKeyPair;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;


import sun.misc.BASE64Encoder;

class MainClass{
    public static void main(String args[]){
        try{
        PrivateKey pk = readPrivateKey("C:/Input/CERT.pem","passphrase");
        PublicKey pubk = readPublicKey("C:/Input/CERT.pem","passphrase");
        byte[] data = "ABCEFG20150520163306".getBytes("UTF8");

        Signature sig = Signature.getInstance("SHA1WithRSA");
        sig.initSign(pk);
        sig.update(data);
        byte[] signatureBytes = sig.sign();
        System.out.println("Singature:" + new BASE64Encoder().encode(signatureBytes));

        sig.initVerify(pubk);
        sig.update(data);
        System.out.println(sig.verify(signatureBytes));

        }catch(Exception e){

            e.printStackTrace();
        }

    }


    private static PrivateKey readPrivateKey(String privateKeyPath, String keyPassword) throws IOException {

        FileReader fileReader = new FileReader(privateKeyPath);

        PEMParser keyReader = new PEMParser(fileReader);

        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        PEMDecryptorProvider decryptionProv = new JcePEMDecryptorProviderBuilder().build(keyPassword.toCharArray());
        System.out.println(keyReader.getClass());
        Object keyPair = keyReader.readObject();
        PrivateKeyInfo keyInfo;
        System.out.println(keyPair.getClass());


        if (keyPair instanceof PrivateKeyInfo) {
            System.out.println("Correct instance found");

            PEMKeyPair decryptedKeyPair = ((PEMEncryptedKeyPair) keyPair).decryptKeyPair(decryptionProv);
            keyInfo = decryptedKeyPair.getPrivateKeyInfo();
        } else {
            keyInfo = ((PEMKeyPair) keyPair).getPrivateKeyInfo();
        }

        keyReader.close();

        return converter.getPrivateKey(keyInfo);
    }


    private static PublicKey readPublicKey(String privateKeyPath, String keyPassword) throws IOException {

        FileReader fileReader = new FileReader(privateKeyPath);
        PEMParser keyReader = new PEMParser(fileReader);

        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
        PEMDecryptorProvider decryptionProv = new JcePEMDecryptorProviderBuilder().build(keyPassword.toCharArray());

        Object keyPair = keyReader.readObject();
        SubjectPublicKeyInfo keyInfo;

        if (keyPair instanceof PEMEncryptedKeyPair) {
            PEMKeyPair decryptedKeyPair = ((PEMEncryptedKeyPair) keyPair).decryptKeyPair(decryptionProv);
            keyInfo = decryptedKeyPair.getPublicKeyInfo();
        } else {
            keyInfo = ((PEMKeyPair) keyPair).getPublicKeyInfo();
        }
        keyReader.close();
        return converter.getPublicKey(keyInfo);
    }
}

此代码工作正常,但现在我必须为ASN1证书做同样的事情,看起来像这样

Bag Attributes
localKeyID: 01 00 00 00 
friendlyName: le-d5391255-2e94-48fe-8327-caca5d9aa498<Microsoft CSP Name: Microsoft Enhanced Cryptographic Provider v1.0
Key Attributes
X509v3 Key Usage: 10 
-----BEGIN PRIVATE KEY-----
MIIEvwIBA....
+..
+..
+..
+..
+....N5kNrDV0Yg==
-----END PRIVATE KEY-----

Bag Attributes
localKeyID: 00 01 00 00 
1.3.6.1.4.1.322.17.3.92: 00 08 00 00 
1.3.6.1.4.1.311.17.3.20: 15 0D 78 6A D0 18 CB A2 D1 7F D1 C2 B2 7A E0 53 70 D7 ED F9 
1.3.6.1.4.1.313.17.3.79: 46 00 61 00 9E 00 65 00 73 00 73 00 61 00 2D 00 50 00 43 00 00 00 
subject=/C=SG/O=Netrust Certificate Authority 1/OU=Netrust CA1 (Server)/OU=ABC-XYZ Private Limited/CN=QICERT
issuer=/C=SG/O=Netrust Certificate Authority 1/OU=Netrust CA
-----BEGIN CERTIFICATE-----
MIIE5DCCA8yg....
+..
+..
+..
+..
+....Y7LF
Byuyq1Pe4QY=
-----END CERTIFICATE-----

Bag Attributes
1.3.6.1.4.1.311.17.3.92: 00 08 00 00 
1.3.1.1.4.1.221.17.3.20: 1D 44 89 B2 45 26 7F 3F 6B 92 C5 3A 7B 72 63 CA D2 70 2A DD 
subject=/C=SG/O=Netrust Certificate Authority 1/OU=Netrust CA1
issuer=/C=SG/O=Netrust Certificate Authority 1/OU=Netrust CA1
-----BEGIN CERTIFICATE-----
MIIESTCCAzGgAwI....
+..
+..
+..
+..
+....Y7LF
iY44mB2Sev4/02GkW7
-----END CERTIFICATE-----

当我为这个新证书运行此代码时,我收到以下错误:

java.lang.ClassCastException: org.bouncycastle.asn1.pkcs.PrivateKeyInfo cannot be cast to org.bouncycastle.openssl.PEMEncryptedKeyPair
    at MainClass.readPrivateKey(MainClass.java:92)
    at MainClass.main(MainClass.java:47)

基于此错误消息,我正在尝试更改我的代码以获取ASN1类型的私钥 - 公钥对,但我无法这样做。

我使用thisthis作为参考。

谢谢!

1 个答案:

答案 0 :(得分:0)

经过同事/批配合的大量帮助,我终于能够解决这个问题了。这就是我所做的:
首先,我使用以下命令将pem证书转换为der证书

openssl pkcs8 -topk8 -inform PEM -outform DER -passin pass:passphrase -in "C:\Input\CERT.pem" -out "C:\Input\CERT.der"-nocrypt

然后我使用以下类根据上面收到的证书对给定字符串进行签名和编码:

import java.io.*;
import java.security.*;
import java.security.spec.*;

import com.sun.org.apache.xml.internal.security.utils.Base64;

class MainClass{
    public static void main(String args[]){
        try {
            MessageDigest cript = MessageDigest.getInstance("SHA-1");
            cript.reset();
                    cript.update(args[0].getBytes("UTF-8"));
                    byte[] b_digest = cript.digest();

            Signature sign = Signature.getInstance("SHA1withRSA");
            PrivateKey pk = get("C:/Input/CERT.der");
            sign.initSign(pk);
            sign.update(b_digest);
            byte[] b1 = sign.sign();

            String signedString = new String(b1);
            String s2 = new String(Base64.encode(b1));

            System.out.println("_______________PrivateKey_________________________");
            System.out.println(pk.toString() +"|");
            System.out.println("_______________Digest_________________________");
            String temp = new String(b_digest);
            System.out.println(temp + "|");
            System.out.println("_______________Signature_________________________");
            System.out.println(signedString +"|");
            System.out.println("_______________Encoded_________________________");
            System.out.println(s2 +"|");

            }
        catch (Exception ex) {
            System.out.println(ex.getMessage());
            ex.printStackTrace();
            }
        }

    public static PrivateKey get(String filename) throws Exception {
        File f = new File(filename);
        FileInputStream fis = new FileInputStream(f);
        DataInputStream dis = new DataInputStream(fis);
        byte[] keyBytes = new byte[(int)f.length()];
        dis.readFully(keyBytes);
        dis.close();

        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(spec);
    }
}

所有这个类都是将字符串作为输入表单命令行进行签名,并使用作为输入提供的证书对其进行签名。

希望所有遇到类似于我所做的事情的人都可以从中获得一些帮助。 谢谢!