Load RSA public key from file

JavaOpensslRsa

Java Problem Overview


I've generated a private key with:

openssl genrsa [-out file] –des3

After this I've generated a public key with:

openssl rsa –pubout -in private.key [-out file]

I want to sign some messages with my private key, and verify some other messages with my public key, using code like this:

public String sign(String message) throws SignatureException{
    try {
        Signature sign = Signature.getInstance("SHA1withRSA");
        sign.initSign(privateKey);
        sign.update(message.getBytes("UTF-8"));
        return new String(Base64.encodeBase64(sign.sign()),"UTF-8");
    } catch (Exception ex) {
        throw new SignatureException(ex);
    }
}

public boolean verify(String message, String signature) throws SignatureException{
    try {
        Signature sign = Signature.getInstance("SHA1withRSA");
        sign.initVerify(publicKey);
        sign.update(message.getBytes("UTF-8"));
        return sign.verify(Base64.decodeBase64(signature.getBytes("UTF-8")));
    } catch (Exception ex) {
        throw new SignatureException(ex);
    }
}

I found a solution to convert my private key to PKCS8 format and load it. It works with some code like this:

public PrivateKey getPrivateKey(String filename) 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();
    PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf =
            KeyFactory.getInstance("RSA");
    return kf.generatePrivate(spec);
}

And finally my question is: How do I load my RSA Public Key from a file?

I think maybe I need to convert my public key file to x509 format, and use X509EncodedKeySpec. But how can I do this?

Java Solutions


Solution 1 - Java

Below is the relevant information from the link which Zaki provided.

> Generate a 2048-bit RSA private key > > $ openssl genrsa -out private_key.pem 2048 > > Convert private Key to PKCS#8 format (so Java can read it) > > $ openssl pkcs8 -topk8 -inform PEM -outform DER -in private_key.pem -out private_key.der -nocrypt > > Output public key portion in DER format (so Java can read it) > > $ openssl rsa -in private_key.pem -pubout -outform DER -out public_key.der

Private key

import java.nio.file.*;
import java.security.*;
import java.security.spec.*;

public class PrivateKeyReader {

  public static PrivateKey get(String filename)
    throws Exception {

    byte[] keyBytes = Files.readAllBytes(Paths.get(filename));

    PKCS8EncodedKeySpec spec =
      new PKCS8EncodedKeySpec(keyBytes);
    KeyFactory kf = KeyFactory.getInstance("RSA");
    return kf.generatePrivate(spec);
  }
}

Public key

import java.nio.file.*;
import java.security.*;
import java.security.spec.*;

public class PublicKeyReader {

  public static PublicKey get(String filename)
	throws Exception {
	
    byte[] keyBytes = Files.readAllBytes(Paths.get(filename));

	X509EncodedKeySpec spec =
	  new X509EncodedKeySpec(keyBytes);
	KeyFactory kf = KeyFactory.getInstance("RSA");
	return kf.generatePublic(spec);
  }
}

Solution 2 - Java

This program is doing almost everything with Public and private keys. The der format can be obtained but saving raw data ( without encoding base64). I hope this helps programmers.

import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import sun.security.pkcs.PKCS8Key;
import sun.security.pkcs10.PKCS10;
import sun.security.x509.X500Name;

import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;



/**
 * @author Desphilboy
 * DorOd bar shomA barobach
 *
 */
public class csrgenerator {
	
	private static PublicKey publickey= null;
	private static PrivateKey privateKey=null;
	//private static PKCS8Key privateKey=null;
	private static KeyPairGenerator kpg= null;
	private static ByteArrayOutputStream bs =null;
	private static csrgenerator thisinstance;
	private KeyPair keypair;
	private static PKCS10 pkcs10;
	private String signaturealgorithm= "MD5WithRSA";
	
	public String getSignaturealgorithm() {
		return signaturealgorithm;
	}



	public void setSignaturealgorithm(String signaturealgorithm) {
		this.signaturealgorithm = signaturealgorithm;
	}



	private csrgenerator() {
        try {
           kpg = KeyPairGenerator.getInstance("RSA");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            System.out.print("No such algorithm RSA in constructor csrgenerator\n");
        }
        kpg.initialize(2048);
        keypair = kpg.generateKeyPair();
        publickey = keypair.getPublic();
        privateKey = keypair.getPrivate();
    }
	
	
	
	/** Generates a new key pair 
    *
    * @param int bits 
    *   this is the number of bits in modulus must be 512, 1024, 2048  or so on 
    */
	public KeyPair generateRSAkys(int bits)
	{
		  kpg.initialize(bits);
	        keypair = kpg.generateKeyPair();
	        publickey = keypair.getPublic();
	        privateKey = keypair.getPrivate();
	        KeyPair dup= keypair;
	 return dup;
	}
	
