How to generate RSA and EC keys with OpenSSL

How to generate keys in PEM format using the OpenSSL command line tools?

RSA keys

The JOSE standard recommends a minimum RSA key size of 2048 bits.

To generate a 2048-bit RSA private + public key pair for use in RSxxx and PSxxx signatures:

openssl genrsa 2048 -out rsa-2048bit-key-pair.pem 

Elliptic Curve keys

To generate an EC key pair the curve designation must be specified. Note that JOSE ESxxx signatures require P-256, P-384 and P-521 curves (see their corresponding OpenSSL identifiers below).

Elliptic Curve private + public key pair for use with ES256 signatures:

openssl ecparam -genkey -name prime256v1 -noout -out ec256-key-pair.pem

Elliptic Curve private + public key pair for use with ES384 signatures:

openssl ecparam -genkey -name secp384r1 -noout -out ec384-key-pair.pem

Elliptic Curve private + public key pair for use with ES512 signatures:

openssl ecparam -genkey -name secp521r1 -noout -out ec512-key-pair.pem

PEM key parsing in Java

The BouncyCastle library provides a simple utility to parse PEM-encoded keys in Java, to use them for JWS or JWE later.

For Maven you should include the following BouncyCastle dependencies (where 1.52 is the latest stable version as of May 2015):

 <dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.52</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk15on</artifactId>
    <version>1.52</version>
</dependency>

Example parsing of an PEM-encoded EC key in Java:

import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.security.KeyPair;
import java.security.Security;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMKeyPair;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import com.nimbusds.jose.*;


// Load BouncyCastle as JCA provider
Security.addProvider(new BouncyCastleProvider());

// Parse the EC key pair
PEMParser pemParser = new PEMParser(new InputStreamReader(new FileInputStream("ec512-key-pair.pem")));
PEMKeyPair pemKeyPair = (PEMKeyPair)pemParser.readObject();

// Convert to Java (JCA) format
JcaPEMKeyConverter converter = new JcaPEMKeyConverter();
KeyPair keyPair = converter.getKeyPair(pemKeyPair);
pemParser.close();

// Get private + public EC key
ECPrivateKey privateKey = (ECPrivateKey)keyPair.getPrivate();
ECPublicKey publicKey = (ECPublicKey)keyPair.getPublic();

// Sign test
JWSObject jwsObject = new JWSObject(new JWSHeader(JWSAlgorithm.ES512), new Payload("Hello world!"));
jwsObject.sign(new ECDSASigner(privateKey));

// Serialise
String compactJWS = jwsObject.serialize();

// Verify test
jwsObject = JWSObject.parse(compactJWS);
assertTrue(jwsObject.verify(new ECDSAVerifier(publicKey)));