How to read .pem file to get private and public key

匿名 (未验证) 提交于 2019-12-03 02:15:02

问题:

I am writing a small piece of code which reads public and private key stored in .pem file. I am using the following commands to generate the keys.

Below command to generate pair of key.

   $openssl genrsa -out mykey.pem 2048

This command to generate the private key

$openssl pkcs8 -topk8 -inform PEM -outform PEM -in mykey.pem \     -out private_key.pem -nocrypt

and this command to get the public key.

$ openssl rsa -in mykey.pem -pubout -outform DER -out public_key.der

I have written two methods which reads the private key and public key respectively.

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

I feel like this is a naive way of doing it. I couldn't get any better way of doing it over internet. Can anyone suggest me what is the best way of writing the same code to handle the generic cases. I don' want to use any kind of third party library.
I have very basic knowledge of singing/encrypting and hardly use any java security APIs. So if I am not making sense somewhere then please point out.

回答1:

One option is to use bouncycastle's PEMParser:

Class for parsing OpenSSL PEM encoded streams containing X509 certificates, PKCS8 encoded keys and PKCS7 objects.

In the case of PKCS7 objects the reader will return a CMS ContentInfo object. Public keys will be returned as well formed SubjectPublicKeyInfo objects, private keys will be returned as well formed PrivateKeyInfo objects. In the case of a private key a PEMKeyPair will normally be returned if the encoding contains both the private and public key definition. CRLs, Certificates, PKCS#10 requests, and Attribute Certificates will generate the appropriate BC holder class.

Here is an example of using the Parser test code:

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  
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!