如何读取.pem文件以获取私钥和公钥
我写了一小段代码,读取存储在.pem文件中的公钥和私钥。 我正在使用以下命令来生成密钥。
下面的命令生成一对密钥。
$openssl genrsa -out mykey.pem 2048
这个命令生成私钥
$openssl pkcs8 -topk8 -inform PEM -outform PEM -in mykey.pem \ -out private_key.pem -nocrypt
和这个命令来获取公钥。
$ openssl rsa -in mykey.pem -pubout -outform DER -out public_key.der
我写了两个分别读取私钥和公钥的方法。
public PrivateKey getPemPrivateKey(String filename, String algorithm) 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(); String temp = new String(keyBytes); String privKeyPEM = temp.replace("-----BEGIN PRIVATE KEY-----\n", ""); privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", ""); //System.out.println("Private key\n"+privKeyPEM); Base64 b64 = new Base64(); byte [] decoded = b64.decode(privKeyPEM); PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance(algorithm); return kf.generatePrivate(spec); } public PublicKey getPemPublicKey(String filename, String algorithm) 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(); String temp = new String(keyBytes); String publicKeyPEM = temp.replace("-----BEGIN PUBLIC KEY-----\n", ""); publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", ""); Base64 b64 = new Base64(); byte [] decoded = b64.decode(publicKeyPEM); X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded); KeyFactory kf = KeyFactory.getInstance(algorithm); return kf.generatePublic(spec); }
我觉得这是一个天真的做法。 我无法通过互联网获得更好的方式。 任何人都可以build议我什么是编写相同的代码来处理通用案件的最佳方式。 我不想使用任何types的第三方库。
我有唱歌/encryption的基本知识,几乎不使用任何Java安全API。 所以,如果我没有意义的地方,请指出。
一种select是使用bouncycastle的PEMParser :
用于parsing包含X509证书,PKCS8编码密钥和PKCS7对象的OpenSSL PEM编码stream的类。
对于PKCS7对象,阅读器将返回一个CMS ContentInfo对象。 公共密钥将被返回以及形成的SubjectPublicKeyInfo对象,私钥将被返回以及形成PrivateKeyInfo对象。 在私钥的情况下,如果编码同时包含私钥和公钥定义,则通常会返回PEMKeyPair。 CRL,证书,PKCS#10请求和属性证书将生成适当的BC持有者类。
这里是使用parsing器testing代码的一个例子:
package org.bouncycastle.openssl.test; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.Reader; import java.math.BigInteger; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.Signature; import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPrivateKey; import org.bouncycastle.asn1.ASN1ObjectIdentifier; import org.bouncycastle.asn1.cms.CMSObjectIdentifiers; import org.bouncycastle.asn1.cms.ContentInfo; import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.cert.X509CertificateHolder; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.PEMWriter; import org.bouncycastle.openssl.PasswordFinder; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JceOpenSSLPKCS8DecryptorProviderBuilder; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; import org.bouncycastle.operator.InputDecryptorProvider; import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; import org.bouncycastle.util.test.SimpleTest; /** * basic class for reading test.pem - the password is "secret" */ public class ParserTest extends SimpleTest { private static class Password implements PasswordFinder { char[] password; Password( char[] word) { this.password = word; } public char[] getPassword() { return password; } } public String getName() { return "PEMParserTest"; } private PEMParser openPEMResource( String fileName) { InputStream res = this.getClass().getResourceAsStream(fileName); Reader fRd = new BufferedReader(new InputStreamReader(res)); return new PEMParser(fRd); } public void performTest() throws Exception { PEMParser pemRd = openPEMResource("test.pem"); Object o; PEMKeyPair pemPair; KeyPair pair; while ((o = pemRd.readObject()) != null) { if (o instanceof KeyPair) { //pair = (KeyPair)o; //System.out.println(pair.getPublic()); //System.out.println(pair.getPrivate()); } else { //System.out.println(o.toString()); } } // test bogus lines before begin are ignored. pemRd = openPEMResource("extratest.pem"); while ((o = pemRd.readObject()) != null) { if (!(o instanceof X509CertificateHolder)) { fail("wrong object found"); } } // // pkcs 7 data // pemRd = openPEMResource("pkcs7.pem"); ContentInfo d = (ContentInfo)pemRd.readObject(); if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData)) { fail("failed envelopedData check"); } // // ECKey // pemRd = openPEMResource("eckey.pem"); ASN1ObjectIdentifier ecOID = (ASN1ObjectIdentifier)pemRd.readObject(); X9ECParameters ecSpec = ECNamedCurveTable.getByOID(ecOID); if (ecSpec == null) { fail("ecSpec not found for named curve"); } pemPair = (PEMKeyPair)pemRd.readObject(); pair = new JcaPEMKeyConverter().setProvider("BC").getKeyPair(pemPair); Signature sgr = Signature.getInstance("ECDSA", "BC"); sgr.initSign(pair.getPrivate()); byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; sgr.update(message); byte[] sigBytes = sgr.sign(); sgr.initVerify(pair.getPublic()); sgr.update(message); if (!sgr.verify(sigBytes)) { fail("EC verification failed"); } if (!pair.getPublic().getAlgorithm().equals("ECDSA")) { fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm()); } if (!pair.getPrivate().getAlgorithm().equals("ECDSA")) { fail("wrong algorithm name on private"); } // // ECKey -- explicit parameters // pemRd = openPEMResource("ecexpparam.pem"); ecSpec = (X9ECParameters)pemRd.readObject(); pemPair = (PEMKeyPair)pemRd.readObject(); pair = new JcaPEMKeyConverter().setProvider("BC").getKeyPair(pemPair); sgr = Signature.getInstance("ECDSA", "BC"); sgr.initSign(pair.getPrivate()); message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; sgr.update(message); sigBytes = sgr.sign(); sgr.initVerify(pair.getPublic()); sgr.update(message); if (!sgr.verify(sigBytes)) { fail("EC verification failed"); } if (!pair.getPublic().getAlgorithm().equals("ECDSA")) { fail("wrong algorithm name on public got: " + pair.getPublic().getAlgorithm()); } if (!pair.getPrivate().getAlgorithm().equals("ECDSA")) { fail("wrong algorithm name on private"); } // // writer/parser test // KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); pair = kpGen.generateKeyPair(); keyPairTest("RSA", pair); kpGen = KeyPairGenerator.getInstance("DSA", "BC"); kpGen.initialize(512, new SecureRandom()); pair = kpGen.generateKeyPair(); keyPairTest("DSA", pair); // // PKCS7 // ByteArrayOutputStream bOut = new ByteArrayOutputStream(); PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut)); pWrt.writeObject(d); pWrt.close(); pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray()))); d = (ContentInfo)pemRd.readObject(); if (!d.getContentType().equals(CMSObjectIdentifiers.envelopedData)) { fail("failed envelopedData recode check"); } // OpenSSL test cases (as embedded resources) doOpenSslDsaTest("unencrypted"); doOpenSslRsaTest("unencrypted"); doOpenSslTests("aes128"); doOpenSslTests("aes192"); doOpenSslTests("aes256"); doOpenSslTests("blowfish"); doOpenSslTests("des1"); doOpenSslTests("des2"); doOpenSslTests("des3"); doOpenSslTests("rc2_128"); doOpenSslDsaTest("rc2_40_cbc"); doOpenSslRsaTest("rc2_40_cbc"); doOpenSslDsaTest("rc2_64_cbc"); doOpenSslRsaTest("rc2_64_cbc"); doDudPasswordTest("7fd98", 0, "corrupted stream - out of bounds length found"); doDudPasswordTest("ef677", 1, "corrupted stream - out of bounds length found"); doDudPasswordTest("800ce", 2, "unknown tag 26 encountered"); doDudPasswordTest("b6cd8", 3, "DEF length 81 object truncated by 56"); doDudPasswordTest("28ce09", 4, "DEF length 110 object truncated by 28"); doDudPasswordTest("2ac3b9", 5, "DER length more than 4 bytes: 11"); doDudPasswordTest("2cba96", 6, "DEF length 100 object truncated by 35"); doDudPasswordTest("2e3354", 7, "DEF length 42 object truncated by 9"); doDudPasswordTest("2f4142", 8, "DER length more than 4 bytes: 14"); doDudPasswordTest("2fe9bb", 9, "DER length more than 4 bytes: 65"); doDudPasswordTest("3ee7a8", 10, "DER length more than 4 bytes: 57"); doDudPasswordTest("41af75", 11, "unknown tag 16 encountered"); doDudPasswordTest("1704a5", 12, "corrupted stream detected"); doDudPasswordTest("1c5822", 13, "unknown object in getInstance: org.bouncycastle.asn1.DERUTF8String"); doDudPasswordTest("5a3d16", 14, "corrupted stream detected"); doDudPasswordTest("8d0c97", 15, "corrupted stream detected"); doDudPasswordTest("bc0daf", 16, "corrupted stream detected"); doDudPasswordTest("aaf9c4d",17, "corrupted stream - out of bounds length found"); doNoPasswordTest(); // encrypted private key test InputDecryptorProvider pkcs8Prov = new JceOpenSSLPKCS8DecryptorProviderBuilder().build("password".toCharArray()); pemRd = openPEMResource("enckey.pem"); PKCS8EncryptedPrivateKeyInfo encPrivKeyInfo = (PKCS8EncryptedPrivateKeyInfo)pemRd.readObject(); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); RSAPrivateCrtKey privKey = (RSAPrivateCrtKey)converter.getPrivateKey(encPrivKeyInfo.decryptPrivateKeyInfo(pkcs8Prov)); if (!privKey.getPublicExponent().equals(new BigInteger("10001", 16))) { fail("decryption of private key data check failed"); } // general PKCS8 test pemRd = openPEMResource("pkcs8test.pem"); Object privInfo; while ((privInfo = pemRd.readObject()) != null) { if (privInfo instanceof PrivateKeyInfo) { privKey = (RSAPrivateCrtKey)converter.getPrivateKey(PrivateKeyInfo.getInstance(privInfo)); } else { privKey = (RSAPrivateCrtKey)converter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo)privInfo).decryptPrivateKeyInfo(pkcs8Prov)); } if (!privKey.getPublicExponent().equals(new BigInteger("10001", 16))) { fail("decryption of private key data check failed"); } } } private void keyPairTest( String name, KeyPair pair) throws IOException { PEMParser pemRd; ByteArrayOutputStream bOut = new ByteArrayOutputStream(); PEMWriter pWrt = new PEMWriter(new OutputStreamWriter(bOut)); pWrt.writeObject(pair.getPublic()); pWrt.close(); pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray()))); SubjectPublicKeyInfo pub = SubjectPublicKeyInfo.getInstance(pemRd.readObject()); JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); PublicKey k = converter.getPublicKey(pub); if (!k.equals(pair.getPublic())) { fail("Failed public key read: " + name); } bOut = new ByteArrayOutputStream(); pWrt = new PEMWriter(new OutputStreamWriter(bOut)); pWrt.writeObject(pair.getPrivate()); pWrt.close(); pemRd = new PEMParser(new InputStreamReader(new ByteArrayInputStream(bOut.toByteArray()))); KeyPair kPair = converter.getKeyPair((PEMKeyPair)pemRd.readObject()); if (!kPair.getPrivate().equals(pair.getPrivate())) { fail("Failed private key read: " + name); } if (!kPair.getPublic().equals(pair.getPublic())) { fail("Failed private key public read: " + name); } } private void doOpenSslTests( String baseName) throws IOException { doOpenSslDsaModesTest(baseName); doOpenSslRsaModesTest(baseName); } private void doOpenSslDsaModesTest( String baseName) throws IOException { doOpenSslDsaTest(baseName + "_cbc"); doOpenSslDsaTest(baseName + "_cfb"); doOpenSslDsaTest(baseName + "_ecb"); doOpenSslDsaTest(baseName + "_ofb"); } private void doOpenSslRsaModesTest( String baseName) throws IOException { doOpenSslRsaTest(baseName + "_cbc"); doOpenSslRsaTest(baseName + "_cfb"); doOpenSslRsaTest(baseName + "_ecb"); doOpenSslRsaTest(baseName + "_ofb"); } private void doOpenSslDsaTest( String name) throws IOException { String fileName = "dsa/openssl_dsa_" + name + ".pem"; doOpenSslTestFile(fileName, DSAPrivateKey.class); } private void doOpenSslRsaTest( String name) throws IOException { String fileName = "rsa/openssl_rsa_" + name + ".pem"; doOpenSslTestFile(fileName, RSAPrivateKey.class); } private void doOpenSslTestFile( String fileName, Class expectedPrivKeyClass) throws IOException { JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC"); PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("BC").build("changeit".toCharArray()); PEMParser pr = openPEMResource("data/" + fileName); Object o = pr.readObject(); if (o == null || !((o instanceof PEMKeyPair) || (o instanceof PEMEncryptedKeyPair))) { fail("Didn't find OpenSSL key"); } KeyPair kp = (o instanceof PEMEncryptedKeyPair) ? converter.getKeyPair(((PEMEncryptedKeyPair)o).decryptKeyPair(decProv)) : converter.getKeyPair((PEMKeyPair)o); PrivateKey privKey = kp.getPrivate(); if (!expectedPrivKeyClass.isInstance(privKey)) { fail("Returned key not of correct type"); } } private void doDudPasswordTest(String password, int index, String message) { // illegal state exception check - in this case the wrong password will // cause an underlying class cast exception. try { PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("BC").build(password.toCharArray()); PEMParser pemRd = openPEMResource("test.pem"); Object o; while ((o = pemRd.readObject()) != null) { if (o instanceof PEMEncryptedKeyPair) { ((PEMEncryptedKeyPair)o).decryptKeyPair(decProv); } } fail("issue not detected: " + index); } catch (IOException e) { if (e.getCause() != null && !e.getCause().getMessage().endsWith(message)) { fail("issue " + index + " exception thrown, but wrong message"); } else if (e.getCause() == null && !e.getMessage().equals(message)) { e.printStackTrace(); fail("issue " + index + " exception thrown, but wrong message"); } } } private void doNoPasswordTest() throws IOException { PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().setProvider("BC").build("".toCharArray()); PEMParser pemRd = openPEMResource("smimenopw.pem"); Object o; PrivateKeyInfo key = null; while ((o = pemRd.readObject()) != null) { key = (PrivateKeyInfo)o; } if (key == null) { fail("private key not detected"); } } public static void main( String[] args) { Security.addProvider(new BouncyCastleProvider()); runTest(new ParserTest()); } }
那么,我的代码就像你的代码一样,几乎没有区别。
public static X509Certificate loadPublicX509(String fileName) throws GeneralSecurityException { InputStream is = null; X509Certificate crt = null; try { is = fileName.getClass().getResourceAsStream("/" + fileName); CertificateFactory cf = CertificateFactory.getInstance("X.509"); crt = (X509Certificate)cf.generateCertificate(is); } finally { closeSilent(is); } return crt; } public static PrivateKey loadPrivateKey(String fileName) throws IOException, GeneralSecurityException { PrivateKey key = null; InputStream is = null; try { is = fileName.getClass().getResourceAsStream("/" + fileName); BufferedReader br = new BufferedReader(new InputStreamReader(is)); StringBuilder builder = new StringBuilder(); boolean inKey = false; for (String line = br.readLine(); line != null; line = br.readLine()) { if (!inKey) { if (line.startsWith("-----BEGIN ") && line.endsWith(" PRIVATE KEY-----")) { inKey = true; } continue; } else { if (line.startsWith("-----END ") && line.endsWith(" PRIVATE KEY-----")) { inKey = false; break; } builder.append(line); } } // byte[] encoded = DatatypeConverter.parseBase64Binary(builder.toString()); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); KeyFactory kf = KeyFactory.getInstance("RSA"); key = kf.generatePrivate(keySpec); } finally { closeSilent(is); } return key; } public static void closeSilent(final InputStream is) { if (is == null) return; try { is.close(); } catch (Exception ign) {} }
试试这个class。
package groovy; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.KeyFactory; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import javax.crypto.Cipher; import org.apache.commons.codec.binary.Base64; public class RSA { private static String getKey(String filename) throws IOException { // Read key from file String strKeyPEM = ""; BufferedReader br = new BufferedReader(new FileReader(filename)); String line; while ((line = br.readLine()) != null) { strKeyPEM += line + "\n"; } br.close(); return strKeyPEM; } public static RSAPrivateKey getPrivateKey(String filename) throws IOException, GeneralSecurityException { String privateKeyPEM = getKey(filename); return getPrivateKeyFromString(privateKeyPEM); } public static RSAPrivateKey getPrivateKeyFromString(String key) throws IOException, GeneralSecurityException { String privateKeyPEM = key; privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----\n", ""); privateKeyPEM = privateKeyPEM.replace("-----END PRIVATE KEY-----", ""); byte[] encoded = Base64.decodeBase64(privateKeyPEM); KeyFactory kf = KeyFactory.getInstance("RSA"); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(keySpec); return privKey; } public static RSAPublicKey getPublicKey(String filename) throws IOException, GeneralSecurityException { String publicKeyPEM = getKey(filename); return getPublicKeyFromString(publicKeyPEM); } public static RSAPublicKey getPublicKeyFromString(String key) throws IOException, GeneralSecurityException { String publicKeyPEM = key; publicKeyPEM = publicKeyPEM.replace("-----BEGIN PUBLIC KEY-----\n", ""); publicKeyPEM = publicKeyPEM.replace("-----END PUBLIC KEY-----", ""); byte[] encoded = Base64.decodeBase64(publicKeyPEM); KeyFactory kf = KeyFactory.getInstance("RSA"); RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded)); return pubKey; } public static String sign(PrivateKey privateKey, String message) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException { Signature sign = Signature.getInstance("SHA1withRSA"); sign.initSign(privateKey); sign.update(message.getBytes("UTF-8")); return new String(Base64.encodeBase64(sign.sign()), "UTF-8"); } public static boolean verify(PublicKey publicKey, String message, String signature) throws SignatureException, NoSuchAlgorithmException, UnsupportedEncodingException, InvalidKeyException { Signature sign = Signature.getInstance("SHA1withRSA"); sign.initVerify(publicKey); sign.update(message.getBytes("UTF-8")); return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8"))); } public static String encrypt(String rawText, PublicKey publicKey) throws IOException, GeneralSecurityException { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return Base64.encodeBase64String(cipher.doFinal(rawText.getBytes("UTF-8"))); } public static String decrypt(String cipherText, PrivateKey privateKey) throws IOException, GeneralSecurityException { Cipher cipher = Cipher.getInstance("RSA"); cipher.init(Cipher.DECRYPT_MODE, privateKey); return new String(cipher.doFinal(Base64.decodeBase64(cipherText)), "UTF-8"); } } Required jar library "common-codec-1.6"
我想在你的私钥定义中,你应该replace:
X509EncodedKeySpec spec = new X509EncodedKeySpec(decoded);
有:
PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
看看你的openssl
命令:
$openssl **pkcs8** -topk8 -inform PEM -outform PEM -in mykey.pem \ -out private_key.pem -nocrypt
和Javaexception:
Only PCKS8 codification