Repository: cxf Updated Branches: refs/heads/master a97f886f3 -> e84bdde24
Completing all of Jose algorithm coverage with a ESDH wrap prototype Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/e84bdde2 Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/e84bdde2 Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/e84bdde2 Branch: refs/heads/master Commit: e84bdde247a896f2daf2f853642b9af56dab1cfa Parents: a97f886 Author: Sergey Beryozkin <[email protected]> Authored: Mon Jan 5 22:02:48 2015 +0300 Committer: Sergey Beryozkin <[email protected]> Committed: Mon Jan 5 22:02:48 2015 +0300 ---------------------------------------------------------------------- .../cxf/rs/security/jose/jwa/Algorithm.java | 14 +++- .../jwe/EcdhAesWrapKeyDecryptionAlgorithm.java | 52 +++++++++++++++ .../jwe/EcdhAesWrapKeyEncryptionAlgorithm.java | 70 ++++++++++++++++++++ .../jose/jwe/EcdhDirectKeyJweDecryption.java | 24 +++---- .../jose/jwe/EcdhDirectKeyJweEncryption.java | 48 +++++++++----- 5 files changed, 177 insertions(+), 31 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/e84bdde2/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/Algorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/Algorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/Algorithm.java index 056ddc4..f6e167e 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/Algorithm.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/Algorithm.java @@ -56,7 +56,9 @@ public enum Algorithm { PBES2_HS256_A128KW(JoseConstants.PBES2_HS256_A128KW_ALGO, "AESWrap", 128), PBES2_HS384_A192KW(JoseConstants.PBES2_HS384_A192KW_ALGO, "AESWrap", 192), PBES2_HS512_A256KW(JoseConstants.PBES2_HS512_A256KW_ALGO, "AESWrap", 256), - + ECDH_ES_A128KW(JoseConstants.ECDH_ES_A128KW_ALGO, "AESWrap", 128), + ECDH_ES_A192KW(JoseConstants.ECDH_ES_A192KW_ALGO, "AESWrap", 192), + ECDH_ES_A256KW(JoseConstants.ECDH_ES_A256KW_ALGO, "AESWrap", 256), // Content Encryption A128GCM(JoseConstants.A128GCM_ALGO, "AES/GCM/NoPadding", 128), A192GCM(JoseConstants.A192GCM_ALGO, "AES/GCM/NoPadding", 192), @@ -120,6 +122,10 @@ public enum Algorithm { new HashSet<String>(Arrays.asList(PBES2_HS256_A128KW.getJwtName(), PBES2_HS384_A192KW.getJwtName(), PBES2_HS512_A256KW.getJwtName())); + public static final Set<String> ECDH_ES_SET = + new HashSet<String>(Arrays.asList(ECDH_ES_A128KW.getJwtName(), + ECDH_ES_A192KW.getJwtName(), + ECDH_ES_A256KW.getJwtName())); private static final Map<String, String> JAVA_TO_JWT_NAMES; private static final Map<String, String> JWT_TO_JAVA_NAMES; @@ -180,6 +186,9 @@ public enum Algorithm { JWT_TO_JAVA_NAMES.put(JoseConstants.PBES2_HS256_A128KW_ALGO, AES_WRAP_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JoseConstants.PBES2_HS384_A192KW_ALGO, AES_WRAP_ALGO_JAVA); JWT_TO_JAVA_NAMES.put(JoseConstants.PBES2_HS512_A256KW_ALGO, AES_WRAP_ALGO_JAVA); + JWT_TO_JAVA_NAMES.put(JoseConstants.ECDH_ES_A128KW_ALGO, AES_WRAP_ALGO_JAVA); + JWT_TO_JAVA_NAMES.put(JoseConstants.ECDH_ES_A192KW_ALGO, AES_WRAP_ALGO_JAVA); + JWT_TO_JAVA_NAMES.put(JoseConstants.ECDH_ES_A256KW_ALGO, AES_WRAP_ALGO_JAVA); } private final String jwtName; private final String javaName; @@ -248,6 +257,9 @@ public enum Algorithm { public static boolean isPbesHsWrap(String algo) { return PBES_HS_SET.contains(algo); } + public static boolean isEcdhEsWrap(String algo) { + return ECDH_ES_SET.contains(algo); + } public static boolean isAesGcm(String algo) { return AES_GCM_CEK_SET.contains(algo); } http://git-wip-us.apache.org/repos/asf/cxf/blob/e84bdde2/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyDecryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyDecryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyDecryptionAlgorithm.java new file mode 100644 index 0000000..025d2db --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyDecryptionAlgorithm.java @@ -0,0 +1,52 @@ +/** + * 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.interfaces.ECPrivateKey; + +import org.apache.cxf.rs.security.jose.jwa.Algorithm; + +public class EcdhAesWrapKeyDecryptionAlgorithm implements KeyDecryptionAlgorithm { + private ECPrivateKey key; + private String algo; + public EcdhAesWrapKeyDecryptionAlgorithm(ECPrivateKey key) { + this(key, Algorithm.ECDH_ES_A128KW.getJwtName()); + } + public EcdhAesWrapKeyDecryptionAlgorithm(ECPrivateKey key, String algo) { + this.key = key; + this.algo = algo; + } + @Override + public byte[] getDecryptedContentEncryptionKey(JweCompactConsumer consumer) { + byte[] derivedKey = + EcdhDirectKeyJweDecryption.getDecryptedContentEncryptionKeyFromHeaders(consumer.getJweHeaders(), key); + KeyDecryptionAlgorithm aesWrap = new AesWrapKeyDecryptionAlgorithm(derivedKey) { + protected boolean isValidAlgorithmFamily(String wrapAlgo) { + return Algorithm.isEcdhEsWrap(wrapAlgo); + } + }; + return aesWrap.getDecryptedContentEncryptionKey(consumer); + } + + @Override + public String getAlgorithm() { + return algo; + } + +} http://git-wip-us.apache.org/repos/asf/cxf/blob/e84bdde2/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyEncryptionAlgorithm.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyEncryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyEncryptionAlgorithm.java new file mode 100644 index 0000000..ecfa68e --- /dev/null +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhAesWrapKeyEncryptionAlgorithm.java @@ -0,0 +1,70 @@ +/** + * 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.interfaces.ECPublicKey; +import java.util.HashMap; +import java.util.Map; + +import org.apache.cxf.rs.security.jose.jwa.Algorithm; +import org.apache.cxf.rs.security.jose.jwe.EcdhDirectKeyJweEncryption.EcdhHelper; + +public class EcdhAesWrapKeyEncryptionAlgorithm implements KeyEncryptionAlgorithm { + + private static final Map<String, String> ECDH_AES_MAP; + static { + ECDH_AES_MAP = new HashMap<String, String>(); + ECDH_AES_MAP.put(Algorithm.ECDH_ES_A128KW.getJwtName(), Algorithm.A128KW.getJwtName()); + ECDH_AES_MAP.put(Algorithm.ECDH_ES_A192KW.getJwtName(), Algorithm.A192KW.getJwtName()); + ECDH_AES_MAP.put(Algorithm.ECDH_ES_A256KW.getJwtName(), Algorithm.A256KW.getJwtName()); + } + private String keyAlgo; + private EcdhHelper helper; + + public EcdhAesWrapKeyEncryptionAlgorithm(ECPublicKey peerPublicKey, + String curve, + String apuString, + String apvString, + String keyAlgo) { + + this.keyAlgo = keyAlgo; + helper = new EcdhHelper(peerPublicKey, curve, apuString, apvString, keyAlgo); + } + + @Override + public byte[] getEncryptedContentEncryptionKey(JweHeaders headers, byte[] cek) { + final byte[] derivedKey = helper.getDerivedKey(headers); + Algorithm jwtAlgo = Algorithm.valueOf(ECDH_AES_MAP.get(keyAlgo)); + KeyEncryptionAlgorithm aesWrap = new AesWrapKeyEncryptionAlgorithm(derivedKey, + jwtAlgo.getJwtName()) { + protected void checkAlgorithms(JweHeaders headers) { + // complete + } + protected String getKeyEncryptionAlgoJava(JweHeaders headers) { + return Algorithm.AES_WRAP_ALGO_JAVA; + } + }; + return aesWrap.getEncryptedContentEncryptionKey(headers, cek); + } + + @Override + public String getAlgorithm() { + return keyAlgo; + } +} http://git-wip-us.apache.org/repos/asf/cxf/blob/e84bdde2/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweDecryption.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweDecryption.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweDecryption.java index 01b4ffb..688ecfa 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweDecryption.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweDecryption.java @@ -32,6 +32,17 @@ public class EcdhDirectKeyJweDecryption extends DirectKeyJweDecryption { new EcdhDirectKeyDecryptionAlgorithm(privateKey), new AesGcmContentDecryptionAlgorithm(supportedCtAlgo)); } + protected static byte[] getDecryptedContentEncryptionKeyFromHeaders(JweHeaders headers, + ECPrivateKey privateKey) { + Algorithm jwtAlgo = Algorithm.valueOf(headers.getContentEncryptionAlgorithm()); + JsonWebKey publicJwk = headers.getJsonWebKey("epv"); + String apuHeader = (String)headers.getHeader("apu"); + byte[] apuBytes = apuHeader == null ? null : JoseUtils.decode(apuHeader); + String apvHeader = (String)headers.getHeader("apv"); + byte[] apvBytes = apvHeader == null ? null : JoseUtils.decode(apvHeader); + return JweUtils.getECDHKey(privateKey, JwkUtils.toECPublicKey(publicJwk), + apuBytes, apvBytes, jwtAlgo.getJwtName(), jwtAlgo.getKeySizeBits()); + } protected static class EcdhDirectKeyDecryptionAlgorithm extends DirectKeyDecryptionAlgorithm { private ECPrivateKey privateKey; public EcdhDirectKeyDecryptionAlgorithm(ECPrivateKey privateKey) { @@ -42,18 +53,7 @@ public class EcdhDirectKeyJweDecryption extends DirectKeyJweDecryption { public byte[] getDecryptedContentEncryptionKey(JweCompactConsumer consumer) { super.validateKeyEncryptionKey(consumer); - return getDecryptedContentEncryptionKeyFromHeaders(consumer.getJweHeaders()); - } - - protected byte[] getDecryptedContentEncryptionKeyFromHeaders(JweHeaders headers) { - Algorithm jwtAlgo = Algorithm.valueOf(headers.getContentEncryptionAlgorithm()); - JsonWebKey publicJwk = headers.getJsonWebKey("epv"); - String apuHeader = (String)headers.getHeader("apu"); - byte[] apuBytes = apuHeader == null ? null : JoseUtils.decode(apuHeader); - String apvHeader = (String)headers.getHeader("apv"); - byte[] apvBytes = apvHeader == null ? null : JoseUtils.decode(apvHeader); - return JweUtils.getECDHKey(privateKey, JwkUtils.toECPublicKey(publicJwk), - apuBytes, apvBytes, jwtAlgo.getJwtName(), jwtAlgo.getKeySizeBits()); + return getDecryptedContentEncryptionKeyFromHeaders(consumer.getJweHeaders(), privateKey); } } } http://git-wip-us.apache.org/repos/asf/cxf/blob/e84bdde2/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweEncryption.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweEncryption.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweEncryption.java index 1943444..07ce2f4 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweEncryption.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/EcdhDirectKeyJweEncryption.java @@ -39,45 +39,53 @@ public class EcdhDirectKeyJweEncryption extends DirectKeyJweEncryption { super(new JweHeaders(ctAlgo), new EcdhAesGcmContentEncryptionAlgorithm(peerPublicKey, curve, - toBytes(apuString), - toBytes(apvString), + apuString, + apvString, ctAlgo), new EcdhDirectKeyEncryptionAlgorithm()); } - private static byte[] toBytes(String str) { - return str == null ? null : StringUtils.toBytesUTF8(str); - } protected static class EcdhDirectKeyEncryptionAlgorithm extends DirectKeyEncryptionAlgorithm { protected void checkKeyEncryptionAlgorithm(JweHeaders headers) { headers.setKeyEncryptionAlgorithm(JoseConstants.ECDH_ES_DIRECT_ALGO); } } protected static class EcdhAesGcmContentEncryptionAlgorithm extends AesGcmContentEncryptionAlgorithm { + private EcdhHelper helper; + public EcdhAesGcmContentEncryptionAlgorithm(ECPublicKey peerPublicKey, + String curve, + String apuString, + String apvString, + String ctAlgo) { + super(ctAlgo); + helper = new EcdhHelper(peerPublicKey, curve, apuString, apvString, ctAlgo); + } + public byte[] getContentEncryptionKey(JweHeaders headers) { + return helper.getDerivedKey(headers); + } + } + + protected static class EcdhHelper { private ECPublicKey peerPublicKey; private String ecurve; private byte[] apuBytes; private byte[] apvBytes; - public EcdhAesGcmContentEncryptionAlgorithm(ECPublicKey peerPublicKey, + private String ctAlgo; + public EcdhHelper(ECPublicKey peerPublicKey, String curve, - byte[] apuBytes, - byte[] apvBytes, + String apuString, + String apvString, String ctAlgo) { - super(ctAlgo); + this.ctAlgo = ctAlgo; this.peerPublicKey = peerPublicKey; this.ecurve = curve; - this.apuBytes = apuBytes; - this.apvBytes = apvBytes; + this.apuBytes = toBytes(apuString); + this.apvBytes = toBytes(apvString); } - public byte[] getContentEncryptionKey(JweHeaders headers) { + public byte[] getDerivedKey(JweHeaders headers) { KeyPair pair = CryptoUtils.generateECKeyPair(ecurve); ECPublicKey publicKey = (ECPublicKey)pair.getPublic(); ECPrivateKey privateKey = (ECPrivateKey)pair.getPrivate(); - return doGetContentEncryptionKey(headers, publicKey, privateKey); - } - protected byte[] doGetContentEncryptionKey(JweHeaders headers, - ECPublicKey publicKey, - ECPrivateKey privateKey) { - Algorithm jwtAlgo = Algorithm.valueOf(super.getAlgorithm()); + Algorithm jwtAlgo = Algorithm.valueOf(ctAlgo); headers.setHeader("apu", Base64UrlUtility.encode(apuBytes)); headers.setHeader("apv", Base64UrlUtility.encode(apvBytes)); @@ -87,6 +95,10 @@ public class EcdhDirectKeyJweEncryption extends DirectKeyJweEncryption { jwtAlgo.getJwtName(), jwtAlgo.getKeySizeBits()); } + private byte[] toBytes(String str) { + return str == null ? null : StringUtils.toBytesUTF8(str); + } + } }
