Repository: cxf Updated Branches: refs/heads/master e3dfa35ac -> 9a33c9e45
[CXF-5902] Moving closer to providing a utility Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/9a33c9e4 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/9a33c9e4 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/9a33c9e4 Branch: refs/heads/master Commit: 9a33c9e453c5ac7e6c27b6b326b6fac5bbf022fd Parents: e3dfa35 Author: Sergey Beryozkin <[email protected]> Authored: Fri Aug 1 13:54:01 2014 +0300 Committer: Sergey Beryozkin <[email protected]> Committed: Fri Aug 1 13:54:01 2014 +0300 ---------------------------------------------------------------------- .../jwe/AbstractContentEncryptionAlgorithm.java | 4 + .../oauth2/jwe/AbstractJweEncryption.java | 53 +++++--- .../oauth2/jwe/AesCbcHmacJweEncryption.java | 131 +++++++++++++++++++ .../oauth2/jwe/ContentEncryptionAlgorithm.java | 3 + .../security/oauth2/jwe/JweCompactProducer.java | 33 ++++- .../cxf/rs/security/oauth2/jwe/JweHeaders.java | 5 - .../cxf/rs/security/oauth2/jwt/Algorithm.java | 6 +- .../rs/security/oauth2/jwt/JwtConstants.java | 2 +- .../oauth2/jwe/JweCompactReaderWriterTest.java | 95 +++++--------- 9 files changed, 240 insertions(+), 92 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractContentEncryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractContentEncryptionAlgorithm.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractContentEncryptionAlgorithm.java index 7baa98c..c2494ab 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractContentEncryptionAlgorithm.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractContentEncryptionAlgorithm.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicInteger; import javax.crypto.SecretKey; +import org.apache.cxf.rs.security.oauth2.jwt.JwtHeadersWriter; import org.apache.cxf.rs.security.oauth2.utils.crypto.CryptoUtils; @@ -51,6 +52,9 @@ public abstract class AbstractContentEncryptionAlgorithm implements ContentEncry public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) { return CryptoUtils.getContentEncryptionCipherSpec(getAuthTagLen(), theIv); } + public byte[] getAAD(JweHeaders theHeaders, JwtHeadersWriter writer) { + return theHeaders.toCipherAdditionalAuthData(writer); + } public byte[] getInitVector() { if (iv == null) { return CryptoUtils.generateSecureRandomBytes(DEFAULT_IV_SIZE); http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryption.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryption.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryption.java index 389bb42..133b432 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryption.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AbstractJweEncryption.java @@ -84,36 +84,51 @@ public abstract class AbstractJweEncryption implements JweEncryptionProvider { protected int getAuthTagLen() { return DEFAULT_AUTH_TAG_LENGTH; } - protected JweHeaders getJweHeaders() { - return headers; + protected byte[] getAAD(JweHeaders theHeaders) { + return contentEncryptionAlgo.getAAD(theHeaders, writer); } public String encrypt(byte[] content, String contentType) { JweEncryptionInternal state = getInternalState(contentType); - byte[] cipherText = CryptoUtils.encryptBytes( - content, - state.secretKey, - state.keyProps); + byte[] cipher = CryptoUtils.encryptBytes(content, createCekSecretKey(state), state.keyProps); - JweCompactProducer producer = new JweCompactProducer(state.theHeaders, - writer, - state.jweContentEncryptionKey, - state.theIv, - cipherText, - getAuthTagLen()); + JweCompactProducer producer = getJweCompactProducer(state, cipher); return producer.getJweContent(); } + protected JweCompactProducer getJweCompactProducer(JweEncryptionInternal state, byte[] cipher) { + return new JweCompactProducer(state.theHeaders, + getJwtHeadersWriter(), + state.jweContentEncryptionKey, + state.theIv, + cipher, + getAuthTagLen()); + } + + protected JwtHeadersWriter getJwtHeadersWriter() { + return writer; + } + protected JweHeaders getJweHeaders() { + return headers; + } @Override public JweEncryptionState createJweEncryptionState(String contentType) { JweEncryptionInternal state = getInternalState(contentType); - Cipher c = CryptoUtils.initCipher(state.secretKey, state.keyProps, + Cipher c = CryptoUtils.initCipher(createCekSecretKey(state), state.keyProps, Cipher.ENCRYPT_MODE); return new JweEncryptionState(c, getAuthTagLen(), state.theHeaders, state.jweContentEncryptionKey, state.theIv, state.keyProps.isCompressionSupported()); } + protected SecretKey createCekSecretKey(JweEncryptionInternal state) { + return CryptoUtils.createSecretKeySpec(getActualCek(state.secretKey), state.keyProps.getKeyAlgo()); + } + + protected byte[] getActualCek(byte[] theCek) { + return theCek; + } + private JweEncryptionInternal getInternalState(String contentType) { JweHeaders theHeaders = headers; if (contentType != null) { @@ -125,7 +140,7 @@ public abstract class AbstractJweEncryption implements JweEncryptionProvider { String contentEncryptionAlgoJavaName = Algorithm.toJavaName(theHeaders.getContentEncryptionAlgorithm()); KeyProperties keyProps = new KeyProperties(contentEncryptionAlgoJavaName); keyProps.setCompressionSupported(compressionRequired(theHeaders)); - byte[] additionalEncryptionParam = theHeaders.toCipherAdditionalAuthData(writer); + byte[] additionalEncryptionParam = getAAD(theHeaders); keyProps.setAdditionalData(additionalEncryptionParam); byte[] theIv = contentEncryptionAlgo.getInitVector(); @@ -136,19 +151,21 @@ public abstract class AbstractJweEncryption implements JweEncryptionProvider { state.theHeaders = theHeaders; state.jweContentEncryptionKey = jweContentEncryptionKey; state.keyProps = keyProps; - state.secretKey = CryptoUtils.createSecretKeySpec(theCek, - contentEncryptionAlgoJavaName); + state.secretKey = theCek; state.theIv = theIv; return state; } private boolean compressionRequired(JweHeaders theHeaders) { return JwtConstants.DEFLATE_ZIP_ALGORITHM.equals(theHeaders.getZipAlgorithm()); } - private static class JweEncryptionInternal { + protected KeyEncryptionAlgorithm getKeyEncryptionAlgo() { + return keyEncryptionAlgo; + } + protected static class JweEncryptionInternal { JweHeaders theHeaders; byte[] jweContentEncryptionKey; byte[] theIv; KeyProperties keyProps; - SecretKey secretKey; + byte[] secretKey; } } http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AesCbcHmacJweEncryption.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AesCbcHmacJweEncryption.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AesCbcHmacJweEncryption.java new file mode 100644 index 0000000..3f16b15 --- /dev/null +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/AesCbcHmacJweEncryption.java @@ -0,0 +1,131 @@ +/** + * 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.oauth2.jwe; + +import java.nio.ByteBuffer; +import java.security.spec.AlgorithmParameterSpec; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; + +import org.apache.cxf.rs.security.oauth2.jwt.Algorithm; +import org.apache.cxf.rs.security.oauth2.jwt.JwtHeadersWriter; +import org.apache.cxf.rs.security.oauth2.utils.crypto.HmacUtils; + +public class AesCbcHmacJweEncryption extends AbstractJweEncryption { + private static final Set<String> SUPPORTED_CEK_ALGORITHMS = new HashSet<String>( + Arrays.asList(Algorithm.A128CBC_HS256.getJwtName(), + Algorithm.A192CBC_HS384.getJwtName(), + Algorithm.A256CBC_HS512.getJwtName())); + 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<String, String>(); + AES_HMAC_MAP.put(Algorithm.A128CBC_HS256.getJwtName(), Algorithm.HMAC_SHA_256_JAVA); + AES_HMAC_MAP.put(Algorithm.A192CBC_HS384.getJwtName(), Algorithm.HMAC_SHA_384_JAVA); + AES_HMAC_MAP.put(Algorithm.A256CBC_HS512.getJwtName(), Algorithm.HMAC_SHA_512_JAVA); + + AES_CEK_SIZE_MAP = new HashMap<String, Integer>(); + AES_CEK_SIZE_MAP.put(Algorithm.A128CBC_HS256.getJwtName(), 32); + AES_CEK_SIZE_MAP.put(Algorithm.A192CBC_HS384.getJwtName(), 48); + AES_CEK_SIZE_MAP.put(Algorithm.A256CBC_HS512.getJwtName(), 64); + } + public AesCbcHmacJweEncryption(JweHeaders headers, + KeyEncryptionAlgorithm keyEncryptionAlgorithm) { + this(headers, null, null, keyEncryptionAlgorithm); + } + public AesCbcHmacJweEncryption(JweHeaders headers, byte[] cek, + byte[] iv, KeyEncryptionAlgorithm keyEncryptionAlgorithm) { + this(headers, cek, iv, keyEncryptionAlgorithm, null); + } + public AesCbcHmacJweEncryption(JweHeaders headers, + byte[] cek, + byte[] iv, + KeyEncryptionAlgorithm keyEncryptionAlgorithm, + JwtHeadersWriter writer) { + super(headers, new AesCbcContentEncryptionAlgorithm(cek, iv), keyEncryptionAlgorithm, writer); + if (!SUPPORTED_CEK_ALGORITHMS.contains(headers.getContentEncryptionAlgorithm())) { + throw new SecurityException(); + } + } + + protected byte[] getActualCek(byte[] theCek) { + int size = getCekKeySize() / 2; + byte[] actualCek = new byte[size]; + System.arraycopy(theCek, size, actualCek, 0, size); + return actualCek; + } + + protected int getCekKeySize() { + return AES_CEK_SIZE_MAP.get(super.getContentEncryptionAlgoJwt()); + } + + protected JweCompactProducer getJweCompactProducer(JweEncryptionInternal state, byte[] cipher) { + int size = getCekKeySize() / 2; + byte[] macKey = new byte[size]; + System.arraycopy(state.secretKey, 0, macKey, 0, size); + + String hmacAlgoJava = AES_HMAC_MAP.get(super.getContentEncryptionAlgoJwt()); + Mac mac = HmacUtils.getInitializedMac(macKey, hmacAlgoJava, null); + + String headersJson = getJwtHeadersWriter().headersToJson(state.theHeaders); + byte[] aad = JweHeaders.toCipherAdditionalAuthData(headersJson); + ByteBuffer buf = ByteBuffer.allocate(8); + byte[] al = buf.putInt(0).putInt(aad.length * 8).array(); + + mac.update(aad); + mac.update(state.theIv); + mac.update(cipher); + mac.update(al); + byte[] sig = mac.doFinal(); + int authTagLen = getAuthTagLen() / 8; + byte[] authTag = new byte[authTagLen]; + System.arraycopy(sig, 0, authTag, 0, authTagLen); + + return new JweCompactProducer(headersJson, + state.jweContentEncryptionKey, + state.theIv, + cipher, + authTag); + } + + + protected byte[] getEncryptedContentEncryptionKey(byte[] theCek) { + return getKeyEncryptionAlgo().getEncryptedContentEncryptionKey(getJweHeaders(), theCek); + } + + private static class AesCbcContentEncryptionAlgorithm extends AbstractContentEncryptionAlgorithm { + public AesCbcContentEncryptionAlgorithm(byte[] cek, byte[] iv) { + super(cek, iv); + } + @Override + public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) { + return new IvParameterSpec(theIv); + } + @Override + public byte[] getAAD(JweHeaders theHeaders, JwtHeadersWriter writer) { + return null; + } + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/ContentEncryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/ContentEncryptionAlgorithm.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/ContentEncryptionAlgorithm.java index 7b93ef8..709cffc 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/ContentEncryptionAlgorithm.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/ContentEncryptionAlgorithm.java @@ -20,9 +20,12 @@ package org.apache.cxf.rs.security.oauth2.jwe; import java.security.spec.AlgorithmParameterSpec; +import org.apache.cxf.rs.security.oauth2.jwt.JwtHeadersWriter; + interface ContentEncryptionAlgorithm { byte[] getInitVector(); byte[] getContentEncryptionKey(JweHeaders headers); + byte[] getAAD(JweHeaders headers, JwtHeadersWriter writer); AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] iv); } http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java index 365a986..8d8a015 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactProducer.java @@ -46,11 +46,22 @@ public class JweCompactProducer { byte[] cipherInitVector, byte[] encryptedContentNoTag, byte[] authenticationTag) { - jweContentBuilder = startJweContent(new StringBuilder(), headers, writer, - encryptedContentEncryptionKey, cipherInitVector); + this(getHeadersJson(headers, writer), + encryptedContentEncryptionKey, + cipherInitVector, + encryptedContentNoTag, + authenticationTag); + } + public JweCompactProducer(String headersJson, + byte[] encryptedContentEncryptionKey, + byte[] cipherInitVector, + byte[] encryptedContentNoTag, + byte[] authenticationTag) { + jweContentBuilder = startJweContent(new StringBuilder(), headersJson, + encryptedContentEncryptionKey, cipherInitVector); this.encodedEncryptedContent = Base64UrlUtility.encode(encryptedContentNoTag); this.encodedAuthTag = Base64UrlUtility.encode(authenticationTag); - + } public JweCompactProducer(JweHeaders headers, @@ -91,8 +102,22 @@ public class JweCompactProducer { JwtHeadersWriter writer, byte[] encryptedContentEncryptionKey, byte[] cipherInitVector) { + return startJweContent(sb, + getHeadersJson(headers, writer), + encryptedContentEncryptionKey, + cipherInitVector); + } + private static String getHeadersJson(JweHeaders headers, + JwtHeadersWriter writer) { writer = writer == null ? new JwtTokenReaderWriter() : writer; - String encodedHeaders = Base64UrlUtility.encode(writer.headersToJson(headers)); + return writer.headersToJson(headers); + + } + public static StringBuilder startJweContent(StringBuilder sb, + String headersJson, + byte[] encryptedContentEncryptionKey, + byte[] cipherInitVector) { + String encodedHeaders = Base64UrlUtility.encode(headersJson); String encodedContentEncryptionKey = Base64UrlUtility.encode(encryptedContentEncryptionKey); String encodedInitVector = Base64UrlUtility.encode(cipherInitVector); sb.append(encodedHeaders) http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweHeaders.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweHeaders.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweHeaders.java index 4b0d157..bb956e1 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweHeaders.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwe/JweHeaders.java @@ -25,7 +25,6 @@ import java.util.Map; import org.apache.cxf.rs.security.oauth2.jwt.JwtConstants; import org.apache.cxf.rs.security.oauth2.jwt.JwtHeaders; import org.apache.cxf.rs.security.oauth2.jwt.JwtHeadersWriter; -import org.apache.cxf.rs.security.oauth2.jwt.JwtTokenReaderWriter; import org.apache.cxf.rs.security.oauth2.utils.Base64UrlUtility; @@ -89,10 +88,6 @@ public class JweHeaders extends JwtHeaders { public JwtHeaders setHeader(String name, Object value) { return (JwtHeaders)super.setHeader(name, value); } - - public byte[] toCipherAdditionalAuthData() { - return toCipherAdditionalAuthData(new JwtTokenReaderWriter()); - } public byte[] toCipherAdditionalAuthData(JwtHeadersWriter writer) { return toCipherAdditionalAuthData(writer.headersToJson(this)); } http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java index 1f1b573..e2807f9 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/Algorithm.java @@ -51,7 +51,7 @@ public enum Algorithm { A192GCM(JwtConstants.A192GCM_ALGO, "AES/GCM/NoPadding", 192), A256GCM(JwtConstants.A256GCM_ALGO, "AES/GCM/NoPadding", 256), A128CBC_HS256(JwtConstants.A128CBC_HS256_ALGO, "AES/CBC/PKCS7Padding", 128), - A192CBC_HS354(JwtConstants.A192CBC_HS354_ALGO, "AES/CBC/PKCS7Padding", 192), + A192CBC_HS384(JwtConstants.A192CBC_HS384_ALGO, "AES/CBC/PKCS7Padding", 192), A256CBC_HS512(JwtConstants.A256CBC_HS512_ALGO, "AES/CBC/PKCS7Padding", 256); public static final String HMAC_SHA_256_JAVA = "HmacSHA256"; @@ -94,7 +94,7 @@ public enum Algorithm { JAVA_TO_JWT_NAMES.put(AES_WRAP_ALGO_JAVA, JwtConstants.A192KW_ALGO); JAVA_TO_JWT_NAMES.put(AES_WRAP_ALGO_JAVA, JwtConstants.A256KW_ALGO); JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JwtConstants.A128CBC_HS256_ALGO); - JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JwtConstants.A192CBC_HS354_ALGO); + JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JwtConstants.A192CBC_HS384_ALGO); JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JwtConstants.A256CBC_HS512_ALGO); JWT_TO_JAVA_NAMES = new HashMap<String, String>(); JWT_TO_JAVA_NAMES.put(JwtConstants.HMAC_SHA_256_ALGO, HMAC_SHA_256_JAVA); @@ -116,7 +116,7 @@ public enum Algorithm { JWT_TO_JAVA_NAMES.put(JwtConstants.A192GCM_ALGO, AES_GCM_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.A128GCM_ALGO, AES_GCM_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.A128CBC_HS256_ALGO, AES_CBC_ALGO_JAVA); - JWT_TO_JAVA_NAMES.put(JwtConstants.A192CBC_HS354_ALGO, AES_CBC_ALGO_JAVA); + JWT_TO_JAVA_NAMES.put(JwtConstants.A192CBC_HS384_ALGO, AES_CBC_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JwtConstants.A256CBC_HS512_ALGO, AES_CBC_ALGO_JAVA); } private final String jwtName; http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java index 0356fab..461d7b2 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/main/java/org/apache/cxf/rs/security/oauth2/jwt/JwtConstants.java @@ -71,7 +71,7 @@ public final class JwtConstants { // Content Encryption public static final String A128CBC_HS256_ALGO = "A128CBC-HS256"; - public static final String A192CBC_HS354_ALGO = "A192CBC-HS354"; + public static final String A192CBC_HS384_ALGO = "A192CBC-HS384"; public static final String A256CBC_HS512_ALGO = "A256CBC-HS512"; public static final String A128GCM_ALGO = "A128GCM"; public static final String A192GCM_ALGO = "A192GCM"; http://git-wip-us.apache.org/repos/asf/cxf/blob/9a33c9e4/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactReaderWriterTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactReaderWriterTest.java b/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactReaderWriterTest.java index 091ea1a..8265803 100644 --- a/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactReaderWriterTest.java +++ b/rt/rs/security/oauth-parent/oauth2-jwt/src/test/java/org/apache/cxf/rs/security/oauth2/jwe/JweCompactReaderWriterTest.java @@ -18,22 +18,17 @@ */ package org.apache.cxf.rs.security.oauth2.jwe; -import java.nio.ByteBuffer; import java.security.Security; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; import javax.crypto.Cipher; -import javax.crypto.Mac; import javax.crypto.SecretKey; -import javax.crypto.spec.IvParameterSpec; import org.apache.cxf.rs.security.oauth2.jws.JwsCompactReaderWriterTest; import org.apache.cxf.rs.security.oauth2.jwt.Algorithm; import org.apache.cxf.rs.security.oauth2.utils.Base64UrlUtility; import org.apache.cxf.rs.security.oauth2.utils.crypto.CryptoUtils; -import org.apache.cxf.rs.security.oauth2.utils.crypto.HmacUtils; -import org.apache.cxf.rs.security.oauth2.utils.crypto.KeyProperties; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.AfterClass; @@ -42,12 +37,31 @@ import org.junit.BeforeClass; import org.junit.Test; public class JweCompactReaderWriterTest extends Assert { - private static final byte[] CONTENT_ENCRYPTION_KEY = { + // A1 example + private static final byte[] CONTENT_ENCRYPTION_KEY_A1 = { (byte)177, (byte)161, (byte)244, (byte)128, 84, (byte)143, (byte)225, 115, 63, (byte)180, 3, (byte)255, 107, (byte)154, (byte)212, (byte)246, (byte)138, 7, 110, 91, 112, 46, 34, 105, 47, (byte)130, (byte)203, 46, 122, (byte)234, 64, (byte)252}; + private static final String RSA_MODULUS_ENCODED_A1 = "oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW" + + "cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S" + + "psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a" + + "sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS" + + "tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj" + + "YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw"; + private static final String RSA_PUBLIC_EXPONENT_ENCODED_A1 = "AQAB"; + private static final String RSA_PRIVATE_EXPONENT_ENCODED_A1 = + "kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5N" + + "WV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD9" + + "3Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghk" + + "qDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vl" + + "t3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSnd" + + "VTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ"; + private static final byte[] INIT_VECTOR_A1 = {(byte)227, (byte)197, 117, (byte)252, 2, (byte)219, + (byte)233, 68, (byte)180, (byte)225, 77, (byte)219}; + + // A3 example private static final byte[] CONTENT_ENCRYPTION_KEY_A3 = { 4, (byte)211, 31, (byte)197, 84, (byte)157, (byte)252, (byte)254, 11, 100, (byte)157, (byte)250, 63, (byte)170, 106, (byte)206, 107, 124, (byte)212, @@ -62,24 +76,7 @@ public class JweCompactReaderWriterTest extends Assert { + ".AxY8DCtDaGlsbGljb3RoZQ" + ".KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY" + ".U0m_YmjN04DJvceFICbCVQ"; - private static final String RSA_MODULUS_ENCODED = "oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW" - + "cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S" - + "psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a" - + "sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS" - + "tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj" - + "YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw"; - private static final String RSA_PUBLIC_EXPONENT_ENCODED = "AQAB"; - private static final String RSA_PRIVATE_EXPONENT_ENCODED = - "kLdtIj6GbDks_ApCSTYQtelcNttlKiOyPzMrXHeI-yk1F7-kpDxY4-WY5N" - + "WV5KntaEeXS1j82E375xxhWMHXyvjYecPT9fpwR_M9gV8n9Hrh2anTpTD9" - + "3Dt62ypW3yDsJzBnTnrYu1iwWRgBKrEYY46qAZIrA2xAwnm2X7uGR1hghk" - + "qDp0Vqj3kbSCz1XyfCs6_LehBwtxHIyh8Ripy40p24moOAbgxVw3rxT_vl" - + "t3UVe4WO3JkJOzlpUf-KTVI2Ptgm-dARxTEtE-id-4OJr0h-K-VFs3VSnd" - + "VTIznSxfyrj8ILL6MG_Uv8YAu7VILSB3lOW085-4qE3DzgrTjgyQ"; - private static final byte[] INIT_VECTOR = {(byte)227, (byte)197, 117, (byte)252, 2, (byte)219, - (byte)233, 68, (byte)180, (byte)225, 77, (byte)219}; - @BeforeClass public static void registerBouncyCastleIfNeeded() throws Exception { try { @@ -98,44 +95,18 @@ public class JweCompactReaderWriterTest extends Assert { @Test public void testEncryptDecryptA128CBCHS256() throws Exception { final String specPlainText = "Live long and prosper."; - byte[] macKey = new byte[16]; - System.arraycopy(CONTENT_ENCRYPTION_KEY_A3, 0, macKey, 0, 16); - byte[] encKey = new byte[16]; - System.arraycopy(CONTENT_ENCRYPTION_KEY_A3, 16, encKey, 0, 16); - SecretKey secretEncKey = - CryptoUtils.createSecretKeySpec(encKey, Algorithm.A128CBC_HS256.getJavaAlgoName()); - KeyProperties keyProps = new KeyProperties(Algorithm.AES_CBC_ALGO_JAVA); - keyProps.setAlgoSpec(new IvParameterSpec(INIT_VECTOR_A3)); - byte[] cipher = CryptoUtils.encryptBytes(specPlainText.getBytes("UTF-8"), secretEncKey, keyProps); - JweHeaders headers = new JweHeaders(); headers.setAlgorithm(Algorithm.A128KW.getJwtName()); headers.setContentEncryptionAlgorithm(Algorithm.A128CBC_HS256.getJwtName()); AesWrapKeyAlgorithm keyEncryption = new AesWrapKeyAlgorithm(Base64UrlUtility.decode(KEY_ENCRYPTION_KEY_A3), - Algorithm.A128KW.getJwtName()); - byte[] encryptedCek = keyEncryption.getEncryptedContentEncryptionKey(headers, CONTENT_ENCRYPTION_KEY_A3); - - byte[] aad = headers.toCipherAdditionalAuthData(); - ByteBuffer buf = ByteBuffer.allocate(8); - byte[] al = buf.putInt(0).putInt(aad.length * 8).array(); - - Mac mac = HmacUtils.getInitializedMac(macKey, Algorithm.HMAC_SHA_256_JAVA, null); - mac.update(aad); - mac.update(INIT_VECTOR_A3); - mac.update(cipher); - mac.update(al); - byte[] sig = mac.doFinal(); - assertEquals(32, sig.length); - byte[] authTag = new byte[16]; - System.arraycopy(sig, 0, authTag, 0, 16); - - JweCompactProducer p = new JweCompactProducer(headers, - encryptedCek, - INIT_VECTOR_A3, - cipher, - authTag); - assertEquals(JWE_OUTPUT_A3, p.getJweContent()); + Algorithm.A128KW.getJwtName()); + JweEncryptionProvider encryption = new AesCbcHmacJweEncryption(headers, + CONTENT_ENCRYPTION_KEY_A3, + INIT_VECTOR_A3, + keyEncryption); + String encryptedText = encryption.encrypt(specPlainText.getBytes("UTF-8"), null); + assertEquals(JWE_OUTPUT_A3, encryptedText); } @Test @@ -162,7 +133,8 @@ public class JweCompactReaderWriterTest extends Assert { } private String encryptContent(String content, boolean createIfException) throws Exception { - RSAPublicKey publicKey = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED, RSA_PUBLIC_EXPONENT_ENCODED); + RSAPublicKey publicKey = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED_A1, + RSA_PUBLIC_EXPONENT_ENCODED_A1); SecretKey key = createSecretKey(createIfException); String jwtKeyName = null; if (key == null) { @@ -175,15 +147,16 @@ public class JweCompactReaderWriterTest extends Assert { Algorithm.RSA_OAEP.getJwtName(), key, jwtKeyName, - INIT_VECTOR); + INIT_VECTOR_A1); return encryptor.encrypt(content.getBytes("UTF-8"), null); } private String encryptContentDirect(SecretKey key, String content) throws Exception { - DirectKeyJweEncryption encryptor = new DirectKeyJweEncryption(key, INIT_VECTOR); + DirectKeyJweEncryption encryptor = new DirectKeyJweEncryption(key, INIT_VECTOR_A1); return encryptor.encrypt(content.getBytes("UTF-8"), null); } private void decrypt(String jweContent, String plainContent, boolean unwrap) throws Exception { - RSAPrivateKey privateKey = CryptoUtils.getRSAPrivateKey(RSA_MODULUS_ENCODED, RSA_PRIVATE_EXPONENT_ENCODED); + RSAPrivateKey privateKey = CryptoUtils.getRSAPrivateKey(RSA_MODULUS_ENCODED_A1, + RSA_PRIVATE_EXPONENT_ENCODED_A1); RSAJweDecryption decryptor = new RSAJweDecryption(privateKey, unwrap); String decryptedText = decryptor.decrypt(jweContent).getContentText(); assertEquals(decryptedText, plainContent); @@ -196,7 +169,7 @@ public class JweCompactReaderWriterTest extends Assert { private SecretKey createSecretKey(boolean createIfException) throws Exception { SecretKey key = null; if (Cipher.getMaxAllowedKeyLength("AES") > 128) { - key = CryptoUtils.createSecretKeySpec(CONTENT_ENCRYPTION_KEY, "AES"); + key = CryptoUtils.createSecretKeySpec(CONTENT_ENCRYPTION_KEY_A1, "AES"); } else if (createIfException) { key = CryptoUtils.createSecretKeySpec(CryptoUtils.generateSecureRandomBytes(128 / 8), "AES"); }
