Key Generation
There are four key generation methods described below for each key type:
- Method 1: OpenSSL
- Method 2: JOSE::JWK.generate_key
- Method 3: JOSE::JWE.generate_key
- Method 4: JOSE::JWS.generate_key
EC
The three curve types defined in the JWA RFC 7518 for the EC
key type are:
"P-256"
(openssl curvesecp256r1
)"P-384"
(openssl curvesecp384r1
)"P-521"
(openssl curvesecp521r1
)
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:
jwk = JOSE::JWK.from_pem_file("ec-secp256r1.pem")
Method 2
The curve names are almost the same as the ones for OpenSSL.
jwk = JOSE::JWK.generate_key([:ec, 'prime256v1'])
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.to_map})
jwk = jwe.generate_key
# 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:
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([: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:
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.to_map})
jwk = jwe.generate_key
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"})
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. Ruby does not support multi-prime RSA at this time.
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:
jwk = JOSE::JWK.from_pem_file("rsa-2048.pem")
Method 2
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"})