	 public static csrgenerator getInstance() {
	        if (thisinstance == null)
	        	thisinstance = new csrgenerator();
	        return thisinstance;
	    }
	 
	 
	 /**
	  *  Returns a CSR as string  
	  * @param cn  Common Name
	  * @param OU  Organizational Unit 
	  * @param Org  Organization
	  * @param LocName Location name
	  * @param Statename  State/Territory/Province/Region
	  * @param Country    Country
	  * @return     returns  csr as string.
	  * @throws Exception
	  */
	 public String getCSR(String commonname, String organizationunit, String organization,String localname, String statename, String country ) throws Exception {
	        byte[] csr = generatePKCS10(commonname, organizationunit, organization, localname, statename, country,signaturealgorithm);
	        return new String(csr);
	    }
	 
	 /** This function generates a new Certificate 
	  * Signing Request. 
     *
     * @param CN
     *            Common Name, is X.509 speak for the name that distinguishes
     *            the Certificate best, and ties it to your Organization
     * @param OU
     *            Organizational unit
     * @param O
     *            Organization NAME
     * @param L
     *            Location
     * @param S
     *            State
     * @param C
     *            Country
     * @return    byte stream of generated request
     * @throws Exception
     */
    private static byte[] generatePKCS10(String CN, String OU, String O,String L, String S, String C,String sigAlg) throws Exception {
        // generate PKCS10 certificate request
        
        pkcs10 = new PKCS10(publickey);
       Signature   signature = Signature.getInstance(sigAlg);
        signature.initSign(privateKey);
        // common, orgUnit, org, locality, state, country
        //X500Name(String commonName, String organizationUnit,String organizationName,Local,State, String country)
        X500Name x500Name = new X500Name(CN, OU, O, L, S, C);
        pkcs10.encodeAndSign(x500Name,signature);
        bs = new ByteArrayOutputStream();
        PrintStream ps = new PrintStream(bs);
        pkcs10.print(ps);
        byte[] c = bs.toByteArray();
        try {
            if (ps != null)
                ps.close();
            if (bs != null)
                bs.close();
        } catch (Throwable th) {
        }
        return c;
    }
	 
    public  PublicKey getPublicKey() {
        return publickey;
    }
    
    
    
    
    /**
     * @return
     */
    public PrivateKey getPrivateKey() {
        return privateKey;
    }

