【问题标题】:Bouncy Castle - how to get Public Key Info from JceOpenSSLPKCS8DecryptorProviderBuilderBouncy Castle - 如何从 JceOpenSSLPKCS8DecryptorProviderBuilder 获取公钥信息
【发布时间】:2019-11-24 09:18:40
【问题描述】:

我有以下代码来提取私钥

    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。有什么办法吗?

谢谢,

【问题讨论】:

    标签: java bouncycastle public-key


    【解决方案1】:

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

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

    【讨论】:

    • 独一无二!谢谢。现在我想我会尝试单独使用公钥。这样做的原因是我们正在从数据库加载密钥。我们有两个变体 - JKS 和 PKCS8(PEM 编码)。我希望保存一个私钥条目就足够了。但看起来 PKCS8 格式的密钥应该分别作为公钥和私钥保存。我现在将采用这种方法。
    【解决方案2】:

    除了其他答案之外,还有一种将 Ed25519 私钥转换为公钥的方法:

    private val bouncyCastleProvider = BouncyCastleProvider()
    private val pkcs8pemKeyConverter = JcaPEMKeyConverter().setProvider(bouncyCastleProvider)
    
    fun makeKeyPair(keyReader: Reader, passphrase: CharArray): KeyPair {
        var obj = PEMParser(keyReader).readObject()
        ...
        if (obj is PrivateKeyInfo) {
            val privateKey = pkcs8pemKeyConverter.getPrivateKey(obj)
    
            if (privateKey is EdDSAKey) {
                return KeyPair(genEd25519publicKey(privateKey, obj), privateKey)
            }
    
            ...
        }
        ...
    }
    
    private fun genEd25519publicKey(privateKey: EdDSAKey, keyInfo: PrivateKeyInfo): PublicKey {
        val privateKeyParameters = Ed25519PrivateKeyParameters(privateKey.encoded, 0)
        val publicKeyParameters = privateKeyParameters.generatePublicKey()
        val spi = SubjectPublicKeyInfo(keyInfo.privateKeyAlgorithm, publicKeyParameters.encoded)
        val factory = KeyFactory.getInstance(privateKey.algorithm, bouncyCastleProvider)
        return factory.generatePublic(X509EncodedKeySpec(spi.encoded))
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-05
      • 1970-01-01
      • 2018-10-06
      • 2021-12-19
      • 1970-01-01
      • 2013-02-06
      • 1970-01-01
      相关资源
      最近更新 更多