View Source Examples: Key Generation

There are four key generation methods described below for each key type:

EC

The three curve types defined in the JWA RFC 7518 for the EC key type are:

  1. "P-256" (openssl curve secp256r1)
  2. "P-384" (openssl curve secp384r1)
  3. "P-521" (openssl curve secp521r1)

Method 1

The basic formula for key generation is openssl ecparam -name CURVE -genkey -noout -out FILE, for example:

openssl ecparam -name secp256r1 -genkey -noout -out ec-secp256r1.pem
openssl ecparam -name secp384r1 -genkey -noout -out ec-secp384r1.pem
openssl ecparam -name secp521r1 -genkey -noout -out ec-secp521r1.pem

The PEM files can then be read using jose_jwk:from_pem_file/1 or JOSE.JWK.from_pem_file/1:

jwk = JOSE.JWK.from_pem_file("ec-secp256r1.pem")

Method 2

The curve names are the same as the ones for OpenSSL.

jwk = JOSE.JWK.generate_key(:secp256r1)
jwk = JOSE.JWK.generate_key(:secp384r1)
jwk = JOSE.JWK.generate_key(:secp521r1)

# Alternative explicit syntax:
jwk = JOSE.JWK.generate_key({:ec, :secp256r1})
jwk = JOSE.JWK.generate_key({:ec, :secp384r1})
jwk = JOSE.JWK.generate_key({:ec, :secp521r1})

# Alternative curve alias syntax:
jwk = JOSE.JWK.generate_key({:ec, "P-256"})
jwk = JOSE.JWK.generate_key({:ec, "P-384"})
jwk = JOSE.JWK.generate_key({:ec, "P-521"})

Keys may also be generated based on other keys. The new key will use the same curve as the supplied key.

old_jwk = JOSE.JWK.from_pem_file("ec-secp256r1.pem")
new_jwk = JOSE.JWK.generate_key(old_jwk)

Method 3

If you have a JWE header with an "epk" field, a new key will be generated based on the same key type of the "epk". Otherwise, the P-521 curve will be used.

# Based on the "epk" field.
epk = JOSE.JWK.generate_key({:ec, "P-256"})
jwe = JOSE.JWE.from_map(%{"alg" => "ECDH-ES", "enc" => "A128GCM", "epk" => epk |> JOSE.JWK.to_map |> elem(1)})
jwk = JOSE.JWE.generate_key(jwe)

# Otherwise, defaults to "P-521".
jwk = JOSE.JWE.generate_key(%{"alg" => "ECDH-ES", "enc" => "A128GCM"})

Method 4

If you have a JWS header with one of the ECDSA signature algorithms specified, a corresponding EC key will be generated with the correct curve for the signature type.

jwk_ec256 = JOSE.JWS.generate_key(%{"alg" => "ES256"})
jwk_ec384 = JOSE.JWS.generate_key(%{"alg" => "ES384"})
jwk_ec521 = JOSE.JWS.generate_key(%{"alg" => "ES512"})

oct

This key type is simply an octet or byte sequence (see RFC 7518 Section 6.4).

Method 1

The basic formula for generating a random octet sequence is openssl rand -out FILE BYTE_SIZE, for example:

openssl rand -out oct-128-bit.bin 16

The binary file can then be read using jose_jwk:from_oct_file/1 or JOSE.JWK.from_oct_file/1:

jwk = JOSE.JWK.from_oct_file("oct-128-bit.bin")

Method 2

Calling either of these functions with an integer will generate a random octet sequence.

jwk = JOSE.JWK.generate_key(16)

# Alternative explicit syntax:
jwk = JOSE.JWK.generate_key({:oct, 16})

Keys may also be generated based on other keys. The new key will use the same byte size as the supplied key.

old_jwk = JOSE.JWK.from_oct_file("oct-128-bit.bin")
new_jwk = JOSE.JWK.generate_key(old_jwk)

Method 3

If you have a JWE header with an "alg" field that requires a symmetric key, a new oct key will be generated based on the byte size required of "alg" and/or "enc".

jwk_oct16 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A128GCM"})
jwk_oct24 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A192GCM"})
jwk_oct32 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A256GCM"})
jwk_oct32 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A128CBC-HS256"})
jwk_oct48 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A192CBC-HS384"})
jwk_oct64 = JOSE.JWE.generate_key(%{"alg" => "dir", "enc" => "A256CBC-HS512"})

Method 4

If you have a JWS header with an "alg" field that requires a symmetric key, a new oct key will be generated based on the byte size recommended for "alg".

jwk_oct32 = JOSE.JWS.generate_key(%{"alg" => "HS256"})
jwk_oct48 = JOSE.JWS.generate_key(%{"alg" => "HS384"})
jwk_oct64 = JOSE.JWS.generate_key(%{"alg" => "HS512"})

OKP

This key type is an octet key pair with an associated curve (see draft-ietf-jose-cfrg-curves).

Method 1

NOTE: Only Ed25519 is currently supported by ssh-keygen.

The basic formula for generating a octet key pair is ssh-keygen -t TYPE -f FILE, for example:

