org.apache.cxf.rs.security.jose.jwe.JweCompactReaderWriterTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cxf.rs.security.jose.jwe.JweCompactReaderWriterTest.java

Source

/**
 * 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.nio.charset.StandardCharsets;
import java.security.Security;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;

import org.apache.cxf.common.util.Base64UrlUtility;
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.jwa.KeyAlgorithm;
import org.apache.cxf.rs.security.jose.jwk.JsonWebKey;
import org.apache.cxf.rs.security.jose.jws.JwsCompactReaderWriterTest;
import org.apache.cxf.rt.security.crypto.CryptoUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;

public class JweCompactReaderWriterTest extends Assert {
    // A1 example
    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 };
    static final String RSA_MODULUS_ENCODED_A1 = "oahUIoWw0K0usKNuOR6H4wkf4oBUXHTxRvgb48E-BVvxkeDNjbC4he8rUW"
            + "cJoZmds2h7M70imEVhRU5djINXtqllXI4DFqcI1DgjT9LewND8MW2Krf3S"
            + "psk_ZkoFnilakGygTwpZ3uesH-PFABNIUYpOiN15dsQRkgr0vEhxN92i2a"
            + "sbOenSZeyaxziK72UwxrrKoExv6kc5twXTq4h-QChLOln0_mtUZwfsRaMS"
            + "tPs6mS6XrgxnxbWhojf663tuEQueGC-FCMfra36C9knDFGzKsNa7LZK2dj"
            + "YgyD3JR_MB_4NUJW_TqOQtwHYbxevoJArm-L5StowjzGy-_bq6Gw";
    static final String RSA_PUBLIC_EXPONENT_ENCODED_A1 = "AQAB";
    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";

    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
    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, 45,
            111, 107, 9, (byte) 219, (byte) 200, (byte) 177, 0, (byte) 240, (byte) 143, (byte) 156, 44,
            (byte) 207 };
    static final byte[] INIT_VECTOR_A3 = { 3, 22, 60, 12, 43, 67, 104, 105, 108, 108, 105, 99, 111, 116, 104, 101 };
    static final String KEY_ENCRYPTION_KEY_A3 = "GawgguFyGrWKav7AX4VKUg";
    private static final String JWE_OUTPUT_A3 = "eyJhbGciOiJBMTI4S1ciLCJlbmMiOiJBMTI4Q0JDLUhTMjU2In0"
            + ".6KB707dM9YTIgHtLvtgWQ8mKwboJW3of9locizkDTHzBC2IlrT1oOQ" + ".AxY8DCtDaGlsbGljb3RoZQ"
            + ".KDlTtXchhZTGufMYmOYGS4HffxPSUrfmqCHXaI9wOGY" + ".U0m_YmjN04DJvceFICbCVQ";

    @BeforeClass
    public static void registerBouncyCastleIfNeeded() throws Exception {
        try {
            Cipher.getInstance(AlgorithmUtils.AES_GCM_ALGO_JAVA);
            Cipher.getInstance(AlgorithmUtils.AES_CBC_ALGO_JAVA);
        } catch (Throwable t) {
            Security.addProvider(new BouncyCastleProvider());
        }
    }

    @AfterClass
    public static void unregisterBouncyCastleIfNeeded() throws Exception {
        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Test
    public void testEncryptDecryptAesWrapA128CBCHS256() throws Exception {
        final String specPlainText = "Live long and prosper.";

        byte[] cekEncryptionKey = Base64UrlUtility.decode(KEY_ENCRYPTION_KEY_A3);

        AesWrapKeyEncryptionAlgorithm keyEncryption = new AesWrapKeyEncryptionAlgorithm(cekEncryptionKey,
                KeyAlgorithm.A128KW);
        JweEncryptionProvider encryption = new AesCbcHmacJweEncryption(ContentAlgorithm.A128CBC_HS256,
                CONTENT_ENCRYPTION_KEY_A3, INIT_VECTOR_A3, keyEncryption);
        String jweContent = encryption.encrypt(specPlainText.getBytes(StandardCharsets.UTF_8), null);
        assertEquals(JWE_OUTPUT_A3, jweContent);

        AesWrapKeyDecryptionAlgorithm keyDecryption = new AesWrapKeyDecryptionAlgorithm(cekEncryptionKey);
        JweDecryptionProvider decryption = new AesCbcHmacJweDecryption(keyDecryption);
        String decryptedText = decryption.decrypt(jweContent).getContentText();
        assertEquals(specPlainText, decryptedText);
    }

    @Test
    public void testECDHESDirectKeyEncryption() throws Exception {
        ECPrivateKey bobPrivateKey = CryptoUtils.getECPrivateKey(JsonWebKey.EC_CURVE_P256,
                "VEmDZpDXXK8p8N0Cndsxs924q6nS1RXFASRl6BfUqdw");

        final ECPublicKey bobPublicKey = CryptoUtils.getECPublicKey(JsonWebKey.EC_CURVE_P256,
                "weNJy2HscCSM6AEDTDg04biOvhFhyyWvOHQfeF_PxMQ", "e8lnCO-AlStT-NJVX-crhB7QRYhiix03illJOVAOyck");
        JweEncryptionProvider jweOut = new EcdhDirectKeyJweEncryption(bobPublicKey, JsonWebKey.EC_CURVE_P256,
                "Alice", "Bob", ContentAlgorithm.A128GCM);

        String jweOutput = jweOut.encrypt("Hello".getBytes(), null);
        JweDecryptionProvider jweIn = new EcdhDirectKeyJweDecryption(bobPrivateKey, ContentAlgorithm.A128GCM);
        assertEquals("Hello", jweIn.decrypt(jweOutput).getContentText());
    }

    @Test
    public void testEncryptDecryptRSA15WrapA128CBCHS256() throws Exception {
        final String specPlainText = "Live long and prosper.";

        RSAPublicKey publicKey = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED_A1,
                RSA_PUBLIC_EXPONENT_ENCODED_A1);

        KeyEncryptionProvider keyEncryption = new RSAKeyEncryptionAlgorithm(publicKey, KeyAlgorithm.RSA1_5);

        JweEncryptionProvider encryption = new AesCbcHmacJweEncryption(ContentAlgorithm.A128CBC_HS256,
                CONTENT_ENCRYPTION_KEY_A3, INIT_VECTOR_A3, keyEncryption);
        String jweContent = encryption.encrypt(specPlainText.getBytes(StandardCharsets.UTF_8), null);

        RSAPrivateKey privateKey = CryptoUtils.getRSAPrivateKey(RSA_MODULUS_ENCODED_A1,
                RSA_PRIVATE_EXPONENT_ENCODED_A1);
        KeyDecryptionProvider keyDecryption = new RSAKeyDecryptionAlgorithm(privateKey, KeyAlgorithm.RSA1_5);
        JweDecryptionProvider decryption = new AesCbcHmacJweDecryption(keyDecryption);
        String decryptedText = decryption.decrypt(jweContent).getContentText();
        assertEquals(specPlainText, decryptedText);
    }

    @Test
    public void testEncryptDecryptAesGcmWrapA128CBCHS256() throws Exception {
        //
        // This test fails with the IBM JDK
        //
        if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
            return;
        }
        final String specPlainText = "Live long and prosper.";

        byte[] cekEncryptionKey = Base64UrlUtility.decode(KEY_ENCRYPTION_KEY_A3);

        AesGcmWrapKeyEncryptionAlgorithm keyEncryption = new AesGcmWrapKeyEncryptionAlgorithm(cekEncryptionKey,
                KeyAlgorithm.A128GCMKW);
        JweEncryptionProvider encryption = new AesCbcHmacJweEncryption(ContentAlgorithm.A128CBC_HS256,
                CONTENT_ENCRYPTION_KEY_A3, INIT_VECTOR_A3, keyEncryption);
        String jweContent = encryption.encrypt(specPlainText.getBytes(StandardCharsets.UTF_8), null);

        AesGcmWrapKeyDecryptionAlgorithm keyDecryption = new AesGcmWrapKeyDecryptionAlgorithm(cekEncryptionKey);
        JweDecryptionProvider decryption = new AesCbcHmacJweDecryption(keyDecryption);
        String decryptedText = decryption.decrypt(jweContent).getContentText();
        assertEquals(specPlainText, decryptedText);
    }

    @Test
    public void testEncryptDecryptSpecExample() throws Exception {
        final String specPlainText = "The true sign of intelligence is not knowledge but imagination.";
        String jweContent = encryptContent(specPlainText, true);

        decrypt(jweContent, specPlainText, true);
    }

    @Test
    public void testDirectKeyEncryptDecrypt() throws Exception {
        final String specPlainText = "The true sign of intelligence is not knowledge but imagination.";
        SecretKey key = createSecretKey(true);
        String jweContent = encryptContentDirect(key, specPlainText);

        decryptDirect(key, jweContent, specPlainText);
    }

    @Test
    public void testEncryptDecryptJwsToken() throws Exception {
        String jweContent = encryptContent(JwsCompactReaderWriterTest.ENCODED_TOKEN_SIGNED_BY_MAC, false);
        decrypt(jweContent, JwsCompactReaderWriterTest.ENCODED_TOKEN_SIGNED_BY_MAC, false);
    }

    private String encryptContent(String content, boolean createIfException) throws Exception {
        RSAPublicKey publicKey = CryptoUtils.getRSAPublicKey(RSA_MODULUS_ENCODED_A1,
                RSA_PUBLIC_EXPONENT_ENCODED_A1);
        SecretKey key = createSecretKey(createIfException);
        String jwtKeyName = null;
        if (key == null) {
            // the encryptor will generate it
            jwtKeyName = ContentAlgorithm.A128GCM.getJwaName();
        } else {
            jwtKeyName = AlgorithmUtils.toJwaName(key.getAlgorithm(), key.getEncoded().length * 8);
        }
        KeyEncryptionProvider keyEncryptionAlgo = new RSAKeyEncryptionAlgorithm(publicKey, KeyAlgorithm.RSA_OAEP);
        ContentEncryptionProvider contentEncryptionAlgo = new AesGcmContentEncryptionAlgorithm(
                key == null ? null : key.getEncoded(), INIT_VECTOR_A1, ContentAlgorithm.getAlgorithm(jwtKeyName));
        JweEncryptionProvider encryptor = new JweEncryption(keyEncryptionAlgo, contentEncryptionAlgo);
        return encryptor.encrypt(content.getBytes(StandardCharsets.UTF_8), null);
    }

    private String encryptContentDirect(SecretKey key, String content) throws Exception {
        JweEncryption encryptor = new JweEncryption(new DirectKeyEncryptionAlgorithm(),
                new AesGcmContentEncryptionAlgorithm(key, INIT_VECTOR_A1, ContentAlgorithm.A128GCM));
        return encryptor.encrypt(content.getBytes(StandardCharsets.UTF_8), null);
    }

    private void decrypt(String jweContent, String plainContent, boolean unwrap) throws Exception {
        RSAPrivateKey privateKey = CryptoUtils.getRSAPrivateKey(RSA_MODULUS_ENCODED_A1,
                RSA_PRIVATE_EXPONENT_ENCODED_A1);
        ContentAlgorithm algo = Cipher.getMaxAllowedKeyLength("AES") > 128 ? ContentAlgorithm.A256GCM
                : ContentAlgorithm.A128GCM;
        JweDecryptionProvider decryptor = new JweDecryption(new RSAKeyDecryptionAlgorithm(privateKey),
                new AesGcmContentDecryptionAlgorithm(algo));
        String decryptedText = decryptor.decrypt(jweContent).getContentText();
        assertEquals(decryptedText, plainContent);
    }

    private void decryptDirect(SecretKey key, String jweContent, String plainContent) throws Exception {
        JweDecryption decryptor = new JweDecryption(new DirectKeyDecryptionAlgorithm(key),
                new AesGcmContentDecryptionAlgorithm(ContentAlgorithm.A128GCM));
        String decryptedText = decryptor.decrypt(jweContent).getContentText();
        assertEquals(decryptedText, plainContent);
    }

    private SecretKey createSecretKey(boolean createIfException) throws Exception {
        SecretKey key = null;
        if (Cipher.getMaxAllowedKeyLength("AES") > 128) {
            key = CryptoUtils.createSecretKeySpec(CONTENT_ENCRYPTION_KEY_A1, "AES");
        } else if (createIfException) {
            key = CryptoUtils.createSecretKeySpec(CryptoUtils.generateSecureRandomBytes(128 / 8), "AES");
        }
        return key;
    }
}