问题
I have the following code to extract Private 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));
}
I would like to get the Public Key from converter when it's JceOpenSSLPKCS8DecryptorProviderBuilder
. Is there any way?
Thanks,
回答1:
The simplest way, although it feels rather ugly to me, is to convert the private key 'back' to one of OpenSSL's 'legacy' forms, which PEMParser
is then able to turn into a PEMKeyPair
with both halves, from which the public can be selected. Otherwise, the method must be tailored depending on the key algorithm aka type, but can be more efficient which I like better. Here are both options for your consideration:
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());
}
来源:https://stackoverflow.com/questions/57043669/bouncy-castle-how-to-get-public-key-info-from-jceopensslpkcs8decryptorprovider