    /**
     * saves private key to a file
     * @param filename
     */
    public  void SavePrivateKey(String filename)
    {
    	PKCS8EncodedKeySpec pemcontents=null;
    	pemcontents= new PKCS8EncodedKeySpec( privateKey.getEncoded());
    	PKCS8Key pemprivatekey= new  PKCS8Key( );
    	try {
			pemprivatekey.decode(pemcontents.getEncoded());
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	File file=new File(filename);
    	try {
        		
			file.createNewFile();
			FileOutputStream fos=new FileOutputStream(file);
			fos.write(pemprivatekey.getEncoded());
			fos.flush();
			fos.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    	
    	

    }
    


    /**
     * Saves Certificate Signing Request to a file;
     * @param filename  is a String containing full path to the file which will be created containing the CSR.
     */
    public void SaveCSR(String filename)
    {
    	FileOutputStream fos=null;
    	PrintStream ps=null;
		File file;
		try {
 
			file = new File(filename);
			file.createNewFile();
			fos = new FileOutputStream(file);
			ps= new PrintStream(fos);
		}catch (IOException e)
		{
			System.out.print("\n could not open the file "+ filename);
		}
		
		try {
			try {
				pkcs10.print(ps);
			} catch (SignatureException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			ps.flush();
			ps.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			System.out.print("\n cannot write to the file "+ filename);
			e.printStackTrace();
			
		}
		
        }
    
    
	/**
	 * Saves both public key and private  key to file names specified
	 * @param fnpub  file name of public key
	 * @param fnpri  file name of private key
	 * @throws IOException
	 */
	public static void SaveKeyPair(String fnpub,String fnpri) throws IOException { 
 
// Store Public Key.
X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
publickey.getEncoded());
FileOutputStream fos = new FileOutputStream(fnpub);
fos.write(x509EncodedKeySpec.getEncoded());
fos.close();
 
// Store Private Key.
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(privateKey.getEncoded());
fos = new FileOutputStream(fnpri);
fos.write(pkcs8EncodedKeySpec.getEncoded());
fos.close();
}
    
	
	/**
	 * Reads a Private Key from a pem base64 encoded file.
	 * @param filename name of the file to read.
	 * @param algorithm Algorithm is usually "RSA"
	 * @return returns the privatekey which is read from the file;
	 * @throws Exception
	 */
	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-----", "");
	      privKeyPEM = privKeyPEM.replace("-----END PRIVATE KEY-----", "");
	      //System.out.println("Private key\n"+privKeyPEM);

	      BASE64Decoder b64=new BASE64Decoder();
	      byte[] decoded = b64.decodeBuffer(privKeyPEM);

	      PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(decoded);
	      KeyFactory kf = KeyFactory.getInstance(algorithm);
	      return kf.generatePrivate(spec);
	      }
	
	
	
	/**
	 * Saves the private key to a pem file.
	 * @param filename  name of the file to write the key into 
	 * @param key the Private key to save.
	 * @return  String representation of the pkcs8 object.
	 * @throws Exception
	 */
	public  String  SavePemPrivateKey(String filename) throws Exception {
		PrivateKey key=this.privateKey;
	      File f = new File(filename);
	      FileOutputStream fos = new FileOutputStream(f);
	      DataOutputStream dos = new DataOutputStream(fos);
	      
	      
	      byte[] keyBytes = key.getEncoded();
	      PKCS8Key pkcs8= new PKCS8Key();
	      pkcs8.decode(keyBytes);
	      byte[] b=pkcs8.encode();
	      
	      BASE64Encoder b64=new BASE64Encoder();
	      String  encoded = b64.encodeBuffer(b);
	      
	      encoded= "-----BEGIN PRIVATE KEY-----\r\n" + encoded + "-----END PRIVATE KEY-----";
	    		  
	     dos.writeBytes(encoded);
	     dos.flush();
	     dos.close();
	     
	      //System.out.println("Private key\n"+privKeyPEM);
	    return pkcs8.toString();
      
	      }
	
	
	/**
	 * Saves a public key to a base64 encoded pem file
	 * @param filename  name of the file 
	 * @param key public key to be saved 
	 * @return string representation of the pkcs8 object.
	 * @throws Exception
	 */
	public  String  SavePemPublicKey(String filename) throws Exception {
	    PublicKey key=this.publickey;  
		File f = new File(filename);
	      FileOutputStream fos = new FileOutputStream(f);
	      DataOutputStream dos = new DataOutputStream(fos);
	      
	      
	      byte[] keyBytes = key.getEncoded();
	      BASE64Encoder b64=new BASE64Encoder();
	      String  encoded = b64.encodeBuffer(keyBytes);
	      
	      encoded= "-----BEGIN PUBLIC KEY-----\r\n" + encoded + "-----END PUBLIC KEY-----";
	    		  
	     dos.writeBytes(encoded);
	     dos.flush();
	     dos.close();
	     
	      //System.out.println("Private key\n"+privKeyPEM);
	  return  encoded.toString();
    
	      }
	
	
	
	

	   /**
	 * reads a public key from a file
	 * @param filename name of the file to read
	 * @param algorithm is usually RSA
	 * @return the read public key
	 * @throws Exception
	 */
	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-----", "");


	      BASE64Decoder b64=new BASE64Decoder();
	      byte[] decoded = b64.decodeBuffer(publicKeyPEM);

	      X509EncodedKeySpec spec =
	            new X509EncodedKeySpec(decoded);
	      KeyFactory kf = KeyFactory.getInstance(algorithm);
	      return kf.generatePublic(spec);
	      }
	
	
	
 
    public static void main(String[] args) throws Exception {
        csrgenerator gcsr = csrgenerator.getInstance();
        gcsr.setSignaturealgorithm("SHA512WithRSA");
        System.out.println("Public Key:\n"+gcsr.getPublicKey().toString());
        
        System.out.println("Private Key:\nAlgorithm: "+gcsr.getPrivateKey().getAlgorithm().toString());
        System.out.println("Format:"+gcsr.getPrivateKey().getFormat().toString());
        System.out.println("To String :"+gcsr.getPrivateKey().toString());
        System.out.println("GetEncoded :"+gcsr.getPrivateKey().getEncoded().toString());
        BASE64Encoder encoder= new BASE64Encoder();
        String s=encoder.encodeBuffer(gcsr.getPrivateKey().getEncoded());
        System.out.println("Base64:"+s+"\n");
        
        String csr = gcsr.getCSR( "[email protected]","baxshi az xodam", "Xodam","PointCook","VIC" ,"AU");
        System.out.println("CSR Request Generated!!");
        System.out.println(csr);
        gcsr.SaveCSR("c:\\testdir\\javacsr.csr");
        String p=gcsr.SavePemPrivateKey("c:\\testdir\\java_private.pem");
        System.out.print(p);
        p=gcsr.SavePemPublicKey("c:\\testdir\\java_public.pem");
        privateKey= gcsr.getPemPrivateKey("c:\\testdir\\java_private.pem", "RSA");
        BASE64Encoder encoder1= new BASE64Encoder();
        String s1=encoder1.encodeBuffer(gcsr.getPrivateKey().getEncoded());
        System.out.println("Private Key in Base64:"+s1+"\n");
        System.out.print(p);
        
        
    }
 
    }
 
    
    

