How to select a JOSE / JWT cryptographic algorithm for your application

JavaScript Object Signing and Encryption (JOSE) has adopted an array of standard cryptographic algorithms, including new Edwards-curve algorithms (added in 2017). Which algorithm should you pick to secure JWTs or other objects in your application? This guide will provide you with the basic criteria for making an informed choice, but do make sure to also consult with reputable literature and experts in the field so that nothing critical is missed.

The common data security objectives

Our needs to secure data, such as tokens, typically stem from one or more concerns:

Integrity

Objective: Verify data has not been tampered with

Authenticity

Objective: The origin of the data can be verified

Non-repudiation

Objective: The origin of the data must be verifiable by others

Confidentiality

Objective: Data is kept secret from unauthorised parties and processes

Understanding which security aspect(s) we're after is the first step in selecting an appropriate JOSE algorithm.

Available JOSE algorithm classes

JOSE provides three distinct classes of cryptographic algorithms to cater for the four security objectives, with partially overlapping properties:

Integrity Authentication Non-repudiation Confidentiality
HMAC

Digital signatures
Authenticated encryption

HMAC algorithms: A special super efficient hash (HMAC) for ensuring the integrity and authenticity of data. In order to compute an HMAC you need a secret key.

Digital signatures: Offer the properties of HMAC, plus cryptographic non-repudiation (enabling others than the signer to check the signature's validity). Digital signatures are based on public / private key cryptography. Require a public / private key pair (of type RSA, elliptic curve (EC), or Edwards-curve Octet Key Pair (OKP)).

Authenticated encryption: Encrypt data, while also ensuring its integrity and authenticity (like HMAC). JOSE offers encryption with public / private keys, with secret (shared) keys and with passwords.

1. Hash-based Message Authentication Code (HMAC)

Provide Integrity, Authentication
JOSE format JSON Web Signature (JWS)
Key type Secret key
Algorithms HMAC with SHA-2:
  • HS256
  • HS384
  • HS512
Use cases
  • Stateless sessions stored in browser cookies
  • Email verification codes
  • Session IDs with the ability to differentiate between expired and invalid IDs
  • Tokens where issuer and ultimate consumer is the same party
Notes
  • The HMAC is not a digital signature!
  • Use longer keys / hashes (e.g. HS512) for increased security
  • Keys longer than the hash size don't provide additional security

The HMAC algorithms (with JOSE alg identifiers HS256, HS384 and HS512) are ideal for securing tokens and other information that needs to be sent out or stored externally, in order to be eventually consumed by the issuing application. The key concerns here are ensuring 1) the integrity of the data when we get it back, and 2) that the data was actually produced by us.

A good example is employing HMAC-secured JWTs for generating stateless session cookies. The JWT can include the ID and other information about the logged-in user. When a cookie is received by the web app the HMAC is recomputed and compared to that of the JWT. If the two HMACs don't match we can assume that the cookie has been tampered with, or isn't ours.

Example JWT claims for a stateless session cookie:

{
  "sub"      : "user-12345",
  "email"    : "[email protected]",
  "login_ip" : "172.16.254.1", 
  "exp"      : 1471102267
}

A common misconception is that message authentication codes qualify as digital signatures. They don't! That's because verification requires access to the original secret key used to compute the HMAC, and by its nature you cannot share that key with others without also giving them the ability to generate their own HMACs. If you want non-repudiation use RSA, EC or EdDSA signatures.

2. Digital signatures

Provide Integrity, Authentication, Non-repudiation
JOSE format JSON Web Signature (JWS)
Key type Public / private key pair:
  • RSA
  • EC
  • OKP
Algorithms RSA signature with PKCS #1 and SHA-2:
  • RS256
  • RS384
  • RS512
RSA PSS signature with SHA-2:
  • PS256
  • PS384
  • PS512
EC DSA signature with SHA-2:
  • ES256
  • ES384
  • ES512
  • ES256K
Edwards-curve DSA signature with SHA-2:
  • Ed25519
  • Ed448
Use cases
  • ID tokens (OpenID Connect)
  • Self-contained access tokens (OAuth 2.0)
  • Passing security assertions and tokens between domains
  • Data which integrity and authenticity must be verifiable by others
Notes
  • Keep your private keys secret!
  • The recommended RSA key size is 2048 bits
  • EdDSA signatures offer the best performance

Digital signatures are suited for issuing of tokens, statements, assertions and documents which integrity and authenticity must be verifiable by other parties.

Example uses:

  • Identity tokens issued by an OpenID provider, which a relying party needs to verify in order to sign in a user.

  • Access tokens issued by an OAuth 2.0 server, which the resource servers / web API must verify before serving the request.

Digital signatures work only with public / private keys:

  • The issuer needs to generate a public / private key pair before it can sign JWTs or other objects.

  • The signature is computed with the private key, which must be kept secure at all times, otherwise there is risk of impersonation.

  • The signature of a JWT or JWS object is validated with the public key. The method by which recipients can discover and download the public key are application specific. OpenID Connect servers for example publishe their public keys at a URL in JWK format.

