首页 > 解决方案 > Bouncy Castle - 如何从 JceOpenSSLPKCS8DecryptorProviderBuilder 获取公钥信息

问题描述

我有以下代码来提取私钥

    PEMParser parser = new PEMParser(new InputStreamReader(new ByteArrayInputStream(decoded)));
    Object object = parser.readObject();
    PEMDecryptorProvider provider = new JcePEMDecryptorProviderBuilder()
            .build(props.getProperty(KeytoolFlags.KEYPASS.name()).toCharArray());

    JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider(BouncyCastleProvider.PROVIDER_NAME);
    if (object instanceof PEMEncryptedKeyPair) {
        KeyPair pair = converter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(provider));
        return loadPublic ? pair.getPublic() : pair.getPrivate();
    } else if (object instanceof PEMKeyPair) {
        return loadPublic ? converter.getPublicKey(((PEMKeyPair) (object)).getPublicKeyInfo())
                : converter.getPrivateKey(((PEMKeyPair) (object)).getPrivateKeyInfo());
    } else {
        InputDecryptorProvider p2 = new JceOpenSSLPKCS8DecryptorProviderBuilder()
                .setProvider(BouncyCastleProvider.PROVIDER_NAME)
                .build(props.getProperty(KeytoolFlags.KEYPASS.name()).toCharArray());
        return converter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(p2));
    }

我想从转换器获取公钥JceOpenSSLPKCS8DecryptorProviderBuilder。有什么办法吗?

谢谢,

标签: javabouncycastlepublic-key

解决方案


最简单的方法,虽然对我来说感觉相当难看,但是将私钥“返回”转换为 OpenSSL 的“传统”形式之一,PEMParser然后可以变PEMKeyPair成两半的 a,可以从中选择公众。否则,该方法必须根据密钥算法(也称为类型)进行定制,但可以更有效,我更喜欢。这里有两个选项供您考虑:

public static void SO57043669PKCS8_Public_BC (String[] args) throws Exception {
    Object p8e = new PEMParser (new FileReader (args[0])).readObject();
    // for PKCS8-encrypted result is org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo 
    PrivateKeyInfo p8i = ((PKCS8EncryptedPrivateKeyInfo)p8e).decryptPrivateKeyInfo(
            new JceOpenSSLPKCS8DecryptorProviderBuilder().build(args[1].toCharArray()) );
    // or get org.bouncycastle.asn1.pkcs.PrivateKeyInfo directly from PEMParser for PKCS8-clear
    PublicKey pub = null;
    if( args.length>=3 ){ // the simple way:
        PrivateKey prv = new JcaPEMKeyConverter().getPrivateKey(p8i);
        PemObject old = new JcaMiscPEMGenerator (prv,null).generate();
        StringWriter w1 = new StringWriter(); 
        PemWriter w2 = new PemWriter(w1);
        w2.writeObject(old); w2.close();
        Object pair = new PEMParser(new StringReader(w1.toString())).readObject();
        pub = new JcaPEMKeyConverter().getKeyPair((PEMKeyPair)pair).getPublic();
    }else{
        ASN1ObjectIdentifier id = p8i.getPrivateKeyAlgorithm().getAlgorithm();
        PKCS8EncodedKeySpec p8s = new PKCS8EncodedKeySpec (p8i.getEncoded());
        if( id.equals(PKCSObjectIdentifiers.rsaEncryption) ){
            // the standard PKCS1 private key format for RSA redundantly includes e
            KeyFactory rfact = KeyFactory.getInstance("RSA");
            RSAPrivateCrtKey rprv = (RSAPrivateCrtKey) rfact.generatePrivate(p8s);
            // or JcaPEMKeyConverter.getPrivateKey does the same thing
            pub = /*(RSAPublicKey)*/ rfact.generatePublic(
                    new RSAPublicKeySpec (rprv.getModulus(), rprv.getPublicExponent()));
        }else if( id.equals(X9ObjectIdentifiers.id_dsa) ){
            // the apparently ad-hoc format OpenSSL uses for DSA does not include y but it can be computed
            KeyFactory dfact = KeyFactory.getInstance("DSA");
            DSAPrivateKey dprv = (DSAPrivateKey) dfact.generatePrivate(p8s);
            // or JcaPEMKeyConverter.getPrivateKey does the same thing
            BigInteger p = dprv.getParams().getP(), q = dprv.getParams().getQ(), g = dprv.getParams().getG();
            pub = /*(DSAPublicKey)*/ dfact.generatePublic (
                    new DSAPublicKeySpec(g.modPow(dprv.getX(),p), p, q, g) );
            // warning: naive computation probably vulnerable to sidechannel attack if any  
        }else if( id.equals(X9ObjectIdentifiers.id_ecPublicKey) ){
            // the SECG SEC1 format for EC private key _in PKCS8 by OpenSSL_ 
            // includes []] BITSTR(Q) (but not [0] params which is already in the PKCS8 algid)
            org.bouncycastle.asn1.sec.ECPrivateKey eprv = org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(p8i.parsePrivateKey());
            byte[] eenc = new SubjectPublicKeyInfo (p8i.getPrivateKeyAlgorithm(), eprv.getPublicKey().getOctets()).getEncoded(); 
            KeyFactory efact = KeyFactory.getInstance("EC");
            pub = /*(ECPublicKey)*/ KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(eenc));
            //}else if maybe others ...
        }else throw new Exception ("unknown private key OID " + id);
    }
    System.out.println (pub.getAlgorithm() + " " + pub.getClass().getName());
}

推荐阅读