Solution 3 - Java

Once you have your key stored in a PEM file, you can read it back easily using PemObject and PemReader classes provided by BouncyCastle, as shown in this this tutorial.

Create a PemFile class that encapsulates file handling:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;

import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;

public class PemFile {

	private PemObject pemObject;

	public PemFile(String filename) throws FileNotFoundException, IOException {
		PemReader pemReader = new PemReader(new InputStreamReader(
				new FileInputStream(filename)));
		try {
			this.pemObject = pemReader.readPemObject();
		} finally {
			pemReader.close();
		}
	}

	public PemObject getPemObject() {
		return pemObject;
	}
}

Then instantiate private and public keys as usual:

import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import org.apache.log4j.Logger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Main {

	protected final static Logger LOGGER = Logger.getLogger(Main.class);

	public final static String RESOURCES_DIR = "src/main/resources/rsa-sample/";

	public static void main(String[] args) throws FileNotFoundException,
			IOException, NoSuchAlgorithmException, NoSuchProviderException {
		Security.addProvider(new BouncyCastleProvider());
		LOGGER.info("BouncyCastle provider added.");

		KeyFactory factory = KeyFactory.getInstance("RSA", "BC");
		try {
			PrivateKey priv = generatePrivateKey(factory, RESOURCES_DIR
					+ "id_rsa");
			LOGGER.info(String.format("Instantiated private key: %s", priv));

			PublicKey pub = generatePublicKey(factory, RESOURCES_DIR
					+ "id_rsa.pub");
			LOGGER.info(String.format("Instantiated public key: %s", pub));
		} catch (InvalidKeySpecException e) {
			e.printStackTrace();
		}
	}

	private static PrivateKey generatePrivateKey(KeyFactory factory,
			String filename) throws InvalidKeySpecException,
			FileNotFoundException, IOException {
		PemFile pemFile = new PemFile(filename);
		byte[] content = pemFile.getPemObject().getContent();
		PKCS8EncodedKeySpec privKeySpec = new PKCS8EncodedKeySpec(content);
		return factory.generatePrivate(privKeySpec);
	}

	private static PublicKey generatePublicKey(KeyFactory factory,
			String filename) throws InvalidKeySpecException,
			FileNotFoundException, IOException {
		PemFile pemFile = new PemFile(filename);
		byte[] content = pemFile.getPemObject().getContent();
		X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(content);
		return factory.generatePublic(pubKeySpec);
	}
}

Hope this helps.

Solution 4 - Java

Below code works absolutely fine to me and working. This code will read RSA private and public key though java code. You can refer to http://snipplr.com/view/18368/

import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
    
public class Demo {
    public static final String PRIVATE_KEY="/home/user/private.der";
    public static final String PUBLIC_KEY="/home/user/public.der";

    public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
        //get the private key
        File file = new File(PRIVATE_KEY);
        FileInputStream fis = new FileInputStream(file);
        DataInputStream dis = new DataInputStream(fis);

        byte[] keyBytes = new byte[(int) file.length()];
        dis.readFully(keyBytes);
        dis.close();

        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
    	KeyFactory kf = KeyFactory.getInstance("RSA");
    	RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(spec);
    	System.out.println("Exponent :" + privKey.getPrivateExponent());
    	System.out.println("Modulus" + privKey.getModulus());

    	//get the public key
    	File file1 = new File(PUBLIC_KEY);
    	FileInputStream fis1 = new FileInputStream(file1);
    	DataInputStream dis1 = new DataInputStream(fis1);
    	byte[] keyBytes1 = new byte[(int) file1.length()];
    	dis1.readFully(keyBytes1);
    	dis1.close();

    	X509EncodedKeySpec spec1 = new X509EncodedKeySpec(keyBytes1);
    	KeyFactory kf1 = KeyFactory.getInstance("RSA");
    	RSAPublicKey pubKey = (RSAPublicKey) kf1.generatePublic(spec1);

    	System.out.println("Exponent :" + pubKey.getPublicExponent());
        System.out.println("Modulus" + pubKey.getModulus());
    }
}

Solution 5 - Java

@Value("${spring.security.oauth2.resourceserver.jwt.key-value}")
RSAPublicKey key;

key-value can be uri (i.e. "classpath:keys/pub.pcks8.pem") or pem content.

you must include the following deps:

compile project(':spring-security-config')
compile project(':spring-security-oauth2-jose')
compile project(':spring-security-oauth2-resource-server')

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionalexey_efimovView Question on Stackoverflow
Solution 1 - JavajdhurstView Answer on Stackoverflow
Solution 2 - JavaDesphilboyView Answer on Stackoverflow
Solution 3 - JavatxedoView Answer on Stackoverflow
Solution 4 - JavaPAAView Answer on Stackoverflow
Solution 5 - JavaSimon LogicView Answer on Stackoverflow