Which digital signature algorithm to choose?

  • If you're looking for broad support, choose RS256. This algorithm is based on RSA PKCS #1, which is still the most widely used standard for public / private key cryptography. Any decent JWT library should support it. RSxxx signatures also take very little CPU time to verify (good for ensuring quick processing of access tokens at resource servers). 2048 bits is the recommended RSA key length.

  • The ESxxx signature algorithms use Elliptic Curve (EC) cryptography. They require shorter keys and produce mush smaller signatures (of equivalent to RSA strength). EC signatures have one disadvantage though: their verification is significantly slower.

  • The new Edxxx algorithms offer the best sign / validate performance mix. Signing in particular is boosted 62x over 2048-bit RSA and 14x over EC DSA with P-265 curve.

We have examples for RSA, EC and EdDSA signed JWTs.

3. Authenticated encryption

Provide Confidentiality, Integrity, Authentication
JOSE format JSON Web Encryption (JWE)
Key type
  • Public / private key pair:
    • RSA
    • EC
    • OKP
  • Secret (shared) key
  • Password
Algorithms Public / private key encryption: Secret (shared) key encryption: Password based encryption:
  • PBES2:
    • PBES2-HS256+A128KW
    • PBES2-HS384+A192KW
    • PBES2-HS512+A256KW
Use cases
  • Signed and encrypted ID tokens (OpenID Connect)
  • Signed and encrypted self-contained access tokens (OAuth 2.0)
  • Encrypted documents and data, with integrity and authenticity check
Notes
  • Keep your private and secret keys secure!
  • The recommended RSA key size is 2048 bits

JOSE provides encryption with the following:

  • A secret key in case you want to encrypt data for yourself. If the secret key is shared with other parties (by some out-of-band mean), they can also encrypt data / decrypt ciphertext with it. Check out the table above for the available secret key encryption algorithms.

  • A public key (RSA, EC or OKP) provided by recipient. OpenID Connect providers for example publish their public keys in JWK format at a discoverable URL. The recipient can then decrypt the JWT / JOSE object with its matching private key. Public / private key cryptography is ideal in situations where communicating a secret key out-of-band is not possible or feasible.

  • A password if you want to encrypt data with some phrase that you can remember.

Encryption in JOSE is always authenticated, meaning that the ciphertext's integrity is protected from tampering. Authenticated encryption thus makes nesting an HMAC JWT inside a JSON Web Encryption (JWE) redundant; use just JWE encryption.

JWE encryption is a "two step" process:

  1. The data, or content, is always encrypted with an AES key (called the Content Encryption Key, or CEK), and each JWT / JWE object uses a different CEK. The Nimbus library will automatically generate this AES key for you, and its length will depend on the enc (encryption method) header parameter (e.g. an "enc":"A128GCM" will cause a 128-bit AES key to be generated). Besides the choice of three AES key lengths (128, 198 and 256), JOSE supports two modes for content encryption: AxxxCBC-HSxxx and AxxxGCM. The AxxxCBC-HSxxx mode is typically the more widely supported.

  2. The second step is encrypting, also called wrapping, the generated AES CEK with the input key, i.e. the secret key, the public key or the password that you provided. This is specified by the alg JWE header parameter. In case you want to skip the second step, and provide the AES CEK directly, choose direct encryption and specify an "alg":"dir" JWE header parameter.

Example JWE header where the content is encrypted with 128-bit AES in GCM mode, while the AES CEK itself is encrypted with a public RSA key (using RSA OAEP encryption):

{
  "alg" : "RSA-OAEP",
  "enc" : "A128GCM"
}

You can check out the example for encrypting a JWT with an RSA public key.

Nested signing and encryption

A signed JWT / JWS object can be additionally encrypted, thus providing integrity, authenticity, non-repudiation and confidentiality to data.

This is achieved by simple nesting (see example):

  1. The JWT is signed with a private RSA, EC or OKP key.

  2. The signed JWT then becomes the payload (plaintext) of a JWE object, which is encrypted with either the public key (RSA, EC, OKP) of the recipient, or with a secret key that has been shared between the two parties.

Processing a nested JWT works backwards:

  1. The JWE object is decrypted with the appropriate key (private key for RSA, EC or OKP, or established secret key).

  2. The extracted payload (plain text) is then parsed as a signed JWT, and verified with the issuer's public key (RSA, EC or OKP).

The Nimbus JOSE+JWT library provides a complete framework for handling nested JWTs.

Algorithm choices in OpenID Connect

The following rules can give you an idea of which ID token algorithms are possible, given a client registration:

  1. A client with a client_secret can receive ID tokens secured with HMAC (where the client_secret serves as the HMAC secret key) or with a signature (RSA, EC or EdDSA). In order to verify an RSA, EC or EdDSA signed ID token the client simply needs to retrieve the matching public key of the OpenID provider (from its JWK set URL).

  2. A client with a client_secret can also receive encrypted ID tokens, where the client_secret is used to derive a secret AES key from it.

  3. Issued client_secrets must be sufficiently long to fit the required secret key length if HMAC is used. For example, a 256 bit client_secret permits HMAC with HS256.

  4. In order for a client to receive RSA or ECDH encrypted ID tokens, it must have a public RSA, EC or OKP key registered with the OpenID provider.

  5. OpenID Connect also permits clients without a client_secret. Such clients need to register a public RSA, EC or OKP key with the OpenID provider, and use that key to authenticate (via JWT) at the token endpoint. The ID token may be encrypted to that public key as explained above.


comments powered by Disqus