ssh-keygen -t ed25519 -f ed25519

The private key file can then be read using jose_jwk:from_openssh_key_file/1 or JOSE.JWK.from_openssh_key_file/1:

jwk = JOSE.JWK.from_openssh_key_file("ed25519")

Method 2

Calling either of these functions with a specified curve will generate an octet key pair. You may also specify the secret portion of the key after the curve.

% Curve25519
jwk_Ed25519   = JOSE.JWK.generate_key({:okp, :Ed25519})
jwk_Ed25519ph = JOSE.JWK.generate_key({:okp, :Ed25519ph})
jwk_X25519    = JOSE.JWK.generate_key({:okp, :X25519})

% Curve448
jwk_Ed448   = JOSE.JWK.generate_key({:okp, :Ed448})
jwk_Ed448ph = JOSE.JWK.generate_key({:okp, :Ed448ph})
jwk_X448    = JOSE.JWK.generate_key({:okp, :X448})

Keys may also be generated based on other keys. The new key will use the same curve as the supplied key.

old_jwk = JOSE.JWK.from_openssh_key_file("ed25519")
new_jwk = JOSE.JWK.generate_key(old_jwk)

Method 3

If you have a JWE header with an "epk" field, a new key will be generated based on the same key type of the "epk".

# Based on the "epk" field.
epk = JOSE.JWK.generate_key({:okp, :X25519})
jwe = JOSE.JWE.from_map(%{"alg" => "ECDH-ES", "enc" => "A128GCM", "epk" => epk |> JOSE.JWK.to_map |> elem(1)})
jwk = JOSE.JWE.generate_key(jwe)

Method 4

If you have a JWS header with one of the EdDSA signature algorithms specified, a corresponding OKP key will be generated with the correct curve for the signature type.

jwk_Ed25519   = JOSE.JWS.generate_key(%{"alg" => "Ed25519"})
jwk_Ed25519ph = JOSE.JWS.generate_key(%{"alg" => "Ed25519ph"})
jwk_Ed448     = JOSE.JWS.generate_key(%{"alg" => "Ed448"})
jwk_Ed448ph   = JOSE.JWS.generate_key(%{"alg" => "Ed448ph"})
# EdDSA defaults to Ed25519
jwk_EdDSA     = JOSE.JWS.generate_key(%{"alg" => "EdDSA"})

RSA

Both two-prime and multi-prime RSA keys are supported by RFC 7518 Section 6.3, but currently only two-prime RSA keys can be generated by OpenSSL-based generators.

See test/jose_SUITE_data/rsa-multi.pem for an example multi-prime RSA key.

Method 1

The basic formula for generating a RSA key is openssl genrsa -out FILE BIT_SIZE, for example:

openssl genrsa -out rsa-2048.pem 2048

The PEM file can then be read using jose_jwk:from_pem_file/1 or JOSE.JWK.from_pem_file/1:

jwk = JOSE.JWK.from_pem_file("rsa-2048.pem")

Method 2

Note: RSA key generation is dependent on cutkey, which must be included as a dependency. An error will be thrown if cutkey is not found.

The modulus bit size is the only required argument. Optionally, you may specify the public exponent as the second argument (default is 65537).

jwk = JOSE.JWK.generate_key({:rsa, 2048})

# Alternative explicit syntax with public exponent:
jwk = JOSE.JWK.generate_key({:rsa, 4096, 65537})

Keys may also be generated based on other keys. The new key will use the same modulus size and public exponent as the supplied key.

old_jwk = JOSE.JWK.from_pem_file("rsa-2048.pem")
new_jwk = JOSE.JWK.generate_key(old_jwk)

Method 3

If you have a JWE header with an "alg" field that requires an asymmetric RSA key, a new RSA key will be generated. 2048-bit keys are generated in these cases.

jwk_rsa1_5      = JOSE.JWE.generate_key(%{"alg" => "RSA1_5", "enc" => "A128GCM"})
jwk_rsa_oaep    = JOSE.JWE.generate_key(%{"alg" => "RSA-OAEP", "enc" => "A128GCM"})
jwk_rsa_oaep256 = JOSE.JWE.generate_key(%{"alg" => "RSA-OAEP-256", "enc" => "A128GCM"})

Method 4

If you have a JWS header with one of the RSA PKCS1 or PSS signature algorithms specified, a corresponding RSA key will be generated with a recommended modulus size based on the digest type.

# RS256, RS384, RS512
jwk_rsa2048 = JOSE.JWS.generate_key(%{"alg" => "RS256"})
jwk_rsa3072 = JOSE.JWS.generate_key(%{"alg" => "RS384"})
jwk_rsa4096 = JOSE.JWS.generate_key(%{"alg" => "RS512"})

# PS256, PS384, PS512
jwk_rsa2048 = JOSE.JWS.generate_key(%{"alg" => "PS256"})
jwk_rsa3072 = JOSE.JWS.generate_key(%{"alg" => "PS384"})
jwk_rsa4096 = JOSE.JWS.generate_key(%{"alg" => "PS512"})