JSON Web Encryption (JWE) with a preset Content Encryption Key (CEK)

Version 5.13 of the Nimbus JOSE+JWT library updated the RSAEncrypter to allow the Content Encryption Key (CEK) to be preset. The standard behaviour is to let the encrypter generate a new CEK for each JWE object that is being encrypted.

Note that the AES CEK length must match the expected CEK length for the encryption method that is going to be used.

You can easily find out the CEK length in bits like this:

EncryptionMethod.A128CBC_HS256.cekBitLength();

If you have a use case which requires presetting of the CEK for some other encrypter, for example the ECDHEncrypter, feel free to submit pull request.

Example preset of a AES CEK for a JWE with RSA-OAEP-256:

JWEAlgorithm alg = JWEAlgorithm.RSA_OAEP_256;
EncryptionMethod enc = EncryptionMethod.A128CBC_HS256;

// Generate an RSA key pair
KeyPairGenerator rsaGen = KeyPairGenerator.getInstance("RSA");
rsaGen.initialize(2048);
KeyPair rsaKeyPair = rsaGen.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey)rsaKeyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)rsaKeyPair.getPrivate();

// Generate the preset Content Encryption (CEK) key
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(enc.cekBitLength());
SecretKey cek = keyGenerator.generateKey();

// Encrypt the JWE with the RSA public key + specified AES CEK
JWEObject jwe = new JWEObject(
    new JWEHeader(alg, enc),
    new Payload("Hello, world!"));
jwe.encrypt(new RSAEncrypter(rsaPublicKey, cek));
String jweString = jwe.serialize();

// Decrypt the JWE with the RSA private key
jwe = JWEObject.parse(jweString);
jwe.decrypt(new RSADecrypter(rsaPrivateKey));
assertEquals("Hello, world!", jwe.getPayload().toString());

// Decrypt JWE with CEK directly, with the DirectDecrypter in promiscuous mode
jwe = JWEObject.parse(jweString);
jwe.decrypt(new DirectDecrypter(cek, true));
assertEquals("Hello, world!", jwe.getPayload().toString());