Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
languagejava
titleCXF JweJson
final String text = "The true sign of intelligence is not knowledge but imagination.";
// Create the secret keys for encrypting the content encryption key:
SecretKey wrapperKey1 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
SecretKey wrapperKey2 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES2, "AES");

// Create KeyEncryptionProviders initialized with these secret keys: 
KeyEncryptionProvider keyEncryption1 = JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey1, KeyAlgorithm.A128KW);
KeyEncryptionProvider keyEncryption2 = JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey2, KeyAlgorithm.A128KW);

// If you work with the public keys do this instead:
// PublicKey publicKey1 = ...;
// KeyEncryptionProvider keyEncryption1 = JweUtils.getPublicKeyEncryptionProvider(publicKey1, KeyAlgorithm.RSA_AEP);
// PublicKey publicKey2 = ...;
// KeyEncryptionProvider keyEncryption2 = JweUtils.getPublicKeyEncryptionProvider(publicKey2, KeyAlgorithm.RSA_AEP);


// Create ContentEncryptionProvider:
// Starting from CXF 3.1.11:
ContentEncryptionProvider contentEncryption = new AesGcmContentEncryptionAlgorithm(ContentAlgorithm.A128GCM, true);
// or 
// ContentEncryptionProvider contentEncryption = JweUtils.getContentEncryptionProvider(ContentAlgorithm.A128GCM, true);

// Before CXF 3.1.1 a CEK needs to be pre-generated when dealing with multiple recipients:
//ContentEncryptionProvider contentEncryption = new AesGcmContentEncryptionAlgorithm(CEK_BYTES, ContentAlgorithm.A128GCM);

// If a single recipient then this line is enough:
//ContentEncryptionProvider contentEncryption = JweUtils.getContentEncryptionProvider(ContentAlgorithm.A128GCM);

// Prepare JweEncryptionProviders, one per each recipient.
List<JweEncryptionProvider> jweProviders = new LinkedList<JweEncryptionProvider>();
jweProviders.add(new JweEncryption(keyEncryption1, contentEncryption));
jweProviders.add(new JweEncryption(keyEncryption2, contentEncryption));


// Let the recipients know that the key encryption algorithm is A128KW. 
// This step is optional if the recipients support A128KW only.
// Note because these headers are shared A128KW needs to be supported by all the recipients.
// Per-reciepient specific headers can be used instead to note the key encryption algorithm if required.
// One can also consider setting this property in the shared protected headers, same as it is done below
// with the content algorithm

JweHeaders sharedUnprotectedHeaders = new JweHeaders();
sharedUnprotectedHeaders.setKeyEncryptionAlgorithm(KeyAlgorithm.A128KW);
// Set some other custom shared unprotected header
sharedUnprotectedHeaders.setHeader("customHeader", "customValue");

// Let the recipients know that the content encryption algorithm is A128GCM. 
// This step is optional if the recipients support A128GCM only.
JweHeaders protectedHeaders = new JweHeaders(ContentAlgorithm.A128GCM);

// Set per-recipient specific headers        
List<JweHeaders> perRecipientHeades = new LinkedList<JweHeaders>();
perRecipientHeades.add(new JweHeaders("key1"));
perRecipientHeades.add(new JweHeaders("key2"));

JweJsonProducer p = new JweJsonProducer(protectedHeaders,
                                        sharedUnprotectedHeaders,
                                        StringUtils.toBytesUTF8(text),
                                        StringUtils.toBytesUTF8(EXTRA_AAD_SOURCE),
                                        false);
String jweJsonOut = p.encryptWith(jweProviders, perRecipientHeades);

JweJsonConsumer consumer = new JweJsonConsumer(jweJsonOut);
KeyAlgorithm keyAlgo = consumer.getSharedUnprotectedHeader().getKeyEncryptionAlgorithm();
ContentAlgorithm ctAlgo = consumer.getProtectedHeader().getContentEncryptionAlgorithm();

// first recipient:
JweDecryptionProvider jwe1 = JweUtils.createJweDecryptionProvider(wrapperKey1, keyAlgo, ctAlgo);

// the consumer will iterate over JWE entries and will try to find the one which can be decrypted with this decryptor
// or do consumer.getRecipientsMap() returning a list of entries and their metadata to do a more precise selection.

String content = consumer.decryptWith(jwe1, Collections.singletonMap("kid", "key1")).getContent();

// second recipient:
JweDecryptionProvider jwe2 = JweUtils.createJweDecryptionProvider(wrapperKey2, keyAlgo, ctAlgo);
content = consumer.decryptWith(jwe2, Collections.singletonMap("kid", "key2")).getContent();


 

If the sequence contains a single recipient entry only then the JWE JSON 'recipients' array will contain a single entry, or the whole sequence can be flattened instead with the actual 'recipients' array dropped. JweJsonProducer  does not produce the flattened sequence when only a single encryption is done by default because 3rd party JWE JSON consumers may only be able to process the sequences with the 'recipients' array, so pass a 'canBeFlat' flag to JwEJsonProducer if needed

...

This approach is more effective compared to the ones where the body hash is calculated before it is submitted to a signature creation function, with the signature added as HTTP header.

JWT authorization

CXF supports both role and claims based authorization for JAX-RS endpoints based on information contained in a received JWT. Please see the JAX-RS Token Authorization page for more information.

Optional protection of HTTP headers

...