[cxf] branch 3.3.x-fixes updated (7b812b2 -> 04454ed)

classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

[cxf] branch 3.3.x-fixes updated (7b812b2 -> 04454ed)

coheigea
Administrator
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a change to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git.


    from 7b812b2  Fixing some invalid bits in some of the test WSDLs
     new 2fad69a  [CXF-8162] JWE with multiple recipients does not work for AES CBC Encryption (#604)
     new dbc1093  Minor fix to last PR
     new 04454ed  Recording .gitmergeinfo Changes

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .gitmergeinfo                                      |   2 +
 .../jose/jwe/AesCbcContentEncryptionAlgorithm.java |  86 ++++++++++++++
 .../security/jose/jwe/AesCbcHmacJweEncryption.java |  92 +++++----------
 .../apache/cxf/rs/security/jose/jwe/JweUtils.java  |   3 +
 .../rs/security/jose/jwe/JweJsonProducerTest.java  | 130 ++++++++++++++++++++-
 5 files changed, 251 insertions(+), 62 deletions(-)
 create mode 100644 rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java

Reply | Threaded
Open this post in threaded view
|

[cxf] 01/03: [CXF-8162] JWE with multiple recipients does not work for AES CBC Encryption (#604)

coheigea
Administrator
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 2fad69a02a19773bdb6ca1261bc7bc3f1864e685
Author: frelibert <[hidden email]>
AuthorDate: Thu Nov 28 13:19:17 2019 +0100

    [CXF-8162] JWE with multiple recipients does not work for AES CBC Encryption (#604)
   
   
    (cherry picked from commit d3a968fb0ea586ac185483a169b1c5ab29dc5615)
---
 .../jose/jwe/AesCbcContentEncryptionAlgorithm.java |  82 +++++++++++++
 .../security/jose/jwe/AesCbcHmacJweEncryption.java |  96 ++++++---------
 .../apache/cxf/rs/security/jose/jwe/JweUtils.java  |   3 +
 .../rs/security/jose/jwe/JweJsonProducerTest.java  | 130 ++++++++++++++++++++-
 4 files changed, 247 insertions(+), 64 deletions(-)

diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java
new file mode 100644
index 0000000..c87907a
--- /dev/null
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java
@@ -0,0 +1,82 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.cxf.rs.security.jose.jwe;
+
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
+import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+
+public class AesCbcContentEncryptionAlgorithm extends AbstractContentEncryptionAlgorithm {
+    
+    static final Map<String, String> AES_HMAC_MAP;
+    static final Map<String, Integer> AES_CEK_SIZE_MAP;
+    
+    static {
+        AES_HMAC_MAP = new HashMap<>();
+        AES_HMAC_MAP.put(ContentAlgorithm.A128CBC_HS256.getJwaName(), AlgorithmUtils.HMAC_SHA_256_JAVA);
+        AES_HMAC_MAP.put(ContentAlgorithm.A192CBC_HS384.getJwaName(), AlgorithmUtils.HMAC_SHA_384_JAVA);
+        AES_HMAC_MAP.put(ContentAlgorithm.A256CBC_HS512.getJwaName(), AlgorithmUtils.HMAC_SHA_512_JAVA);
+
+        AES_CEK_SIZE_MAP = new HashMap<>();
+        AES_CEK_SIZE_MAP.put(ContentAlgorithm.A128CBC_HS256.getJwaName(), 32);
+        AES_CEK_SIZE_MAP.put(ContentAlgorithm.A192CBC_HS384.getJwaName(), 48);
+        AES_CEK_SIZE_MAP.put(ContentAlgorithm.A256CBC_HS512.getJwaName(), 64);
+    }
+    
+    public AesCbcContentEncryptionAlgorithm(ContentAlgorithm algo, boolean generateCekOnce) {
+        super(validateCekAlgorithm(algo), generateCekOnce);
+    }
+    
+    public AesCbcContentEncryptionAlgorithm(byte[] cek, byte[] iv, ContentAlgorithm algo) {
+        super(cek, iv, validateCekAlgorithm(algo));
+    }
+    
+    @Override
+    public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
+        return new IvParameterSpec(theIv);
+    }
+    
+    @Override
+    public byte[] getAdditionalAuthenticationData(String headersJson, byte[] aad) {
+        return null;
+    }
+    
+    @Override
+    protected int getContentEncryptionKeySize(JweHeaders headers) {
+        return getFullCekKeySize(getAlgorithm().getJwaName()) * 8;
+    }
+    
+    protected static int getFullCekKeySize(String algoJwt) {
+        return AES_CEK_SIZE_MAP.get(algoJwt);
+    }
+    
+    protected static ContentAlgorithm validateCekAlgorithm(ContentAlgorithm cekAlgo) {
+        if (!AlgorithmUtils.isAesCbcHmac(cekAlgo.getJwaName())) {
+            LOG.warning("Invalid content encryption algorithm");
+            throw new JweException(JweException.Error.INVALID_CONTENT_ALGORITHM);
+        }
+        return cekAlgo;
+    }
+
+}
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
index 12170c1..b995245 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
@@ -19,66 +19,61 @@
 package org.apache.cxf.rs.security.jose.jwe;
 
 import java.nio.ByteBuffer;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.HashMap;
-import java.util.Map;
 
 import javax.crypto.Mac;
-import javax.crypto.spec.IvParameterSpec;
 
-import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
 import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
+import org.apache.cxf.rs.security.jose.jwe.JweException.Error;
 import org.apache.cxf.rt.security.crypto.HmacUtils;
 
 public class AesCbcHmacJweEncryption extends JweEncryption {
-    private static final Map<String, String> AES_HMAC_MAP;
-    private static final Map<String, Integer> AES_CEK_SIZE_MAP;
-    static {
-        AES_HMAC_MAP = new HashMap<>();
-        AES_HMAC_MAP.put(ContentAlgorithm.A128CBC_HS256.getJwaName(), AlgorithmUtils.HMAC_SHA_256_JAVA);
-        AES_HMAC_MAP.put(ContentAlgorithm.A192CBC_HS384.getJwaName(), AlgorithmUtils.HMAC_SHA_384_JAVA);
-        AES_HMAC_MAP.put(ContentAlgorithm.A256CBC_HS512.getJwaName(), AlgorithmUtils.HMAC_SHA_512_JAVA);
-
-        AES_CEK_SIZE_MAP = new HashMap<>();
-        AES_CEK_SIZE_MAP.put(ContentAlgorithm.A128CBC_HS256.getJwaName(), 32);
-        AES_CEK_SIZE_MAP.put(ContentAlgorithm.A192CBC_HS384.getJwaName(), 48);
-        AES_CEK_SIZE_MAP.put(ContentAlgorithm.A256CBC_HS512.getJwaName(), 64);
-    }
+    
     public AesCbcHmacJweEncryption(ContentAlgorithm cekAlgoJwt,
                                    KeyEncryptionProvider keyEncryptionAlgorithm) {
         this(cekAlgoJwt, keyEncryptionAlgorithm, false);
     }
+    
     public AesCbcHmacJweEncryption(ContentAlgorithm cekAlgoJwt,
                                    KeyEncryptionProvider keyEncryptionAlgorithm,
                                    boolean generateCekOnce) {
-        super(keyEncryptionAlgorithm,
-              new AesCbcContentEncryptionAlgorithm(validateCekAlgorithm(cekAlgoJwt),
-                                                   generateCekOnce));
+        super(keyEncryptionAlgorithm, new AesCbcContentEncryptionAlgorithm(cekAlgoJwt, generateCekOnce));
     }
+    
     public AesCbcHmacJweEncryption(ContentAlgorithm cekAlgoJwt, byte[] cek,
                                    byte[] iv, KeyEncryptionProvider keyEncryptionAlgorithm) {
-        super(keyEncryptionAlgorithm,
-              new AesCbcContentEncryptionAlgorithm(cek, iv,
-                                                   validateCekAlgorithm(cekAlgoJwt)));
-
+        super(keyEncryptionAlgorithm, new AesCbcContentEncryptionAlgorithm(cek, iv, cekAlgoJwt));
     }
+    
+    public AesCbcHmacJweEncryption(KeyEncryptionProvider keyEncryptionAlgorithm,
+        AesCbcContentEncryptionAlgorithm contentEncryptionAlgorithm) {
+        super(keyEncryptionAlgorithm, contentEncryptionAlgorithm);
+    }
+    
     @Override
     protected byte[] getActualCek(byte[] theCek, String algoJwt) {
         return doGetActualCek(theCek, algoJwt);
     }
+    
     protected static byte[] doGetActualCek(byte[] theCek, String algoJwt) {
-        int size = getFullCekKeySize(algoJwt) / 2;
-        byte[] actualCek = new byte[size];
-        System.arraycopy(theCek, size, actualCek, 0, size);
-        return actualCek;
+        // K
+        int inputKeySize = AesCbcContentEncryptionAlgorithm.getFullCekKeySize(algoJwt);
+        if (theCek.length != inputKeySize) {
+            LOG.warning("Length input key [" + theCek.length + "] invalid for algorithm " + algoJwt
+                + " [" + inputKeySize + "]");
+            throw new JweException(Error.INVALID_CONTENT_KEY);
+        }
+        // MAC_KEY, ENC_KEY
+        int secondaryKeySize = inputKeySize / 2;
+        // Extract secondary key ENC_KEY from the input key K
+        byte[] encKey = new byte[secondaryKeySize];
+        System.arraycopy(theCek, secondaryKeySize, encKey, 0, secondaryKeySize);
+        return encKey;
     }
 
-    protected static int getFullCekKeySize(String algoJwt) {
-        return AES_CEK_SIZE_MAP.get(algoJwt);
-    }
     protected byte[] getActualCipher(byte[] cipher) {
         return cipher;
     }
+    
     protected byte[] getAuthenticationTag(JweEncryptionInternal state, byte[] cipher) {
         final MacState macState = getInitializedMacState(state);
         macState.mac.update(cipher);
@@ -94,21 +89,23 @@ public class AesCbcHmacJweEncryption extends JweEncryption {
         System.arraycopy(sig, 0, authTag, 0, authTagLen);
         return authTag;
     }
+    
     private MacState getInitializedMacState(final JweEncryptionInternal state) {
         return getInitializedMacState(state.secretKey, state.theIv, state.aad,
                                       state.theHeaders, state.protectedHeadersJson);
     }
+    
     protected static MacState getInitializedMacState(byte[] secretKey,
                                                      byte[] theIv,
                                                      byte[] extraAad,
                                                      JweHeaders theHeaders,
                                                      String protectedHeadersJson) {
         String algoJwt = theHeaders.getContentEncryptionAlgorithm().getJwaName();
-        int size = getFullCekKeySize(algoJwt) / 2;
+        int size = AesCbcContentEncryptionAlgorithm.getFullCekKeySize(algoJwt) / 2;
         byte[] macKey = new byte[size];
         System.arraycopy(secretKey, 0, macKey, 0, size);
 
-        String hmacAlgoJava = AES_HMAC_MAP.get(algoJwt);
+        String hmacAlgoJava = AesCbcContentEncryptionAlgorithm.AES_HMAC_MAP.get(algoJwt);
         Mac mac = HmacUtils.getInitializedMac(macKey, hmacAlgoJava, null);
 
         byte[] aad = JweUtils.getAdditionalAuthenticationData(protectedHeadersJson, extraAad);
@@ -140,42 +137,15 @@ public class AesCbcHmacJweEncryption extends JweEncryption {
             }
         };
     }
+
     @Override
     protected byte[] getEncryptedContentEncryptionKey(JweHeaders headers, byte[] theCek) {
         return getKeyEncryptionAlgo().getEncryptedContentEncryptionKey(headers, theCek);
     }
 
-    private static class AesCbcContentEncryptionAlgorithm extends AbstractContentEncryptionAlgorithm {
-        AesCbcContentEncryptionAlgorithm(ContentAlgorithm algo, boolean generateCekOnce) {
-            super(algo, generateCekOnce);
-        }
-        AesCbcContentEncryptionAlgorithm(byte[] cek, byte[] iv, ContentAlgorithm algo) {
-            super(cek, iv, algo);
-        }
-        @Override
-        public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
-            return new IvParameterSpec(theIv);
-        }
-        @Override
-        public byte[] getAdditionalAuthenticationData(String headersJson, byte[] aad) {
-            return null;
-        }
-        @Override
-        protected int getContentEncryptionKeySize(JweHeaders headers) {
-            return getFullCekKeySize(getAlgorithm().getJwaName()) * 8;
-        }
-    }
-
     protected static class MacState {
         protected Mac mac;
         private byte[] al;
     }
-
-    private static ContentAlgorithm validateCekAlgorithm(ContentAlgorithm cekAlgo) {
-        if (!AlgorithmUtils.isAesCbcHmac(cekAlgo.getJwaName())) {
-            LOG.warning("Invalid content encryption algorithm");
-            throw new JweException(JweException.Error.INVALID_CONTENT_ALGORITHM);
-        }
-        return cekAlgo;
-    }
+    
 }
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
index b2b91e0..32696b0 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java
@@ -267,6 +267,9 @@ public final class JweUtils {
         if (AlgorithmUtils.isAesGcm(algorithm.getJwaName())) {
             return new AesGcmContentEncryptionAlgorithm(key, null, algorithm);
         }
+        if (AlgorithmUtils.isAesCbcHmac(algorithm.getJwaName())) {
+            return new AesCbcContentEncryptionAlgorithm(key, null, algorithm);
+        }
         return null;
     }
     public static ContentEncryptionProvider getContentEncryptionProvider(ContentAlgorithm algorithm) {
diff --git a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
index 6d438e2..c1a2f35 100644
--- a/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
+++ b/rt/rs/security/jose-parent/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweJsonProducerTest.java
@@ -19,6 +19,7 @@
 package org.apache.cxf.rs.security.jose.jwe;
 
 import java.security.Security;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -32,8 +33,10 @@ import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
 import org.apache.cxf.rs.security.jose.jwa.KeyAlgorithm;
 import org.apache.cxf.rt.security.crypto.CryptoUtils;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.util.encoders.Hex;
 
 import org.junit.AfterClass;
+import org.junit.Assert;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -43,6 +46,7 @@ public class JweJsonProducerTest {
     static final byte[] WRAPPER_BYTES1 = {91, 96, 105, 38, 99, 108, 110, 8, -93, 50, -15, 62, 0, -115, 73, -39};
     static final byte[] WRAPPER_BYTES2 = {-39, 96, 105, 38, 99, 108, 110, 8, -93, 50, -15, 62, 0, -115, 73, 91};
     static final byte[] CEK_BYTES = {-43, 123, 77, 115, 40, 49, -4, -9, -48, -74, 62, 59, 60, 102, -22, -100};
+    static final String CEK_32_HEX = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
     static final String SINGLE_RECIPIENT_OUTPUT =
         "{"
         + "\"protected\":\"eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4R0NNIn0\","
@@ -148,6 +152,30 @@ public class JweJsonProducerTest {
         + "\"ciphertext\":\"KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY\","
         + "\"tag\":\"Mz-VPPyU4RlcuYv1IwIvzw\""
         + "}";
+    static final String MULTIPLE_RECIPIENTS_A128CBCHS256_JSON_OUTPUT =
+        "{"
+        + "\"protected\":\"eyJlbmMiOiJBMTI4Q0JDLUhTMjU2In0\","
+        + "\"unprotected\":"
+        + "{"
+        + "\"jku\":\"https://server.example.com/keys.jwks\","
+        + "\"alg\":\"A128KW\""
+        + "},"
+        + "\"recipients\":["
+        + "{"
+        + "\"header\":{\"kid\":\"key1\"},"
+        + "\"encrypted_key\":\"NrhRVDNccP-gul5SB393C8DlbEtgGdvSgYgH5QRUXJYt-r8_wzef1g\""
+        + "},{"
+        + "\"header\":{\"kid\":\"key2\"},"
+        + "\"encrypted_key\":\"6a_nnEYO45qB_Vp6N2QbFQ7Cv1uecbiE\""
+        + "}],"
+        + "\"aad\":\"WyJ2Y2FyZCIsW1sidmVyc2lvbiIse30sInRleHQiLCI0LjAiXSxbImZuIix7fSwidGV4dCIsIk1lcmlhZG9jIEJyYW5ke"
+        + "WJ1Y2siXSxbIm4iLHt9LCJ0ZXh0IixbIkJyYW5keWJ1Y2siLCJNZXJpYWRvYyIsIk1yLiIsIiJdXSxbImJkYXkiLHt9LCJ0ZXh0Iiwi"
+        + "VEEgMjk4MiJdLFsiZ2VuZGVyIix7fSwidGV4dCIsIk0iXV1d\","
+        + "\"iv\":\"AxY8DCtDaGlsbGljb3RoZQ\","
+        + "\"ciphertext\":\"pwitNt2DsK1zM72z5CxGClCr8ANYuIYZgCnohazsPyZhvR8atJnnlkR3fdSpyXYJcNx2LP-gcm3oNWiaAk0H2A\","
+        + "\"tag\":\"nNSN9kYhubsQ9QELBmZIhA\""
+        + "}";
+    
     @BeforeClass
     public static void registerBouncyCastleIfNeeded() throws Exception {
         try {
@@ -270,7 +298,7 @@ public class JweJsonProducerTest {
         assertEquals(SINGLE_RECIPIENT_ALL_HEADERS_AAD_OUTPUT, jweJson);
     }
     @Test
-    public void testMultipleRecipients() {
+    public void testMultipleRecipientsA128GCM() {
         final String text = "The true sign of intelligence is not knowledge but imagination.";
         SecretKey wrapperKey1 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
         SecretKey wrapperKey2 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES2, "AES");
@@ -308,4 +336,104 @@ public class JweJsonProducerTest {
         String jweJson = p.encryptWith(jweProviders, perRecipientHeades);
         assertEquals(MULTIPLE_RECIPIENTS_OUTPUT, jweJson);
     }
+    
+    @Test
+    public void testMultipleRecipientsA128CBCHS256GivenCek() throws Exception {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        
+        KeyAlgorithm keyAlgo = KeyAlgorithm.A128KW;
+        ContentAlgorithm contentAlgo = ContentAlgorithm.A128CBC_HS256;
+        
+        SecretKey wrapperKey1 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
+        SecretKey wrapperKey2 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES2, "AES");
+
+        JweHeaders protectedHeaders = new JweHeaders(contentAlgo);
+        JweHeaders sharedUnprotectedHeaders = new JweHeaders();
+        sharedUnprotectedHeaders.setJsonWebKeysUrl("https://server.example.com/keys.jwks");
+        
+        sharedUnprotectedHeaders.setKeyEncryptionAlgorithm(keyAlgo);
+
+        List<JweEncryptionProvider> jweProviders = new LinkedList<>();
+
+        KeyEncryptionProvider keyEncryption1 =
+            JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey1, keyAlgo);
+        
+        JweEncryptionProvider jwe1 = new AesCbcHmacJweEncryption(contentAlgo, Hex.decode(CEK_32_HEX),
+            JweCompactReaderWriterTest.INIT_VECTOR_A3, keyEncryption1);
+        KeyEncryptionProvider keyEncryption2 =
+            JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey2, keyAlgo);
+        JweEncryptionProvider jwe2 = new AesCbcHmacJweEncryption(contentAlgo, CEK_BYTES,
+            JweCompactReaderWriterTest.INIT_VECTOR_A3, keyEncryption2);
+        jweProviders.add(jwe1);
+        jweProviders.add(jwe2);
+
+        List<JweHeaders> perRecipientHeades = new LinkedList<>();
+        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 jweJson = p.encryptWith(jweProviders, perRecipientHeades);
+        assertEquals(MULTIPLE_RECIPIENTS_A128CBCHS256_JSON_OUTPUT, jweJson);
+    }
+    
+    @Test
+    public void testMultipleRecipientsA128CBCHS256() {
+        final String text = "The true sign of intelligence is not knowledge but imagination.";
+        
+        KeyAlgorithm keyAlgo = KeyAlgorithm.A128KW;
+        ContentAlgorithm contentAlgo = ContentAlgorithm.A128CBC_HS256;
+        
+        SecretKey wrapperKey1 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES1, "AES");
+        SecretKey wrapperKey2 = CryptoUtils.createSecretKeySpec(WRAPPER_BYTES2, "AES");
+
+        JweHeaders protectedHeaders = new JweHeaders(contentAlgo);
+        JweHeaders sharedUnprotectedHeaders = new JweHeaders();
+        sharedUnprotectedHeaders.setJsonWebKeysUrl("https://server.example.com/keys.jwks");
+        
+        sharedUnprotectedHeaders.setKeyEncryptionAlgorithm(keyAlgo);
+
+        List<JweEncryptionProvider> jweProviders = new LinkedList<>();
+
+        AesCbcContentEncryptionAlgorithm contentEncryption = new AesCbcContentEncryptionAlgorithm(contentAlgo, true);
+        
+        KeyEncryptionProvider keyEncryption1 = JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey1, keyAlgo);
+        JweEncryptionProvider jwe1 = new AesCbcHmacJweEncryption(keyEncryption1, contentEncryption);
+        KeyEncryptionProvider keyEncryption2 = JweUtils.getSecretKeyEncryptionAlgorithm(wrapperKey2, keyAlgo);
+        JweEncryptionProvider jwe2 = new AesCbcHmacJweEncryption(keyEncryption2, contentEncryption);
+        
+        jweProviders.add(jwe1);
+        jweProviders.add(jwe2);
+
+        List<JweHeaders> perRecipientHeades = new LinkedList<>();
+        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 jweJson = p.encryptWith(jweProviders, perRecipientHeades);
+        
+        JweJsonConsumer consumer = new JweJsonConsumer(jweJson);
+        Assert.assertEquals(keyAlgo, consumer.getSharedUnprotectedHeader().getKeyEncryptionAlgorithm());
+        Assert.assertEquals(contentAlgo, consumer.getProtectedHeader().getContentEncryptionAlgorithm());
+        
+        // Recipient 1
+        JweDecryptionProvider jwd1 = JweUtils.createJweDecryptionProvider(wrapperKey1, keyAlgo, contentAlgo);
+        JweDecryptionOutput out1 = consumer.decryptWith(jwd1, Collections.singletonMap("kid", "key1"));
+        assertEquals(text, out1.getContentText());
+        // Recipient 2
+        JweDecryptionProvider jwd2 = JweUtils.createJweDecryptionProvider(wrapperKey2, keyAlgo, contentAlgo);
+
+        JweDecryptionOutput out2 = consumer.decryptWith(jwd2, Collections.singletonMap("kid", "key2"));
+        assertEquals(text, out2.getContentText());
+    }
+    
 }

Reply | Threaded
Open this post in threaded view
|

[cxf] 02/03: Minor fix to last PR

coheigea
Administrator
In reply to this post by coheigea
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit dbc1093a035a81e9381356eb5ca079a5149eea01
Author: Colm O hEigeartaigh <[hidden email]>
AuthorDate: Thu Nov 28 12:22:36 2019 +0000

    Minor fix to last PR
   
    (cherry picked from commit c5ec3ac60ccfa800242caea6a7e62989ea9a5e9e)
---
 .../jose/jwe/AesCbcContentEncryptionAlgorithm.java | 26 +++++++++++---------
 .../security/jose/jwe/AesCbcHmacJweEncryption.java | 28 +++++++++++-----------
 2 files changed, 29 insertions(+), 25 deletions(-)

diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java
index c87907a..62f4e43 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcContentEncryptionAlgorithm.java
@@ -28,10 +28,10 @@ import org.apache.cxf.rs.security.jose.jwa.AlgorithmUtils;
 import org.apache.cxf.rs.security.jose.jwa.ContentAlgorithm;
 
 public class AesCbcContentEncryptionAlgorithm extends AbstractContentEncryptionAlgorithm {
-    
-    static final Map<String, String> AES_HMAC_MAP;
-    static final Map<String, Integer> AES_CEK_SIZE_MAP;
-    
+
+    private static final Map<String, String> AES_HMAC_MAP;
+    private static final Map<String, Integer> AES_CEK_SIZE_MAP;
+
     static {
         AES_HMAC_MAP = new HashMap<>();
         AES_HMAC_MAP.put(ContentAlgorithm.A128CBC_HS256.getJwaName(), AlgorithmUtils.HMAC_SHA_256_JAVA);
@@ -43,34 +43,38 @@ public class AesCbcContentEncryptionAlgorithm extends AbstractContentEncryptionA
         AES_CEK_SIZE_MAP.put(ContentAlgorithm.A192CBC_HS384.getJwaName(), 48);
         AES_CEK_SIZE_MAP.put(ContentAlgorithm.A256CBC_HS512.getJwaName(), 64);
     }
-    
+
     public AesCbcContentEncryptionAlgorithm(ContentAlgorithm algo, boolean generateCekOnce) {
         super(validateCekAlgorithm(algo), generateCekOnce);
     }
-    
+
     public AesCbcContentEncryptionAlgorithm(byte[] cek, byte[] iv, ContentAlgorithm algo) {
         super(cek, iv, validateCekAlgorithm(algo));
     }
-    
+
     @Override
     public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
         return new IvParameterSpec(theIv);
     }
-    
+
     @Override
     public byte[] getAdditionalAuthenticationData(String headersJson, byte[] aad) {
         return null;
     }
-    
+
     @Override
     protected int getContentEncryptionKeySize(JweHeaders headers) {
         return getFullCekKeySize(getAlgorithm().getJwaName()) * 8;
     }
-    
+
     protected static int getFullCekKeySize(String algoJwt) {
         return AES_CEK_SIZE_MAP.get(algoJwt);
     }
-    
+
+    protected static String getHMACAlgorithm(String algoJwt) {
+        return AES_HMAC_MAP.get(algoJwt);
+    }
+
     protected static ContentAlgorithm validateCekAlgorithm(ContentAlgorithm cekAlgo) {
         if (!AlgorithmUtils.isAesCbcHmac(cekAlgo.getJwaName())) {
             LOG.warning("Invalid content encryption algorithm");
diff --git a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
index b995245..8226a17 100644
--- a/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
+++ b/rt/rs/security/jose-parent/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
@@ -27,40 +27,40 @@ import org.apache.cxf.rs.security.jose.jwe.JweException.Error;
 import org.apache.cxf.rt.security.crypto.HmacUtils;
 
 public class AesCbcHmacJweEncryption extends JweEncryption {
-    
+
     public AesCbcHmacJweEncryption(ContentAlgorithm cekAlgoJwt,
                                    KeyEncryptionProvider keyEncryptionAlgorithm) {
         this(cekAlgoJwt, keyEncryptionAlgorithm, false);
     }
-    
+
     public AesCbcHmacJweEncryption(ContentAlgorithm cekAlgoJwt,
                                    KeyEncryptionProvider keyEncryptionAlgorithm,
                                    boolean generateCekOnce) {
         super(keyEncryptionAlgorithm, new AesCbcContentEncryptionAlgorithm(cekAlgoJwt, generateCekOnce));
     }
-    
+
     public AesCbcHmacJweEncryption(ContentAlgorithm cekAlgoJwt, byte[] cek,
                                    byte[] iv, KeyEncryptionProvider keyEncryptionAlgorithm) {
         super(keyEncryptionAlgorithm, new AesCbcContentEncryptionAlgorithm(cek, iv, cekAlgoJwt));
     }
-    
-    public AesCbcHmacJweEncryption(KeyEncryptionProvider keyEncryptionAlgorithm,
+
+    public AesCbcHmacJweEncryption(KeyEncryptionProvider keyEncryptionAlgorithm,
         AesCbcContentEncryptionAlgorithm contentEncryptionAlgorithm) {
         super(keyEncryptionAlgorithm, contentEncryptionAlgorithm);
     }
-    
+
     @Override
     protected byte[] getActualCek(byte[] theCek, String algoJwt) {
         return doGetActualCek(theCek, algoJwt);
     }
-    
+
     protected static byte[] doGetActualCek(byte[] theCek, String algoJwt) {
         // K
         int inputKeySize = AesCbcContentEncryptionAlgorithm.getFullCekKeySize(algoJwt);
         if (theCek.length != inputKeySize) {
-            LOG.warning("Length input key [" + theCek.length + "] invalid for algorithm " + algoJwt
+            LOG.warning("Length input key [" + theCek.length + "] invalid for algorithm " + algoJwt
                 + " [" + inputKeySize + "]");
-            throw new JweException(Error.INVALID_CONTENT_KEY);
+            throw new JweException(Error.INVALID_CONTENT_KEY);
         }
         // MAC_KEY, ENC_KEY
         int secondaryKeySize = inputKeySize / 2;
@@ -73,7 +73,7 @@ public class AesCbcHmacJweEncryption extends JweEncryption {
     protected byte[] getActualCipher(byte[] cipher) {
         return cipher;
     }
-    
+
     protected byte[] getAuthenticationTag(JweEncryptionInternal state, byte[] cipher) {
         final MacState macState = getInitializedMacState(state);
         macState.mac.update(cipher);
@@ -89,12 +89,12 @@ public class AesCbcHmacJweEncryption extends JweEncryption {
         System.arraycopy(sig, 0, authTag, 0, authTagLen);
         return authTag;
     }
-    
+
     private MacState getInitializedMacState(final JweEncryptionInternal state) {
         return getInitializedMacState(state.secretKey, state.theIv, state.aad,
                                       state.theHeaders, state.protectedHeadersJson);
     }
-    
+
     protected static MacState getInitializedMacState(byte[] secretKey,
                                                      byte[] theIv,
                                                      byte[] extraAad,
@@ -105,7 +105,7 @@ public class AesCbcHmacJweEncryption extends JweEncryption {
         byte[] macKey = new byte[size];
         System.arraycopy(secretKey, 0, macKey, 0, size);
 
-        String hmacAlgoJava = AesCbcContentEncryptionAlgorithm.AES_HMAC_MAP.get(algoJwt);
+        String hmacAlgoJava = AesCbcContentEncryptionAlgorithm.getHMACAlgorithm(algoJwt);
         Mac mac = HmacUtils.getInitializedMac(macKey, hmacAlgoJava, null);
 
         byte[] aad = JweUtils.getAdditionalAuthenticationData(protectedHeadersJson, extraAad);
@@ -147,5 +147,5 @@ public class AesCbcHmacJweEncryption extends JweEncryption {
         protected Mac mac;
         private byte[] al;
     }
-    
+
 }

Reply | Threaded
Open this post in threaded view
|

[cxf] 03/03: Recording .gitmergeinfo Changes

coheigea
Administrator
In reply to this post by coheigea
This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 3.3.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git

commit 04454ed1c3356805f6a828d5e02b6bcf45ddc8b1
Author: Colm O hEigeartaigh <[hidden email]>
AuthorDate: Thu Nov 28 12:23:13 2019 +0000

    Recording .gitmergeinfo Changes
---
 .gitmergeinfo | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/.gitmergeinfo b/.gitmergeinfo
index 10a4833..56718d8 100644
--- a/.gitmergeinfo
+++ b/.gitmergeinfo
@@ -3,6 +3,7 @@ origin/master
 B 08164e1f0e07c222ae45d320973401833df6ab9c
 B 0c7ab097483a2a30844cae32e6532f1028afc17e
 B 0deb502385473af355a96c20eea624a812addcd2
+B 0e8b0fac8fe12e56c30980cf08590b549af0c0d9
 B 11de1e0dfff9a8f9b157e23983c8e25f8503f868
 B 180fbbbd5571840b5f7a09ab7c0ce59605edd346
 B 1c55f929bd90a5a50530b5eaf22216c93ce3f2f9
@@ -25,6 +26,7 @@ B 64915c3d36d6ef2bef8168e912a9b8977b5b2330
 B 65869badeefe7eedd60fbc8b7d7c614a3c6d59a8
 B 67715076cb7d245aaf2d3a2442a40349d354e323
 B 6fbaddee67676f9840405bd49cb7d6e08a81bd23
+B 71b0cee7b2148af88c005cccd4c46f64ffbf62dd
 B 75e9ae0a7d31c14098e821e723cd766aa1e88785
 B 7689d884a64db0352cdb1ac9ee0628a26491f35a
 B 7b333d06910b3d4a84dd77a3c76b48d1b44525b3