Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 596
Rakesh Avatar asked Aug 03 '12 00:08

Rakesh


People also ask

How do I read a PEM file?

Certificate Decoder A PEM encoded certificate is a block of encoded text that contains all of the certificate information and public key. Another simple way to view the information in a certificate on a Windows machine is to just double-click the certificate file.

Is PEM a public or private key?

Privacy Enhanced Mail (PEM) files are a type of Public Key Infrastructure (PKI) file used for keys and certificates.


2 Answers

Try this 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" 
like image 163
srsajid Avatar answered Oct 10 '22 21:10

srsajid


Java 9+:

private byte[] loadPEM(String resource) throws IOException {     URL url = getClass().getResource(resource);     InputStream in = url.openStream();     String pem = new String(in.readAllBytes(), StandardCharsets.ISO_8859_1);     Pattern parse = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*");     String encoded = parse.matcher(pem).replaceFirst("$1");     return Base64.getMimeDecoder().decode(encoded); }  @Test public void test() throws Exception {     KeyFactory kf = KeyFactory.getInstance("RSA");     CertificateFactory cf = CertificateFactory.getInstance("X.509");     PrivateKey key = kf.generatePrivate(new PKCS8EncodedKeySpec(loadPEM("test.key")));     PublicKey pub = kf.generatePublic(new X509EncodedKeySpec(loadPEM("test.pub")));     Certificate crt = cf.generateCertificate(getClass().getResourceAsStream("test.crt")); } 

Java 8:

replace the in.readAllBytes() call with a call to this:

byte[] readAllBytes(InputStream in) throws IOException {     ByteArrayOutputStream baos= new ByteArrayOutputStream();     byte[] buf = new byte[1024];     for (int read=0; read != -1; read = in.read(buf)) { baos.write(buf, 0, read); }     return baos.toByteArray(); } 

thanks to Daniel for noticing API compatibility issues

like image 36
patrikbeno Avatar answered Oct 10 '22 22:10

patrikbeno