java - Bouncy CaSTLe - 如何从 JceOpenSSLPKCS8DecryptorProviderBuilder 获取公钥信息

标签 java bouncycastle public-key

我有以下代码来提取私钥

    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 时,我想从转换器获取公钥。有什么办法吗?

谢谢

最佳答案

最简单的方法,虽然对我来说相当难看,是将私钥“转换回”OpenSSL 的“旧版”形式之一,然后 PEMParser 能够将其转换为 PEMKeyPair 具有两半,可以从中选择公共(public)。否则,该方法必须根据关键算法(即类型)进行定制,但可以更有效,这是我更喜欢的。以下是供您考虑的两个选项:

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());
}

关于java - Bouncy CaSTLe - 如何从 JceOpenSSLPKCS8DecryptorProviderBuilder 获取公钥信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57043669/

相关文章:

java - ECC ASN1 签名验证失败

java - 无法使用 RSA 公钥(使用 bouncycaSTLe 创建的 PEM 文件)来加密文件

java - 如何从 String 加载 RSA 公钥以在 Java 中进行签名验证?

java - PDFBox - 如何创建目录

java - 事后如何添加依赖注入(inject)?

java - 如何将字符串日期解析为 MongoDB 日期类型

java - 如何将字典键值项目应用到spark数据集中的列?

encryption - 代码分析以提高性能 : see CPU cycles inside mscorlib. dll?

java - 无法在java中从xml创建公钥对象

python - 如何从 python 中的 RSA 公钥中提取 N 和 E?