Repository: cxf Updated Branches: refs/heads/master a3bf2a80b -> 632cb29d8
Creating some utility ECDH code Project: http://git-wip-us.apache.org/repos/asf/cxf/repo Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/632cb29d Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/632cb29d Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/632cb29d Branch: refs/heads/master Commit: 632cb29d89ea23bca39791ef774db5c53b752a09 Parents: a3bf2a8 Author: Sergey Beryozkin <[email protected]> Authored: Tue Dec 30 17:06:04 2014 +0000 Committer: Sergey Beryozkin <[email protected]> Committed: Tue Dec 30 17:06:04 2014 +0000 ---------------------------------------------------------------------- .../cxf/rs/security/jose/JoseConstants.java | 4 + .../cxf/rs/security/jose/jwe/JweUtils.java | 86 +++++++++++++++++- .../jose/jwe/JweCompactReaderWriterTest.java | 94 +++----------------- 3 files changed, 100 insertions(+), 84 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cxf/blob/632cb29d/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java index 39b86c7..e131147 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/JoseConstants.java @@ -71,6 +71,10 @@ public final class JoseConstants { public static final String ECDH_ES_DIRECT_ALGO = "ECDH-ES"; + public static final String ECDH_ES_A128KW_ALGO = "ECDH-ES+A128KW"; + public static final String ECDH_ES_A192KW_ALGO = "ECDH-ES+A192KW"; + public static final String ECDH_ES_A256KW_ALGO = "ECDH-ES+A256KW"; + public static final String PBES2_HS256_A128KW_ALGO = "PBES2-HS256+A128KW"; public static final String PBES2_HS384_A192KW_ALGO = "PBES2-HS384+A192KW"; public static final String PBES2_HS512_A256KW_ALGO = "PBES2-HS512+A256KW"; http://git-wip-us.apache.org/repos/asf/cxf/blob/632cb29d/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java index ec0a69c..62ecbb0 100644 --- a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java +++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/JweUtils.java @@ -18,13 +18,20 @@ */ package org.apache.cxf.rs.security.jose.jwe; +import java.nio.ByteBuffer; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; import java.util.Collections; import java.util.Properties; +import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; +import org.apache.cxf.common.util.StringUtils; +import org.apache.cxf.common.util.crypto.MessageDigestUtils; import org.apache.cxf.jaxrs.utils.JAXRSUtils; import org.apache.cxf.message.Message; import org.apache.cxf.rs.security.jose.JoseConstants; @@ -354,11 +361,88 @@ public final class JweUtils { getContentDecryptionAlgorithm(contentDecryptionAlgo)); } } - public static boolean validateCriticalHeaders(JoseHeaders headers) { //TODO: Validate JWE specific constraints return JoseUtils.validateCriticalHeaders(headers); } + public static byte[] getECDHKey(JsonWebKey privateKey, + JsonWebKey peerPublicKey, + byte[] partyUInfo, + byte[] partyVInfo, + String algoName, + int algoKeyBitLen) { + return getECDHKey(JwkUtils.toECPrivateKey(privateKey), + JwkUtils.toECPublicKey(peerPublicKey), + partyUInfo, partyVInfo, algoName, algoKeyBitLen); + } + public static byte[] getECDHKey(ECPrivateKey privateKey, + ECPublicKey peerPublicKey, + byte[] partyUInfo, + byte[] partyVInfo, + String algoName, + int algoKeyBitLen) { + byte[] keyZ = generateKeyZ(privateKey, peerPublicKey); + return calculateDerivedKey(keyZ, algoName, partyUInfo, partyVInfo, algoKeyBitLen); + } + + private static byte[] calculateDerivedKey(byte[] keyZ, + String algoName, + byte[] apuBytes, + byte[] apvBytes, + int algoKeyBitLen) { + final byte[] emptyPartyInfo = new byte[4]; + + if (apuBytes != null && apvBytes != null && Arrays.equals(apuBytes, apvBytes)) { + throw new SecurityException(); + } + byte[] algorithmId = concatenateDatalenAndData(StringUtils.toBytesASCII(algoName)); + byte[] partyUInfo = apuBytes == null ? emptyPartyInfo : concatenateDatalenAndData(apuBytes); + byte[] partyVInfo = apvBytes == null ? emptyPartyInfo : concatenateDatalenAndData(apvBytes); + byte[] suppPubInfo = datalenToBytes(algoKeyBitLen); + + byte[] otherInfo = new byte[algorithmId.length + + partyUInfo.length + + partyVInfo.length + + suppPubInfo.length]; + System.arraycopy(algorithmId, 0, otherInfo, 0, algorithmId.length); + System.arraycopy(partyUInfo, 0, otherInfo, algorithmId.length, partyUInfo.length); + System.arraycopy(partyVInfo, 0, otherInfo, algorithmId.length + partyUInfo.length, partyVInfo.length); + System.arraycopy(suppPubInfo, 0, otherInfo, algorithmId.length + partyUInfo.length + partyVInfo.length, + suppPubInfo.length); + + + byte[] concatKDF = new byte[36 + otherInfo.length]; + concatKDF[3] = 1; + System.arraycopy(keyZ, 0, concatKDF, 4, keyZ.length); + System.arraycopy(otherInfo, 0, concatKDF, 36, otherInfo.length); + try { + byte[] round1Hash = MessageDigestUtils.createDigest(concatKDF, MessageDigestUtils.ALGO_SHA_256); + return Arrays.copyOf(round1Hash, algoKeyBitLen / 8); + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + private static byte[] generateKeyZ(ECPrivateKey privateKey, ECPublicKey publicKey) { + try { + KeyAgreement ka = KeyAgreement.getInstance("ECDH"); + ka.init(privateKey); + ka.doPhase(publicKey, true); + return ka.generateSecret(); + } catch (Exception ex) { + throw new SecurityException(ex); + } + } + private static byte[] concatenateDatalenAndData(byte[] bytesASCII) { + final byte[] datalen = datalenToBytes(bytesASCII.length); + byte[] all = new byte[4 + bytesASCII.length]; + System.arraycopy(datalen, 0, all, 0, 4); + System.arraycopy(bytesASCII, 0, all, 4, bytesASCII.length); + return all; + } + private static byte[] datalenToBytes(int len) { + ByteBuffer buf = ByteBuffer.allocate(4); + return buf.putInt(len).array(); + } private static JweHeaders prepareJweHeaders(String keyEncryptionAlgo, String contentEncryptionAlgo, String compression) { http://git-wip-us.apache.org/repos/asf/cxf/blob/632cb29d/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweCompactReaderWriterTest.java ---------------------------------------------------------------------- diff --git a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweCompactReaderWriterTest.java b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweCompactReaderWriterTest.java index 9204f3a..649e927 100644 --- a/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweCompactReaderWriterTest.java +++ b/rt/rs/security/jose/src/test/java/org/apache/cxf/rs/security/jose/jwe/JweCompactReaderWriterTest.java @@ -18,7 +18,6 @@ */ package org.apache.cxf.rs.security.jose.jwe; -import java.nio.ByteBuffer; import java.security.Security; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; @@ -27,13 +26,11 @@ import java.security.interfaces.RSAPublicKey; import java.util.Arrays; import javax.crypto.Cipher; -import javax.crypto.KeyAgreement; import javax.crypto.SecretKey; import org.apache.cxf.common.util.Base64UrlUtility; import org.apache.cxf.common.util.StringUtils; import org.apache.cxf.common.util.crypto.CryptoUtils; -import org.apache.cxf.common.util.crypto.MessageDigestUtils; import org.apache.cxf.rs.security.jose.JoseConstants; import org.apache.cxf.rs.security.jose.JoseHeaders; import org.apache.cxf.rs.security.jose.JoseUtils; @@ -141,15 +138,11 @@ public class JweCompactReaderWriterTest extends Assert { "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck"); - byte[] keyZ = generateKeyZ(alicePrivateKey, bobPublicKey); byte[] apuBytes = StringUtils.toBytesUTF8("Alice"); byte[] apvBytes = StringUtils.toBytesUTF8("Bob"); - byte[] derivedKey = calculateDerivedKey(keyZ, - Algorithm.A128GCM.getJwtName(), - apuBytes, - apvBytes, - Algorithm.A128GCM.getKeySizeBits()); + byte[] derivedKey = JweUtils.getECDHKey(alicePrivateKey, bobPublicKey, apuBytes, apvBytes, + Algorithm.A128GCM.getJwtName(), Algorithm.A128GCM.getKeySizeBits()); assertEquals("VqqN6vgjbSBcIijNcacQGg", Base64UrlUtility.encode(derivedKey)); JweHeaders headers = new JweHeaders(); @@ -159,90 +152,25 @@ public class JweCompactReaderWriterTest extends Assert { headers.setHeader("apv", Base64UrlUtility.encode(apvBytes)); headers.setJsonWebKey("epv", JwkUtils.fromECPublicKey(alicePublicKey, JsonWebKey.EC_CURVE_P256)); - ECPrivateKey bobPrivateKey = - CryptoUtils.getECPrivateKey(JsonWebKey.EC_CURVE_P256, - "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"); - byte[] derivedKey2 = calculateDerivedKeyFromHeaders(bobPrivateKey, - headers, + byte[] derivedKey2 = calculateDerivedKeyFromHeaders(headers, headers.getContentEncryptionAlgorithm(), Algorithm.A128GCM.getKeySizeBits()); assertTrue(Arrays.equals(derivedKey2, derivedKey)); } - private static byte[] calculateDerivedKeyFromHeaders(ECPrivateKey privateKey, - JoseHeaders headers, + private static byte[] calculateDerivedKeyFromHeaders(JoseHeaders headers, String algoName, int algoKeyLen) { - JsonWebKey ephemeralJwk = headers.getJsonWebKey("epv"); - byte[] keyZ = generateKeyZ(privateKey, JwkUtils.toECPublicKey(ephemeralJwk)); + ECPrivateKey bobPrivateKey = + CryptoUtils.getECPrivateKey(JsonWebKey.EC_CURVE_P256, + "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw"); + + 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 calculateDerivedKey(keyZ, - algoName, - apuBytes, - apvBytes, - algoKeyLen); - } - - private static byte[] calculateDerivedKey(byte[] keyZ, - String algoName, - byte[] apuBytes, - byte[] apvBytes, - int algoKeyBitLen) { - final byte[] emptyPartyInfo = new byte[4]; - - if (apuBytes != null && apvBytes != null && Arrays.equals(apuBytes, apvBytes)) { - throw new SecurityException(); - } - byte[] algorithmId = concatenateDatalenAndData(StringUtils.toBytesASCII(algoName)); - byte[] partyUInfo = apuBytes == null ? emptyPartyInfo : concatenateDatalenAndData(apuBytes); - byte[] partyVInfo = apvBytes == null ? emptyPartyInfo : concatenateDatalenAndData(apvBytes); - byte[] suppPubInfo = datalenToBytes(algoKeyBitLen); - - byte[] otherInfo = new byte[algorithmId.length - + partyUInfo.length - + partyVInfo.length - + suppPubInfo.length]; - System.arraycopy(algorithmId, 0, otherInfo, 0, algorithmId.length); - System.arraycopy(partyUInfo, 0, otherInfo, algorithmId.length, partyUInfo.length); - System.arraycopy(partyVInfo, 0, otherInfo, algorithmId.length + partyUInfo.length, partyVInfo.length); - System.arraycopy(suppPubInfo, 0, otherInfo, algorithmId.length + partyUInfo.length + partyVInfo.length, - suppPubInfo.length); - - - byte[] concatKDF = new byte[36 + otherInfo.length]; - concatKDF[3] = 1; - System.arraycopy(keyZ, 0, concatKDF, 4, keyZ.length); - System.arraycopy(otherInfo, 0, concatKDF, 36, otherInfo.length); - try { - byte[] round1Hash = MessageDigestUtils.createDigest(concatKDF, MessageDigestUtils.ALGO_SHA_256); - return Arrays.copyOf(round1Hash, algoKeyBitLen / 8); - } catch (Exception ex) { - throw new SecurityException(ex); - } - } - private static byte[] generateKeyZ(ECPrivateKey privateKey, ECPublicKey publicKey) { - try { - KeyAgreement ka = KeyAgreement.getInstance("ECDH"); - ka.init(privateKey); - ka.doPhase(publicKey, true); - return ka.generateSecret(); - } catch (Exception ex) { - throw new SecurityException(ex); - } - } - private static byte[] concatenateDatalenAndData(byte[] bytesASCII) { - final byte[] datalen = datalenToBytes(bytesASCII.length); - byte[] all = new byte[4 + bytesASCII.length]; - System.arraycopy(datalen, 0, all, 0, 4); - System.arraycopy(bytesASCII, 0, all, 4, bytesASCII.length); - return all; - } - private static byte[] datalenToBytes(int len) { - ByteBuffer buf = ByteBuffer.allocate(4); - return buf.putInt(len).array(); + return JweUtils.getECDHKey(bobPrivateKey, JwkUtils.toECPublicKey(publicJwk), + apuBytes, apvBytes, algoName, algoKeyLen); } @Test public void testEncryptDecryptRSA15WrapA128CBCHS256() throws Exception {
