JCA algorithm support

The Nimbus JOSE + JWT library uses the standard Java Cryptography Architecture API (JCA) to access cryptographic primitives.

The Java runtime comes with several internal providers of such primitives, such as the "SunRsaSign" provider for RSA signatures or the "SunEC" provider for common elliptic curve cryptography. Alternative or additional providers can be plugged in, via the Java Service Provider (SPI) facility for dynamic loading of API implementations. The JCA API can also be used to access cryptographic primitives in devices such as hardware security modules and smart cards. In that case the provider needs to include an appropriate OS-specific driver to talk to the device.

JOSE algorithm support in Java

The cryptographic providers in stock Java 8 and later support all standard JOSE algorithms listed in RFC 7518.

In older Java versions or Android runtimes some algorithms may not be available, which will result in a JOSEException. For instance, PS256 in JWS is not supported in the Java 7 cryptographic provider for RSA signatures. If you are in a situation where the Java runtime doesn't support a JOSE algorithm you need to install an additional JCA provider (library) that can handle it. The open source BouncyCastle is a popular choice for that.

Use the table below to check if a JOSE algorithm is supported by your Java runtime.

BouncyCastle

BouncyCastle is an open source Java library which implements a wide array of cryptographic algorithms, and where possible, they are made available via the standard JCA provider interface.

In terms of JOSE algorithm support, BouncyCastle can handle all those that are not covered out-of-the-box in Java 7.

How do you set up the BouncyCastle JCA provider in your application?

First, add a dependency to BouncyCastle 1.68 or a newer stable version in your project. If you use Maven:

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

Then, load the BouncyCastle JCA provider and add it to the list of the available providers in your Java runtime:

import java.security.Provider;
import java.security.Security;
import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;

Provider bc = BouncyCastleProviderSingleton.getInstance();
Security.addProvider(bc);

That's it!

Setting BouncyCastle globally may not be always feasible. The Nimbus JOSE+JWT library allows a JCA provider to be set for a particular signer, verifier, encrypter or decrypter instance, like this:

RSASSASigner signer = new RSASSASigner(privateKey);
signer.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());

RSASSAVerifier verifier = new RSASSAVerifier(publicKey);
verifier.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());

BouncyCastle for Android

Android comes with a stock shadowed BouncyCastle JCA provider which may be oudated or cut down in features depending on the Android version. If your Android application is getting JCA related runtime issues, such as missing API or cipher exceptions, there are two possible solutions:

  1. Install an independent BouncyCastle JAR under a different JCA provider name. The MyBC utility can package a BouncyCastle JAR with a custom JCA provider name, package prefix and groupId for Maven.

  2. Replace the stock BouncyCastle JCA provider with one imported via a direct dependency. Use to singleton utility to make sure the BC provider doesn't get loaded more than once, which can lead to significant memory leaks.

    import java.security.Provider;
    import java.security.Security;
    import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
    
    Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    Security.addProvider(BouncyCastleProviderSingleton.getInstance());
    

BouncyCastle FIPS

The BouncyCastle project has also devised and certified a FIPS 140-2, Level 1 compliant JCA provider.

Make sure you use the most recent stable version, at the of writing this that's 1.0.2:

<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bc-fips</artifactId>
    <version>1.0.2</version>
</dependency>

Note, this provider must not be loaded together with the regular BouncyCastle provider, because their package and classes names will collide!

JWS and JWE algorithm support

The following table lists the JOSE algorithm support by the Java 7, Java 8 and BouncyCastle JCA providers.

Algorithm family Java 7 Java 8 Bouncy Castle
JWS alg
HS256, HS384, HS512
RS256, RS384, RS512
PS256, PS384, PS512
ES256, ES384, ES512, ES256K
JWE alg
RSA1_5
RSA-OAEP, RSA-OAEP-256
A128KW, A192KW, A256KW
ECDH-ES, ECDH-ES+A128KW, ECDH-ES+A192KW, ECDH-ES+A256KW
A128GCMKW, A192GCMKW, A256GCMKW
PBES2-HS256+A128KW, PBES2-HS384+A192KW, PBES2-HS512+A256KW
JWE enc
A128CBC-HS256, A192CBC-HS384, A256CBC-HS512
A128GCM, A192GCM, A256GCM
A128CBC+HS256, A256CBC+HS512 (deprecated)

Checking JOSE algorithm support programmatically

Version 4.3 of the library introduced a simple utility called JCASupport for checking whether a given JWS or JWE algorithm is supported by a JCA provider. It also works with hardware devices.

Example:

To check if the RSA-PSS signature algorithm PS256 is supported by the available JCA providers:

JCASupport.isSupported(JWSAlgorithm.RS512));

In Java 7 if you're using the default JCA providers you'll get a negative answer.

As we explained above, the open source BouncyCastle JCA provider has ready support for RSA-PSS signatures. Let's verify this:

Provider bc = BouncyCastleProviderSingleton.getInstance();

assert JCASupport.isSupported(JWSAlgorithm.PS256, bc);

Once loaded the BouncyCastle provider may be added to the global JCA provider list:

Security.addProvider(bc);
assert JCASupport.isSupported(JWSAlgorithm.PS256);

If you don't want to add BouncyCastle globally, can just set it for the particular RSA signer / verifier instance that you intend to use:

RSASSASigner signer = new RSASSASigner(privateKey);
signer.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());

RSASSAVerifier verifier = new RSASSAVerifier(publicKey);
verifier.getJCAContext().setProvider(BouncyCastleProviderSingleton.getInstance());