You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2014/10/06 19:26:02 UTC

[09/10] [CXF-5944] Finalizing the current round of refactorings with introducing a dedicated rt rs security module, idea from Luigi Lo Iacono

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJwtMessageBodyWriter.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJwtMessageBodyWriter.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJwtMessageBodyWriter.java
new file mode 100644
index 0000000..e700ff7
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsJwtMessageBodyWriter.java
@@ -0,0 +1,60 @@
+/**
+ * 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.jaxrs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+
+import org.apache.cxf.rs.security.jose.JoseConstants;
+import org.apache.cxf.rs.security.jose.jws.JwsJwtCompactProducer;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
+import org.apache.cxf.rs.security.jose.jwt.JwtHeaders;
+import org.apache.cxf.rs.security.jose.jwt.JwtToken;
+
+public class JwsJwtMessageBodyWriter  extends AbstractJwsWriterProvider 
+    implements MessageBodyWriter<JwtToken> {
+    
+    @Override
+    public long getSize(JwtToken token, Class<?> cls, Type type, Annotation[] anns, MediaType mt) {
+        return -1;
+    }
+
+    @Override
+    public boolean isWriteable(Class<?> cls, Type type, Annotation[] anns, MediaType mt) {
+        return cls == JwtToken.class;
+    }
+
+    @Override
+    public void writeTo(JwtToken token, Class<?> cls, Type type, Annotation[] anns, MediaType mt,
+                        MultivaluedMap<String, Object> headers, OutputStream os) throws IOException,
+        WebApplicationException {
+        JwsJwtCompactProducer p = new JwsJwtCompactProducer(token);
+        JwtHeaders jwtHeaders = new JwtHeaders();
+        JwsSignatureProvider sigProvider = getInitializedSigProvider(jwtHeaders);
+        jwtHeaders.setContentType(JoseConstants.TYPE_JWT);
+        writeJws(p, sigProvider, os);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java
new file mode 100644
index 0000000..56279e5
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/JwsWriterInterceptor.java
@@ -0,0 +1,100 @@
+/**
+ * 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.jaxrs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.annotation.Priority;
+import javax.ws.rs.WebApplicationException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.ext.WriterInterceptor;
+import javax.ws.rs.ext.WriterInterceptorContext;
+
+import org.apache.cxf.common.util.Base64UrlOutputStream;
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.io.CachedOutputStream;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
+import org.apache.cxf.rs.security.jose.JoseConstants;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseHeadersWriter;
+import org.apache.cxf.rs.security.jose.jws.JwsCompactProducer;
+import org.apache.cxf.rs.security.jose.jws.JwsHeaders;
+import org.apache.cxf.rs.security.jose.jws.JwsOutputStream;
+import org.apache.cxf.rs.security.jose.jws.JwsSignature;
+import org.apache.cxf.rs.security.jose.jws.JwsSignatureProvider;
+import org.apache.cxf.rs.security.jose.jwt.JwtHeaders;
+
+@Priority(Priorities.JWS_WRITE_PRIORITY)
+public class JwsWriterInterceptor extends AbstractJwsWriterProvider implements WriterInterceptor {
+    private boolean contentTypeRequired = true;
+    private boolean useJwsOutputStream;
+    private JoseHeadersWriter writer = new JoseHeadersReaderWriter();
+    @Override
+    public void aroundWriteTo(WriterInterceptorContext ctx) throws IOException, WebApplicationException {
+        JwsHeaders headers = new JwsHeaders();
+        JwsSignatureProvider sigProvider = getInitializedSigProvider(headers);
+        setContentTypeIfNeeded(headers, ctx);
+        ctx.setMediaType(JAXRSUtils.toMediaType(JoseConstants.MEDIA_TYPE_JOSE_JSON));
+        OutputStream actualOs = ctx.getOutputStream();
+        if (useJwsOutputStream) {
+            JwsSignature jwsSignature = sigProvider.createJwsSignature(headers);
+            JwsOutputStream jwsStream = new JwsOutputStream(actualOs, jwsSignature);
+            byte[] headerBytes = writer.headersToJson(headers).getBytes("UTF-8");
+            Base64UrlUtility.encodeAndStream(headerBytes, 0, headerBytes.length, jwsStream);
+            jwsStream.write(new byte[]{'.'});
+                        
+            Base64UrlOutputStream base64Stream = new Base64UrlOutputStream(jwsStream);
+            ctx.setOutputStream(base64Stream);
+            ctx.proceed();
+            base64Stream.flush();
+            jwsStream.flush();
+        } else {
+            CachedOutputStream cos = new CachedOutputStream(); 
+            ctx.setOutputStream(cos);
+            ctx.proceed();
+            JwsCompactProducer p = new JwsCompactProducer(headers, new String(cos.getBytes(), "UTF-8"));
+            writeJws(p, sigProvider, actualOs);
+        }
+    }
+    
+    public void setContentTypeRequired(boolean contentTypeRequired) {
+        this.contentTypeRequired = contentTypeRequired;
+    }
+    
+    public void setUseJwsOutputStream(boolean useJwsOutputStream) {
+        this.useJwsOutputStream = useJwsOutputStream;
+    }
+    public void setWriter(JoseHeadersWriter writer) {
+        this.writer = writer;
+    }
+    private void setContentTypeIfNeeded(JwtHeaders headers, WriterInterceptorContext ctx) {    
+        if (contentTypeRequired) {
+            MediaType mt = ctx.getMediaType();
+            if (mt != null 
+                && !JAXRSUtils.mediaTypeToString(mt).equals(JoseConstants.MEDIA_TYPE_JOSE_JSON)) {
+                if ("application".equals(mt.getType())) {
+                    headers.setContentType(mt.getSubtype());
+                } else {
+                    headers.setContentType(JAXRSUtils.mediaTypeToString(mt));
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/KeyManagementUtils.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/KeyManagementUtils.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/KeyManagementUtils.java
new file mode 100644
index 0000000..369e072
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/KeyManagementUtils.java
@@ -0,0 +1,145 @@
+/**
+ * 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.jaxrs;
+
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.util.Properties;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageUtils;
+import org.apache.cxf.security.SecurityContext;
+
+
+/**
+ * Encryption helpers
+ */
+public final class KeyManagementUtils {
+    public static final String RSSEC_KEY_STORE_TYPE = "rs.security.keystore.type";
+    public static final String RSSEC_KEY_STORE_PSWD = "rs.security.keystore.password";
+    public static final String RSSEC_KEY_PSWD = "rs.security.key.password";
+    public static final String RSSEC_KEY_STORE_ALIAS = "rs.security.keystore.alias";
+    public static final String RSSEC_KEY_STORE_FILE = "rs.security.keystore.file";
+    public static final String RSSEC_PRINCIPAL_NAME = "rs.security.principal.name";
+    public static final String RSSEC_KEY_PSWD_PROVIDER = "rs.security.key.password.provider";
+    public static final String RSSEC_SIG_KEY_PSWD_PROVIDER = "rs.security.signature.key.password.provider";
+    public static final String RSSEC_DECRYPT_KEY_PSWD_PROVIDER = "rs.security.decryption.key.password.provider";
+    
+    private KeyManagementUtils() {
+    }
+    
+    public static PublicKey loadPublicKey(Message m, Properties props) {
+        KeyStore keyStore = KeyManagementUtils.loadPersistKeyStore(m, props);
+        return CryptoUtils.loadPublicKey(keyStore, props.getProperty(RSSEC_KEY_STORE_ALIAS));
+    }
+    public static PublicKey loadPublicKey(Message m, String keyStoreLocProp) {
+        return loadPublicKey(m, keyStoreLocProp, null);
+    }
+    public static PublicKey loadPublicKey(Message m, String keyStoreLocPropPreferred, String keyStoreLocPropDefault) {
+        String keyStoreLoc = getMessageProperty(m, keyStoreLocPropPreferred, keyStoreLocPropDefault);
+        Bus bus = m.getExchange().getBus();
+        try {
+            Properties props = ResourceUtils.loadProperties(keyStoreLoc, bus);
+            return KeyManagementUtils.loadPublicKey(m, props);
+        } catch (Exception ex) {
+            throw new SecurityException(ex);
+        }
+    }
+    private static String getMessageProperty(Message m, String keyStoreLocPropPreferred, 
+                                             String keyStoreLocPropDefault) {
+        String propLoc = 
+            (String)MessageUtils.getContextualProperty(m, keyStoreLocPropPreferred, keyStoreLocPropDefault);
+        if (propLoc == null) {
+            throw new SecurityException();
+        }
+        return propLoc;
+    }
+    public static PrivateKey loadPrivateKey(Properties props, Bus bus, PrivateKeyPasswordProvider provider) {
+        KeyStore keyStore = loadKeyStore(props, bus);
+        return loadPrivateKey(keyStore, props, bus, provider);
+    }
+    public static PrivateKey loadPrivateKey(KeyStore keyStore, 
+                                            Properties props, 
+                                            Bus bus, 
+                                            PrivateKeyPasswordProvider provider) {
+        
+        String keyPswd = props.getProperty(RSSEC_KEY_PSWD);
+        String alias = props.getProperty(RSSEC_KEY_STORE_ALIAS);
+        char[] keyPswdChars = provider != null ? provider.getPassword(props) 
+            : keyPswd != null ? keyPswd.toCharArray() : null;    
+        return CryptoUtils.loadPrivateKey(keyStore, keyPswdChars, alias);
+    }
+    
+    public static PrivateKey loadPrivateKey(Message m, String keyStoreLocProp, String passwordProviderProp) {
+        return loadPrivateKey(m, keyStoreLocProp, null, passwordProviderProp);
+    }
+    public static PrivateKey loadPrivateKey(Message m, String keyStoreLocPropPreferred,
+                                            String keyStoreLocPropDefault, String passwordProviderProp) {
+        String keyStoreLoc = getMessageProperty(m, keyStoreLocPropPreferred, keyStoreLocPropDefault);
+        Bus bus = m.getExchange().getBus();
+        try {
+            Properties props = ResourceUtils.loadProperties(keyStoreLoc, bus);
+            return KeyManagementUtils.loadPrivateKey(m, props, passwordProviderProp);
+        } catch (Exception ex) {
+            throw new SecurityException(ex);
+        }
+    }
+    public static PrivateKey loadPrivateKey(Message m, Properties props, String passwordProviderProp) {
+        Bus bus = m.getExchange().getBus();
+        KeyStore keyStore = KeyManagementUtils.loadPersistKeyStore(m, props);
+        PrivateKeyPasswordProvider cb = 
+            (PrivateKeyPasswordProvider)m.getContextualProperty(passwordProviderProp);
+        if (cb != null && m.getExchange().getInMessage() != null) {
+            SecurityContext sc = m.getExchange().getInMessage().get(SecurityContext.class);
+            if (sc != null) {
+                Principal p = sc.getUserPrincipal();
+                if (p != null) {
+                    props.setProperty(RSSEC_PRINCIPAL_NAME, p.getName());
+                }
+            }
+        }
+        return KeyManagementUtils.loadPrivateKey(keyStore, props, bus, cb);
+    }
+    public static KeyStore loadPersistKeyStore(Message m, Properties props) {
+        KeyStore keyStore = (KeyStore)m.getExchange().get(props.get(KeyManagementUtils.RSSEC_KEY_STORE_FILE));
+        if (keyStore == null) {
+            keyStore = KeyManagementUtils.loadKeyStore(props, m.getExchange().getBus());
+            m.getExchange().put((String)props.get(KeyManagementUtils.RSSEC_KEY_STORE_FILE), keyStore);
+        }
+        return keyStore;
+    }
+    public static KeyStore loadKeyStore(Properties props, Bus bus) {
+        String keyStoreType = props.getProperty(RSSEC_KEY_STORE_TYPE);
+        String keyStoreLoc = props.getProperty(RSSEC_KEY_STORE_FILE);
+        String keyStorePswd = props.getProperty(RSSEC_KEY_STORE_PSWD);
+        try {
+            InputStream is = ResourceUtils.getResourceStream(keyStoreLoc, bus);
+            return CryptoUtils.loadKeyStore(is, keyStorePswd.toCharArray(), keyStoreType);
+        } catch (Exception ex) {
+            throw new SecurityException(ex);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java
new file mode 100644
index 0000000..fc48ebc
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/Priorities.java
@@ -0,0 +1,31 @@
+/**
+ * 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.jaxrs;
+
+public final class Priorities {
+    public static final int JWE_SERVER_READ_PRIORITY = 1000;
+    public static final int JWE_WRITE_PRIORITY = 1000;
+    public static final int JWE_CLIENT_READ_PRIORITY = 1001;
+    public static final int JWS_SERVER_READ_PRIORITY = 1001;
+    public static final int JWS_WRITE_PRIORITY = 1001;
+    public static final int JWS_CLIENT_READ_PRIORITY = 1000;
+    private Priorities() {
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/PrivateKeyPasswordProvider.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/PrivateKeyPasswordProvider.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/PrivateKeyPasswordProvider.java
new file mode 100644
index 0000000..bfcde49
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jaxrs/PrivateKeyPasswordProvider.java
@@ -0,0 +1,25 @@
+/**
+ * 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.jaxrs;
+
+import java.util.Properties;
+
+public interface PrivateKeyPasswordProvider {
+    char[] getPassword(Properties storeProperties); 
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/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
new file mode 100644
index 0000000..89ac29d
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwa/Algorithm.java
@@ -0,0 +1,227 @@
+/**
+ * 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.jwa;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cxf.rs.security.jose.JoseConstants;
+
+
+
+public enum Algorithm {
+    // Signature
+    HmacSHA256(JoseConstants.HMAC_SHA_256_ALGO, 256),
+    HmacSHA384(JoseConstants.HMAC_SHA_384_ALGO, 384),
+    HmacSHA512(JoseConstants.HMAC_SHA_512_ALGO, 512),
+    
+    SHA256withRSA(JoseConstants.RS_SHA_256_ALGO, 256),
+    SHA384withRSA(JoseConstants.RS_SHA_384_ALGO, 384),
+    SHA512withRSA(JoseConstants.RS_SHA_512_ALGO, 512),
+    
+    SHA256withECDSA(JoseConstants.ES_SHA_256_ALGO, 256),
+    SHA384withECDSA(JoseConstants.ES_SHA_384_ALGO, 384),
+    SHA512withECDSA(JoseConstants.ES_SHA_512_ALGO, 512),
+    
+    // Key Encryption
+    RSA_OAEP(JoseConstants.RSA_OAEP_ALGO, "RSA/ECB/OAEPWithSHA-1AndMGF1Padding", -1),
+    RSA_OAEP_256(JoseConstants.RSA_OAEP_256_ALGO, "RSA/ECB/OAEPWithSHA-256AndMGF1Padding", -1),
+    RSA_1_5(JoseConstants.RSA_1_5_ALGO, "RSA/ECB/PKCS1Padding", -1),
+    A128KW(JoseConstants.A128KW_ALGO, "AESWrap", 128),
+    A192KW(JoseConstants.A192KW_ALGO, "AESWrap", 192),
+    A256KW(JoseConstants.A256KW_ALGO, "AESWrap", 256),
+    A128GCMKW(JoseConstants.A128GCMKW_ALGO, "AES/GCM/NoPadding", 128),
+    A192GCMKW(JoseConstants.A192GCMKW_ALGO, "AES/GCM/NoPadding", 192),
+    A256GCMKW(JoseConstants.A256GCMKW_ALGO, "AES/GCM/NoPadding", 256),
+    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),
+    
+    // Content Encryption
+    A128GCM(JoseConstants.A128GCM_ALGO, "AES/GCM/NoPadding", 128),
+    A192GCM(JoseConstants.A192GCM_ALGO, "AES/GCM/NoPadding", 192),
+    A256GCM(JoseConstants.A256GCM_ALGO, "AES/GCM/NoPadding", 256),
+    A128CBC_HS256(JoseConstants.A128CBC_HS256_ALGO, "AES/CBC/PKCS7Padding", 128),
+    A192CBC_HS384(JoseConstants.A192CBC_HS384_ALGO, "AES/CBC/PKCS7Padding", 192),
+    A256CBC_HS512(JoseConstants.A256CBC_HS512_ALGO, "AES/CBC/PKCS7Padding", 256);
+    
+    public static final String HMAC_SHA_256_JAVA = "HmacSHA256";
+    public static final String HMAC_SHA_384_JAVA = "HmacSHA384";
+    public static final String HMAC_SHA_512_JAVA = "HmacSHA512";
+    public static final String RS_SHA_256_JAVA = "SHA256withRSA";
+    public static final String RS_SHA_384_JAVA = "SHA384withRSA";
+    public static final String RS_SHA_512_JAVA = "SHA512withRSA";
+    public static final String ES_SHA_256_JAVA = "SHA256withECDSA";
+    public static final String ES_SHA_384_JAVA = "SHA384withECDSA";
+    public static final String ES_SHA_512_JAVA = "SHA512withECDSA";
+    public static final String RSA_OAEP_ALGO_JAVA = "RSA/ECB/OAEPWithSHA-1AndMGF1Padding";
+    public static final String RSA_OAEP_256_ALGO_JAVA = "RSA/ECB/OAEPWithSHA-256AndMGF1Padding";
+    public static final String RSA_1_5_ALGO_JAVA = "RSA/ECB/PKCS1Padding";
+    public static final String AES_ALGO_JAVA = "AES";
+    public static final String AES_WRAP_ALGO_JAVA = "AESWrap";
+    public static final String AES_GCM_ALGO_JAVA = "AES/GCM/NoPadding";
+    public static final String AES_CBC_ALGO_JAVA = "AES/CBC/PKCS7Padding";
+    
+    private static final Map<String, String> JAVA_TO_JWT_NAMES;
+    private static final Map<String, String> JWT_TO_JAVA_NAMES;
+    static {
+        JAVA_TO_JWT_NAMES = new HashMap<String, String>();
+        JAVA_TO_JWT_NAMES.put(HMAC_SHA_256_JAVA, JoseConstants.HMAC_SHA_256_ALGO);
+        JAVA_TO_JWT_NAMES.put(HMAC_SHA_384_JAVA, JoseConstants.HMAC_SHA_384_ALGO);
+        JAVA_TO_JWT_NAMES.put(HMAC_SHA_512_JAVA, JoseConstants.HMAC_SHA_512_ALGO);
+        JAVA_TO_JWT_NAMES.put(RS_SHA_256_JAVA, JoseConstants.RS_SHA_256_ALGO);
+        JAVA_TO_JWT_NAMES.put(RS_SHA_384_JAVA, JoseConstants.RS_SHA_384_ALGO);
+        JAVA_TO_JWT_NAMES.put(RS_SHA_512_JAVA, JoseConstants.RS_SHA_512_ALGO);
+        JAVA_TO_JWT_NAMES.put(ES_SHA_256_JAVA, JoseConstants.ES_SHA_256_ALGO);
+        JAVA_TO_JWT_NAMES.put(ES_SHA_384_JAVA, JoseConstants.ES_SHA_384_ALGO);
+        JAVA_TO_JWT_NAMES.put(ES_SHA_512_JAVA, JoseConstants.ES_SHA_512_ALGO);
+        JAVA_TO_JWT_NAMES.put(RSA_OAEP_ALGO_JAVA, JoseConstants.RSA_OAEP_ALGO);
+        JAVA_TO_JWT_NAMES.put(RSA_OAEP_256_ALGO_JAVA, JoseConstants.RSA_OAEP_256_ALGO);
+        JAVA_TO_JWT_NAMES.put(RSA_1_5_ALGO_JAVA, JoseConstants.RSA_1_5_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_GCM_ALGO_JAVA, JoseConstants.A256GCM_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_GCM_ALGO_JAVA, JoseConstants.A192GCM_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_GCM_ALGO_JAVA, JoseConstants.A128GCM_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_WRAP_ALGO_JAVA, JoseConstants.A128KW_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_WRAP_ALGO_JAVA, JoseConstants.A192KW_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_WRAP_ALGO_JAVA, JoseConstants.A256KW_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JoseConstants.A128CBC_HS256_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JoseConstants.A192CBC_HS384_ALGO);
+        JAVA_TO_JWT_NAMES.put(AES_CBC_ALGO_JAVA, JoseConstants.A256CBC_HS512_ALGO);
+        JWT_TO_JAVA_NAMES = new HashMap<String, String>();
+        JWT_TO_JAVA_NAMES.put(JoseConstants.HMAC_SHA_256_ALGO, HMAC_SHA_256_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.HMAC_SHA_384_ALGO, HMAC_SHA_384_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.HMAC_SHA_512_ALGO, HMAC_SHA_512_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.RS_SHA_256_ALGO, RS_SHA_256_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.RS_SHA_384_ALGO, RS_SHA_384_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.RS_SHA_512_ALGO, RS_SHA_512_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.ES_SHA_256_ALGO, ES_SHA_256_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.ES_SHA_384_ALGO, ES_SHA_384_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.ES_SHA_512_ALGO, ES_SHA_512_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.RSA_OAEP_ALGO, RSA_OAEP_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.RSA_OAEP_256_ALGO, RSA_OAEP_256_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.RSA_1_5_ALGO, RSA_1_5_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A128KW_ALGO, AES_WRAP_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A192KW_ALGO, AES_WRAP_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A256KW_ALGO, AES_WRAP_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A256GCM_ALGO, AES_GCM_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A192GCM_ALGO, AES_GCM_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A128GCM_ALGO, AES_GCM_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A256GCMKW_ALGO, AES_GCM_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A192GCMKW_ALGO, AES_GCM_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A128GCMKW_ALGO, AES_GCM_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A128CBC_HS256_ALGO, AES_CBC_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A192CBC_HS384_ALGO, AES_CBC_ALGO_JAVA);
+        JWT_TO_JAVA_NAMES.put(JoseConstants.A256CBC_HS512_ALGO, AES_CBC_ALGO_JAVA);
+        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);
+    }
+    private final String jwtName;
+    private final String javaName;
+    private final int keySizeBits;
+    
+    private Algorithm(String jwtName, int keySizeBits) {
+        this(jwtName, null, keySizeBits);
+    }
+    private Algorithm(String jwtName, String javaName, int keySizeBits) {
+        this.jwtName = jwtName;
+        this.javaName = javaName;
+        this.keySizeBits = keySizeBits;
+    }
+
+    public String getJwtName() {
+        return jwtName;
+    }
+
+    public String getJavaName() {
+        return javaName == null ? name() : javaName;
+    }
+    
+    public String getJavaAlgoName() {
+        return stripAlgoProperties(getJavaName());
+    }
+
+    public int getKeySizeBits() {
+        return keySizeBits;
+    }
+    
+    public static String toJwtName(String javaName, int keyBitSize) {
+        //TODO: perhaps a key should be a name+keysize pair
+        String name = JAVA_TO_JWT_NAMES.get(javaName);
+        if (name == null && javaName.startsWith(AES_ALGO_JAVA)) {
+            name = "A" + keyBitSize + "GCM";
+        } 
+        return name;
+    }
+    public static String toJavaName(String jwtName) {    
+        return JWT_TO_JAVA_NAMES.get(jwtName);
+    }
+    public static String toJavaAlgoNameOnly(String jwtName) {    
+        return stripAlgoProperties(toJavaName(jwtName));
+    }
+    public static String stripAlgoProperties(String javaName) {    
+        if (javaName != null) {
+            int index = javaName.indexOf('/');
+            if (index != -1) {
+                javaName = javaName.substring(0, index);
+            }
+        }
+        return javaName;
+    }
+    public static boolean isRsaOaep(String algo) {
+        return JoseConstants.RSA_OAEP_ALGO.equals(algo)
+               || JoseConstants.RSA_OAEP_256_ALGO.equals(algo);
+    }
+    public static boolean isAesKeyWrap(String algo) {
+        return JoseConstants.A128KW_ALGO.equals(algo)
+               || JoseConstants.A192KW_ALGO.equals(algo)
+               || JoseConstants.A256KW_ALGO.equals(algo);
+    }
+    public static boolean isAesGcmKeyWrap(String algo) {
+        return JoseConstants.A128GCMKW_ALGO.equals(algo)
+               || JoseConstants.A192GCMKW_ALGO.equals(algo)
+               || JoseConstants.A256GCMKW_ALGO.equals(algo);
+    }
+    public static boolean isAesGcm(String algo) {
+        return JoseConstants.A128GCM_ALGO.equals(algo)
+               || JoseConstants.A192GCM_ALGO.equals(algo)
+               || JoseConstants.A256GCM_ALGO.equals(algo);
+    }
+    public static boolean isAesCbcHmac(String algo) {
+        return JoseConstants.A128CBC_HS256_ALGO.equals(algo)
+            || JoseConstants.A192CBC_HS384_ALGO.equals(algo)
+            || JoseConstants.A256CBC_HS512_ALGO.equals(algo); 
+    }
+    public static boolean isHmacSign(String algo) {
+        return JoseConstants.HMAC_SHA_256_ALGO.equals(algo)
+            || JoseConstants.HMAC_SHA_384_ALGO.equals(algo)
+            || JoseConstants.HMAC_SHA_512_ALGO.equals(algo); 
+    }
+    public static boolean isRsaShaSign(String algo) {
+        return JoseConstants.RS_SHA_256_ALGO.equals(algo)
+            || JoseConstants.RS_SHA_384_ALGO.equals(algo)
+            || JoseConstants.RS_SHA_512_ALGO.equals(algo); 
+    }
+    public static boolean isEcDsaSign(String algo) {
+        return JoseConstants.ES_SHA_256_ALGO.equals(algo)
+            || JoseConstants.ES_SHA_384_ALGO.equals(algo)
+            || JoseConstants.ES_SHA_512_ALGO.equals(algo); 
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionAlgorithm.java
new file mode 100644
index 0000000..770ee56
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionAlgorithm.java
@@ -0,0 +1,61 @@
+/**
+ * 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.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+
+
+public abstract class AbstractContentEncryptionAlgorithm extends AbstractContentEncryptionCipherProperties
+    implements ContentEncryptionAlgorithm {
+    private static final int DEFAULT_IV_SIZE = 128;
+    private byte[] cek;
+    private byte[] iv;
+    private AtomicInteger providedIvUsageCount;
+    private String algorithm;
+    
+    protected AbstractContentEncryptionAlgorithm(byte[] cek, byte[] iv, String algo) { 
+        this.cek = cek;
+        this.iv = iv;
+        if (iv != null && iv.length > 0) {
+            providedIvUsageCount = new AtomicInteger();
+        }    
+        this.algorithm = algo;
+    }
+    @Override
+    public String getAlgorithm() { 
+        return algorithm;
+    }
+    public byte[] getContentEncryptionKey(JweHeaders headers) {
+        return cek;
+    }
+    public byte[] getInitVector() {
+        if (iv == null) {
+            return CryptoUtils.generateSecureRandomBytes(getIvSize() / 8);
+        } else if (iv.length > 0 && providedIvUsageCount.addAndGet(1) > 1) {
+            throw new SecurityException();
+        } else {
+            return iv;
+        }
+    }
+    protected int getIvSize() { 
+        return DEFAULT_IV_SIZE;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionCipherProperties.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionCipherProperties.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionCipherProperties.java
new file mode 100644
index 0000000..bc30979
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractContentEncryptionCipherProperties.java
@@ -0,0 +1,39 @@
+/**
+ * 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 org.apache.cxf.common.util.crypto.CryptoUtils;
+
+
+public abstract class AbstractContentEncryptionCipherProperties implements ContentEncryptionCipherProperties {
+    private static final int DEFAULT_AUTH_TAG_LENGTH = 128;
+    private int authTagLen = DEFAULT_AUTH_TAG_LENGTH;
+    
+    public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
+        return CryptoUtils.getContentEncryptionCipherSpec(getAuthTagLen(), theIv);
+    }
+    public byte[] getAdditionalAuthenticationData(String headersJson) {
+        return JweHeaders.toCipherAdditionalAuthData(headersJson);
+    }
+    protected int getAuthTagLen() {
+        return authTagLen;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweDecryption.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweDecryption.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweDecryption.java
new file mode 100644
index 0000000..45d3ee7
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweDecryption.java
@@ -0,0 +1,105 @@
+/**
+ * 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.Key;
+import java.security.spec.AlgorithmParameterSpec;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.common.util.crypto.KeyProperties;
+import org.apache.cxf.rs.security.jose.JoseConstants;
+import org.apache.cxf.rs.security.jose.JoseHeadersReader;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public abstract class AbstractJweDecryption implements JweDecryptionProvider {
+    private KeyDecryptionAlgorithm keyDecryptionAlgo;
+    private ContentDecryptionAlgorithm contentDecryptionAlgo;
+    private JoseHeadersReader reader = new JoseHeadersReaderWriter();
+    protected AbstractJweDecryption(JoseHeadersReader theReader,
+                                    KeyDecryptionAlgorithm keyDecryptionAlgo,
+                                    ContentDecryptionAlgorithm contentDecryptionAlgo) {
+        if (theReader != null) {
+            reader = theReader;
+        }
+        this.keyDecryptionAlgo = keyDecryptionAlgo;
+        this.contentDecryptionAlgo = contentDecryptionAlgo;
+    }
+    
+    protected byte[] getContentEncryptionKey(JweCompactConsumer consumer) {
+        return this.keyDecryptionAlgo.getDecryptedContentEncryptionKey(consumer);
+    }
+    
+    public JweDecryptionOutput decrypt(String content) {
+        JweCompactConsumer consumer = new JweCompactConsumer(content, reader);
+        return doDecrypt(consumer);
+    }
+    public byte[] decrypt(JweCompactConsumer consumer) {
+        return doDecrypt(consumer).getContent();
+    }
+    
+    protected JweDecryptionOutput doDecrypt(JweCompactConsumer consumer) {
+        byte[] cek = getContentEncryptionKey(consumer);
+        return doDecrypt(consumer, cek);
+    }
+    protected JweDecryptionOutput doDecrypt(JweCompactConsumer consumer, byte[] cek) {
+        KeyProperties keyProperties = new KeyProperties(getContentEncryptionAlgorithm(consumer));
+        keyProperties.setAdditionalData(getContentEncryptionCipherAAD(consumer));
+        AlgorithmParameterSpec spec = getContentEncryptionCipherSpec(consumer);
+        keyProperties.setAlgoSpec(spec);
+        boolean compressionSupported = 
+            JoseConstants.DEFLATE_ZIP_ALGORITHM.equals(consumer.getJweHeaders().getZipAlgorithm());
+        keyProperties.setCompressionSupported(compressionSupported);
+        byte[] actualCek = getActualCek(cek, consumer.getJweHeaders().getContentEncryptionAlgorithm());
+        Key secretKey = CryptoUtils.createSecretKeySpec(actualCek, keyProperties.getKeyAlgo());
+        byte[] bytes = 
+            CryptoUtils.decryptBytes(getEncryptedContentWithAuthTag(consumer), secretKey, keyProperties);
+        return new JweDecryptionOutput(consumer.getJweHeaders(), bytes);
+    }
+    protected byte[] getEncryptedContentEncryptionKey(JweCompactConsumer consumer) {
+        return consumer.getEncryptedContentEncryptionKey();
+    }
+    protected AlgorithmParameterSpec getContentEncryptionCipherSpec(JweCompactConsumer consumer) {
+        return contentDecryptionAlgo.getAlgorithmParameterSpec(getContentEncryptionCipherInitVector(consumer));
+    }
+    protected String getContentEncryptionAlgorithm(JweCompactConsumer consumer) {
+        return Algorithm.toJavaName(consumer.getJweHeaders().getContentEncryptionAlgorithm());
+    }
+    protected byte[] getContentEncryptionCipherAAD(JweCompactConsumer consumer) {
+        return contentDecryptionAlgo.getAdditionalAuthenticationData(consumer.getDecodedJsonHeaders());
+    }
+    protected byte[] getEncryptedContentWithAuthTag(JweCompactConsumer consumer) {
+        return contentDecryptionAlgo.getEncryptedSequence(consumer.getJweHeaders(),
+                                                          consumer.getEncryptedContent(), 
+                                                          getEncryptionAuthenticationTag(consumer));
+    }
+    protected byte[] getContentEncryptionCipherInitVector(JweCompactConsumer consumer) { 
+        return consumer.getContentDecryptionCipherInitVector();
+    }
+    protected byte[] getEncryptionAuthenticationTag(JweCompactConsumer consumer) {
+        return consumer.getEncryptionAuthenticationTag();
+    }
+    protected int getEncryptionAuthenticationTagLenBits(JweCompactConsumer consumer) {
+        return getEncryptionAuthenticationTag(consumer).length * 8;
+    }
+    protected byte[] getActualCek(byte[] theCek, String algoJwt) {
+        return theCek;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweEncryption.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweEncryption.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweEncryption.java
new file mode 100644
index 0000000..4354bf3
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractJweEncryption.java
@@ -0,0 +1,184 @@
+/**
+ * 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 javax.crypto.Cipher;
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.common.util.crypto.KeyProperties;
+import org.apache.cxf.rs.security.jose.JoseConstants;
+import org.apache.cxf.rs.security.jose.JoseHeadersReaderWriter;
+import org.apache.cxf.rs.security.jose.JoseHeadersWriter;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public abstract class AbstractJweEncryption implements JweEncryptionProvider {
+    protected static final int DEFAULT_AUTH_TAG_LENGTH = 128;
+    private JweHeaders headers;
+    private JoseHeadersWriter writer;
+    private ContentEncryptionAlgorithm contentEncryptionAlgo;
+    private KeyEncryptionAlgorithm keyEncryptionAlgo;
+    
+    protected AbstractJweEncryption(JweHeaders headers, 
+                                    ContentEncryptionAlgorithm contentEncryptionAlgo,
+                                    KeyEncryptionAlgorithm keyEncryptionAlgo) {
+        this(headers, contentEncryptionAlgo, keyEncryptionAlgo, null);
+    }
+    protected AbstractJweEncryption(JweHeaders headers, 
+                                    ContentEncryptionAlgorithm contentEncryptionAlgo, 
+                                    KeyEncryptionAlgorithm keyEncryptionAlgo,
+                                    JoseHeadersWriter writer) {
+        this.headers = headers;
+        this.writer = writer;
+        if (this.writer == null) {
+            this.writer = new JoseHeadersReaderWriter();
+        }
+        this.keyEncryptionAlgo = keyEncryptionAlgo;
+        this.contentEncryptionAlgo = contentEncryptionAlgo;
+    }
+    
+    protected AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
+        return contentEncryptionAlgo.getAlgorithmParameterSpec(theIv);
+    }
+    
+    protected byte[] getContentEncryptionKey() {
+        byte[] cek = getProvidedContentEncryptionKey();
+        if (cek == null) {
+            String algoJava = getContentEncryptionAlgoJava();
+            String algoJwt = getContentEncryptionAlgoJwt();
+            cek = CryptoUtils.getSecretKey(Algorithm.stripAlgoProperties(algoJava), 
+                                           getCekSize(algoJwt)).getEncoded();
+        }
+        return cek;
+    }
+   
+    protected int getCekSize(String algoJwt) {
+        return Algorithm.valueOf(algoJwt.replace('-', '_')).getKeySizeBits();
+    }
+    
+    protected byte[] getProvidedContentEncryptionKey() {
+        return contentEncryptionAlgo.getContentEncryptionKey(headers);
+    }
+    
+    protected byte[] getEncryptedContentEncryptionKey(byte[] theCek) {
+        return keyEncryptionAlgo.getEncryptedContentEncryptionKey(headers, theCek);
+    }
+    
+    protected String getContentEncryptionAlgoJwt() {
+        return headers.getContentEncryptionAlgorithm();
+    }
+    protected String getContentEncryptionAlgoJava() {
+        return Algorithm.toJavaName(getContentEncryptionAlgoJwt());
+    }
+    protected byte[] getAAD(JweHeaders theHeaders) {
+        return contentEncryptionAlgo.getAdditionalAuthenticationData(writer.headersToJson(theHeaders));
+    }
+    public String encrypt(byte[] content, String contentType) {
+        JweEncryptionInternal state = getInternalState(contentType);
+        
+        byte[] cipher = CryptoUtils.encryptBytes(content, createCekSecretKey(state), state.keyProps);
+        
+        
+        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,
+                                      DEFAULT_AUTH_TAG_LENGTH);
+    }
+    
+    protected JoseHeadersWriter getJwtHeadersWriter() {
+        return writer;
+    }
+    protected JweHeaders getJweHeaders() {
+        return headers;
+    }
+    @Override
+    public JweEncryptionState createJweEncryptionState(String contentType) {
+        JweEncryptionInternal state = getInternalState(contentType);
+        Cipher c = CryptoUtils.initCipher(createCekSecretKey(state), state.keyProps, 
+                                          Cipher.ENCRYPT_MODE);
+        return new JweEncryptionState(c, 
+                                      state.theHeaders, 
+                                      state.jweContentEncryptionKey, 
+                                      state.theIv,
+                                      getAuthenticationTagProducer(state),
+                                      state.keyProps.isCompressionSupported());
+    }
+    protected AuthenticationTagProducer getAuthenticationTagProducer(JweEncryptionInternal state) {
+        return null;
+    }
+    protected SecretKey createCekSecretKey(JweEncryptionInternal state) {
+        return CryptoUtils.createSecretKeySpec(getActualCek(state.secretKey, this.getContentEncryptionAlgoJwt()), 
+                                               state.keyProps.getKeyAlgo());
+    }
+    
+    protected byte[] getActualCek(byte[] theCek, String algoJwt) {
+        return theCek;
+    }
+    
+    private JweEncryptionInternal getInternalState(String contentType) {
+        byte[] theCek = getContentEncryptionKey();
+        String contentEncryptionAlgoJavaName = Algorithm.toJavaName(headers.getContentEncryptionAlgorithm());
+        KeyProperties keyProps = new KeyProperties(contentEncryptionAlgoJavaName);
+        keyProps.setCompressionSupported(compressionRequired(headers));
+        
+        byte[] theIv = contentEncryptionAlgo.getInitVector();
+        AlgorithmParameterSpec specParams = getAlgorithmParameterSpec(theIv);
+        keyProps.setAlgoSpec(specParams);
+        byte[] jweContentEncryptionKey = getEncryptedContentEncryptionKey(theCek);
+        
+        JweHeaders theHeaders = headers;
+        if (contentType != null) {
+            theHeaders = new JweHeaders(theHeaders.asMap());
+            theHeaders.setContentType(contentType);
+        }
+        byte[] additionalEncryptionParam = getAAD(theHeaders);
+        keyProps.setAdditionalData(additionalEncryptionParam);
+        
+        
+        JweEncryptionInternal state = new JweEncryptionInternal();
+        state.theHeaders = theHeaders;
+        state.jweContentEncryptionKey = jweContentEncryptionKey;
+        state.keyProps = keyProps;
+        state.secretKey = theCek; 
+        state.theIv = theIv;
+        return state;
+    }
+    private boolean compressionRequired(JweHeaders theHeaders) {
+        return JoseConstants.DEFLATE_ZIP_ALGORITHM.equals(theHeaders.getZipAlgorithm());
+    }
+    protected KeyEncryptionAlgorithm getKeyEncryptionAlgo() {
+        return keyEncryptionAlgo;
+    }
+    protected static class JweEncryptionInternal {
+        JweHeaders theHeaders;
+        byte[] jweContentEncryptionKey;
+        byte[] theIv;
+        KeyProperties keyProps;
+        byte[] secretKey;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractWrapKeyEncryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractWrapKeyEncryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractWrapKeyEncryptionAlgorithm.java
new file mode 100644
index 0000000..ed35eab
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AbstractWrapKeyEncryptionAlgorithm.java
@@ -0,0 +1,100 @@
+/**
+ * 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.Key;
+import java.security.spec.AlgorithmParameterSpec;
+import java.util.Set;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.common.util.crypto.KeyProperties;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public abstract class AbstractWrapKeyEncryptionAlgorithm implements KeyEncryptionAlgorithm {
+    private Key keyEncryptionKey;
+    private boolean wrap;
+    private String algorithm;
+    private Set<String> supportedAlgorithms;
+    protected AbstractWrapKeyEncryptionAlgorithm(Key key, Set<String> supportedAlgorithms) {
+        this(key, null, true, supportedAlgorithms);
+    }
+    protected AbstractWrapKeyEncryptionAlgorithm(Key key, boolean wrap, Set<String> supportedAlgorithms) {
+        this(key, null, wrap, supportedAlgorithms);
+    }
+    protected AbstractWrapKeyEncryptionAlgorithm(Key key, String jweAlgo, Set<String> supportedAlgorithms) {
+        this(key, jweAlgo, true, supportedAlgorithms);
+    }
+    protected AbstractWrapKeyEncryptionAlgorithm(Key key, String jweAlgo, boolean wrap, 
+                                                 Set<String> supportedAlgorithms) {
+        this.keyEncryptionKey = key;
+        this.algorithm = jweAlgo;
+        this.wrap = wrap;
+        this.supportedAlgorithms = supportedAlgorithms;
+    }
+    @Override
+    public String getAlgorithm() {
+        return algorithm;
+    }
+    @Override
+    public byte[] getEncryptedContentEncryptionKey(JweHeaders headers, byte[] cek) {
+        checkAlgorithms(headers);
+        KeyProperties secretKeyProperties = new KeyProperties(getKeyEncryptionAlgoJava(headers));
+        AlgorithmParameterSpec spec = getAlgorithmParameterSpec(headers); 
+        if (spec != null) {
+            secretKeyProperties.setAlgoSpec(spec);
+        }
+        if (!wrap) {
+            return CryptoUtils.encryptBytes(cek, keyEncryptionKey, secretKeyProperties);
+        } else {
+            return CryptoUtils.wrapSecretKey(cek, 
+                                             getContentEncryptionAlgoJava(headers),
+                                             keyEncryptionKey, 
+                                             secretKeyProperties);
+        }
+    }
+    protected String getKeyEncryptionAlgoJava(JweHeaders headers) {
+        return Algorithm.toJavaName(headers.getKeyEncryptionAlgorithm());
+    }
+    protected String getContentEncryptionAlgoJava(JweHeaders headers) {
+        return Algorithm.toJavaName(headers.getContentEncryptionAlgorithm());
+    }
+    protected AlgorithmParameterSpec getAlgorithmParameterSpec(JweHeaders headers) {
+        return null;
+    }
+    protected String checkAlgorithm(String algo) {
+        if (algo != null && !supportedAlgorithms.contains(algo)) {
+            throw new SecurityException();
+        }
+        return algo;
+    }
+    protected void checkAlgorithms(JweHeaders headers) {
+        String providedAlgo = headers.getKeyEncryptionAlgorithm();
+        if ((providedAlgo == null && algorithm == null)
+            || (providedAlgo != null && algorithm != null && !providedAlgo.equals(algorithm))) {
+            throw new SecurityException();
+        }
+        if (providedAlgo != null) {
+            checkAlgorithm(providedAlgo);
+        } else if (algorithm != null) {
+            headers.setKeyEncryptionAlgorithm(algorithm);
+            checkAlgorithm(algorithm);
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweDecryption.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweDecryption.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweDecryption.java
new file mode 100644
index 0000000..bf110f3
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweDecryption.java
@@ -0,0 +1,89 @@
+/**
+ * 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.Arrays;
+
+import javax.crypto.spec.IvParameterSpec;
+
+import org.apache.cxf.rs.security.jose.JoseHeadersReader;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class AesCbcHmacJweDecryption extends AbstractJweDecryption {
+    private String supportedAlgo;
+    public AesCbcHmacJweDecryption(KeyDecryptionAlgorithm keyDecryptionAlgo) {
+        this(keyDecryptionAlgo, null);
+    }
+    public AesCbcHmacJweDecryption(KeyDecryptionAlgorithm keyDecryptionAlgo, String supportedAlgo) {
+        this(keyDecryptionAlgo, supportedAlgo, null);
+    }
+    public AesCbcHmacJweDecryption(KeyDecryptionAlgorithm keyDecryptionAlgo,
+                                   String supportedAlgo,
+                                   JoseHeadersReader reader) {
+        super(reader, keyDecryptionAlgo, new AesCbcContentDecryptionAlgorithm());
+        this.supportedAlgo = null;
+    }
+    protected JweDecryptionOutput doDecrypt(JweCompactConsumer consumer, byte[] cek) {
+        validateAuthenticationTag(consumer, cek);
+        return super.doDecrypt(consumer, cek);
+    }
+    @Override
+    protected byte[] getActualCek(byte[] theCek, String algoJwt) {
+        validateCekAlgorithm(algoJwt);
+        return AesCbcHmacJweEncryption.doGetActualCek(theCek, algoJwt);
+    }
+    protected void validateAuthenticationTag(JweCompactConsumer consumer, byte[] theCek) {
+        byte[] actualAuthTag = consumer.getEncryptionAuthenticationTag();
+        
+        final AesCbcHmacJweEncryption.MacState macState = 
+            AesCbcHmacJweEncryption.getInitializedMacState(theCek, 
+                                                           consumer.getContentDecryptionCipherInitVector(),
+                                                           consumer.getJweHeaders(),
+                                                           consumer.getDecodedJsonHeaders());
+        macState.mac.update(consumer.getEncryptedContent());
+        byte[] expectedAuthTag = AesCbcHmacJweEncryption.signAndGetTag(macState);
+        if (!Arrays.equals(actualAuthTag, expectedAuthTag)) {
+            throw new SecurityException();
+        }
+        
+    }
+    private static class AesCbcContentDecryptionAlgorithm extends AbstractContentEncryptionCipherProperties
+        implements ContentDecryptionAlgorithm {
+        @Override
+        public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
+            return new IvParameterSpec(theIv);
+        }
+        @Override
+        public byte[] getAdditionalAuthenticationData(String headersJson) {
+            return null;
+        }
+        @Override
+        public byte[] getEncryptedSequence(JweHeaders headers, byte[] cipher, byte[] authTag) {
+            return cipher;
+        }
+    }
+    private String validateCekAlgorithm(String cekAlgo) {
+        if (!Algorithm.isAesCbcHmac(cekAlgo) 
+            || supportedAlgo != null && !supportedAlgo.equals(cekAlgo)) {
+            throw new SecurityException();
+        }
+        return cekAlgo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
new file mode 100644
index 0000000..ab0220c
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesCbcHmacJweEncryption.java
@@ -0,0 +1,188 @@
+/**
+ * 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.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.common.util.crypto.HmacUtils;
+import org.apache.cxf.rs.security.jose.JoseHeadersWriter;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class AesCbcHmacJweEncryption extends AbstractJweEncryption {
+    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(String cekAlgoJwt, 
+                                   KeyEncryptionAlgorithm keyEncryptionAlgorithm) {
+        this(new JweHeaders(keyEncryptionAlgorithm.getAlgorithm(), cekAlgoJwt), null, null, 
+             keyEncryptionAlgorithm);
+    }
+    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,
+                                   JoseHeadersWriter writer) {
+        super(headers, 
+              new AesCbcContentEncryptionAlgorithm(cek, iv, 
+                                                   validateCekAlgorithm(headers.getContentEncryptionAlgorithm())),
+              keyEncryptionAlgorithm, writer);
+        
+    }
+    @Override
+    protected byte[] getActualCek(byte[] theCek, String algoJwt) {
+        return doGetActualCek(theCek, algoJwt);
+    }
+    @Override
+    protected int getCekSize(String algoJwt) {
+        return getFullCekKeySize(algoJwt) * 8;
+    }
+    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;
+    }
+    
+    protected static int getFullCekKeySize(String algoJwt) {
+        return AES_CEK_SIZE_MAP.get(algoJwt);
+    }
+    
+    protected JweCompactProducer getJweCompactProducer(JweEncryptionInternal state, byte[] cipher) {
+        final MacState macState = getInitializedMacState(state);
+        macState.mac.update(cipher);
+        byte[] authTag = signAndGetTag(macState);
+        return new JweCompactProducer(macState.headersJson,
+                                      state.jweContentEncryptionKey,
+                                      state.theIv,
+                                      cipher,
+                                      authTag);
+    }
+    
+    protected static byte[] signAndGetTag(MacState macState) {
+        macState.mac.update(macState.al);
+        byte[] sig = macState.mac.doFinal();
+        
+        int authTagLen = DEFAULT_AUTH_TAG_LENGTH / 8;
+        byte[] authTag = new byte[authTagLen];
+        System.arraycopy(sig, 0, authTag, 0, authTagLen);
+        return authTag;
+    }
+    private MacState getInitializedMacState(final JweEncryptionInternal state) {
+        String headersJson = getJwtHeadersWriter().headersToJson(state.theHeaders);
+        return getInitializedMacState(state.secretKey, state.theIv, state.theHeaders, headersJson);
+    }
+    protected static MacState getInitializedMacState(byte[] secretKey,
+                                                     byte[] theIv,
+                                                     JweHeaders theHeaders, 
+                                                     String headersJson) {
+        String algoJwt = theHeaders.getContentEncryptionAlgorithm();
+        int size = getFullCekKeySize(algoJwt) / 2;
+        byte[] macKey = new byte[size];
+        System.arraycopy(secretKey, 0, macKey, 0, size);
+        
+        String hmacAlgoJava = AES_HMAC_MAP.get(algoJwt);
+        Mac mac = HmacUtils.getInitializedMac(macKey, hmacAlgoJava, null);
+        
+        
+        byte[] aad = JweHeaders.toCipherAdditionalAuthData(headersJson);
+        ByteBuffer buf = ByteBuffer.allocate(8);
+        final byte[] al = buf.putInt(0).putInt(aad.length * 8).array();
+        
+        mac.update(aad);
+        mac.update(theIv);
+        MacState macState = new MacState();
+        macState.mac = mac;
+        macState.al = al;
+        macState.headersJson = headersJson;
+        return macState;
+    }
+    
+    protected AuthenticationTagProducer getAuthenticationTagProducer(final JweEncryptionInternal state) {
+        final MacState macState = getInitializedMacState(state);
+        
+        
+        return new AuthenticationTagProducer() {
+
+            @Override
+            public void update(byte[] cipher, int off, int len) {
+                macState.mac.update(cipher, off, len);
+            }
+
+            @Override
+            public byte[] getTag() {
+                return signAndGetTag(macState);
+            }
+        };
+    }
+    
+    protected byte[] getEncryptedContentEncryptionKey(byte[] theCek) {
+        return getKeyEncryptionAlgo().getEncryptedContentEncryptionKey(getJweHeaders(), theCek);
+    }
+    
+    private static class AesCbcContentEncryptionAlgorithm extends AbstractContentEncryptionAlgorithm {
+        public AesCbcContentEncryptionAlgorithm(byte[] cek, byte[] iv, String algo) { 
+            super(cek, iv, algo);    
+        }
+        @Override
+        public AlgorithmParameterSpec getAlgorithmParameterSpec(byte[] theIv) {
+            return new IvParameterSpec(theIv);
+        }
+        @Override
+        public byte[] getAdditionalAuthenticationData(String headersJson) {
+            return null;
+        }
+    }
+    
+    protected static class MacState {
+        protected Mac mac;
+        private byte[] al;
+        private String headersJson;
+    }
+    
+    private static String validateCekAlgorithm(String cekAlgo) {
+        if (!Algorithm.isAesCbcHmac(cekAlgo)) {
+            throw new SecurityException();
+        }
+        return cekAlgo;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentDecryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentDecryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentDecryptionAlgorithm.java
new file mode 100644
index 0000000..70b3a00
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentDecryptionAlgorithm.java
@@ -0,0 +1,44 @@
+/**
+ * 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 org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+
+
+public class AesGcmContentDecryptionAlgorithm extends AbstractContentEncryptionCipherProperties
+    implements ContentDecryptionAlgorithm {
+    private String supportedAlgo; 
+    public AesGcmContentDecryptionAlgorithm() {
+        this(null);
+    }
+    public AesGcmContentDecryptionAlgorithm(String supportedAlgo) {
+        this.supportedAlgo = supportedAlgo;
+    }
+
+    @Override
+    public byte[] getEncryptedSequence(JweHeaders headers, byte[] cipher, byte[] authTag) {
+        String algo = headers.getContentEncryptionAlgorithm();
+        if (!Algorithm.isAesGcm(algo)
+            || supportedAlgo != null && !supportedAlgo.equals(algo)) {
+            throw new SecurityException();
+        }
+        return JweCompactConsumer.getCipherWithAuthTag(cipher, authTag);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentEncryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentEncryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentEncryptionAlgorithm.java
new file mode 100644
index 0000000..bcd0fb3
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmContentEncryptionAlgorithm.java
@@ -0,0 +1,50 @@
+/**
+ * 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 javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+
+public class AesGcmContentEncryptionAlgorithm extends AbstractContentEncryptionAlgorithm {
+    private static final int DEFAULT_IV_SIZE = 96;
+    public AesGcmContentEncryptionAlgorithm(String algo) {
+        this((byte[])null, null, algo);
+    }
+    public AesGcmContentEncryptionAlgorithm(String encodedCek, String encodedIv, String algo) {
+        this((byte[])CryptoUtils.decodeSequence(encodedCek), CryptoUtils.decodeSequence(encodedIv), algo);
+    }
+    public AesGcmContentEncryptionAlgorithm(SecretKey key, byte[] iv, String algo) { 
+        this(key.getEncoded(), iv, algo);    
+    }
+    public AesGcmContentEncryptionAlgorithm(byte[] cek, byte[] iv, String algo) { 
+        super(cek, iv, checkAlgorithm(algo));    
+    }
+    protected int getIvSize() { 
+        return DEFAULT_IV_SIZE;
+    }
+    private static String checkAlgorithm(String algo) {
+        if (Algorithm.isAesGcm(algo)) {       
+            return algo;
+        }
+        throw new SecurityException();
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyDecryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyDecryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyDecryptionAlgorithm.java
new file mode 100644
index 0000000..0043ec2
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyDecryptionAlgorithm.java
@@ -0,0 +1,72 @@
+/**
+ * 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 javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class AesGcmWrapKeyDecryptionAlgorithm extends WrappedKeyDecryptionAlgorithm {
+    public AesGcmWrapKeyDecryptionAlgorithm(String encodedKey) {    
+        this(encodedKey, null);
+    }
+    public AesGcmWrapKeyDecryptionAlgorithm(String encodedKey, String supportedAlgo) {    
+        this(CryptoUtils.decodeSequence(encodedKey), supportedAlgo);
+    }
+    public AesGcmWrapKeyDecryptionAlgorithm(byte[] secretKey) {    
+        this(secretKey, null);
+    }
+    public AesGcmWrapKeyDecryptionAlgorithm(byte[] secretKey, String supportedAlgo) {    
+        this(CryptoUtils.createSecretKeySpec(secretKey, Algorithm.AES_ALGO_JAVA), supportedAlgo);
+    }
+    public AesGcmWrapKeyDecryptionAlgorithm(SecretKey secretKey) {    
+        this(secretKey, null);
+    }
+    public AesGcmWrapKeyDecryptionAlgorithm(SecretKey secretKey, String supportedAlgo) {    
+        super(secretKey, supportedAlgo);
+    }
+    @Override
+    protected byte[] getEncryptedContentEncryptionKey(JweCompactConsumer consumer) {
+        byte[] encryptedCekKey = super.getEncryptedContentEncryptionKey(consumer);
+        byte[] tag = getDecodedBytes(consumer, "tag");
+        return JweCompactConsumer.getCipherWithAuthTag(encryptedCekKey, tag);
+    }
+    protected AlgorithmParameterSpec getAlgorithmParameterSpec(JweCompactConsumer consumer) {
+        byte[] iv = getDecodedBytes(consumer, "iv");
+        return CryptoUtils.getContentEncryptionCipherSpec(128, iv);
+    }
+    private byte[] getDecodedBytes(JweCompactConsumer consumer, String headerName) {
+        try {
+            Object ivHeader = consumer.getJweHeaders().getHeader(headerName);
+            return Base64UrlUtility.decode(ivHeader.toString());
+        } catch (Exception ex) {
+            throw new SecurityException(ex);
+        }
+    }
+    protected void validateKeyEncryptionAlgorithm(String keyAlgo) {
+        super.validateKeyEncryptionAlgorithm(keyAlgo);
+        if (!Algorithm.isAesGcmKeyWrap(keyAlgo)) {
+            throw new SecurityException();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyEncryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyEncryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyEncryptionAlgorithm.java
new file mode 100644
index 0000000..e230470
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesGcmWrapKeyEncryptionAlgorithm.java
@@ -0,0 +1,64 @@
+/**
+ * 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.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.Base64UrlUtility;
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class AesGcmWrapKeyEncryptionAlgorithm extends AbstractWrapKeyEncryptionAlgorithm {
+    private static final Set<String> SUPPORTED_ALGORITHMS = new HashSet<String>(
+        Arrays.asList(Algorithm.A128GCMKW.getJwtName(),
+                      Algorithm.A192GCMKW.getJwtName(),
+                      Algorithm.A256GCMKW.getJwtName()));
+    public AesGcmWrapKeyEncryptionAlgorithm(String encodedKey, String keyAlgoJwt) {    
+        this(CryptoUtils.decodeSequence(encodedKey), keyAlgoJwt);
+    }
+    public AesGcmWrapKeyEncryptionAlgorithm(byte[] keyBytes, String keyAlgoJwt) {
+        this(CryptoUtils.createSecretKeySpec(keyBytes, Algorithm.AES_ALGO_JAVA),
+             keyAlgoJwt);
+    }
+    public AesGcmWrapKeyEncryptionAlgorithm(SecretKey key, String keyAlgoJwt) {
+        super(key, keyAlgoJwt, true, SUPPORTED_ALGORITHMS);
+    }
+    
+    @Override
+    public byte[] getEncryptedContentEncryptionKey(JweHeaders headers, byte[] cek) {
+        byte[] wrappedKeyAndTag = super.getEncryptedContentEncryptionKey(headers, cek);
+        byte[] wrappedKey = new byte[wrappedKeyAndTag.length - 128 / 8]; 
+        System.arraycopy(wrappedKeyAndTag, 0, wrappedKey, 0, wrappedKeyAndTag.length - 128 / 8);
+        String encodedTag = Base64UrlUtility.encodeChunk(wrappedKeyAndTag, 
+                                                         wrappedKeyAndTag.length - 128 / 8, 128 / 8);
+        headers.setHeader("tag", encodedTag);
+        return wrappedKey;
+    }
+    protected AlgorithmParameterSpec getAlgorithmParameterSpec(JweHeaders headers) {
+        byte[] iv = CryptoUtils.generateSecureRandomBytes(96 / 8);
+        String encodedIv = Base64UrlUtility.encode(iv);
+        headers.setHeader("iv", encodedIv);
+        return CryptoUtils.getContentEncryptionCipherSpec(128, iv);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyDecryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyDecryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyDecryptionAlgorithm.java
new file mode 100644
index 0000000..3ba6919
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyDecryptionAlgorithm.java
@@ -0,0 +1,53 @@
+/**
+ * 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 javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class AesWrapKeyDecryptionAlgorithm extends WrappedKeyDecryptionAlgorithm {
+    public AesWrapKeyDecryptionAlgorithm(String encodedKey) {    
+        this(encodedKey, null);
+    }
+    public AesWrapKeyDecryptionAlgorithm(String encodedKey, String supportedAlgo) {    
+        this(CryptoUtils.decodeSequence(encodedKey), supportedAlgo);
+    }
+    public AesWrapKeyDecryptionAlgorithm(byte[] secretKey) {    
+        this(secretKey, null);
+    }
+    public AesWrapKeyDecryptionAlgorithm(byte[] secretKey, String supportedAlgo) {    
+        this(CryptoUtils.createSecretKeySpec(secretKey, Algorithm.AES_WRAP_ALGO_JAVA), supportedAlgo);
+    }
+    public AesWrapKeyDecryptionAlgorithm(SecretKey secretKey) {
+        this(secretKey, null);
+    }
+    public AesWrapKeyDecryptionAlgorithm(SecretKey secretKey, String supportedAlgo) {    
+        super(secretKey, supportedAlgo);
+    }
+    @Override
+    protected void validateKeyEncryptionAlgorithm(String keyAlgo) {
+        super.validateKeyEncryptionAlgorithm(keyAlgo);
+        if (!Algorithm.isAesKeyWrap(keyAlgo)) {
+            throw new SecurityException();
+        }
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyEncryptionAlgorithm.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyEncryptionAlgorithm.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyEncryptionAlgorithm.java
new file mode 100644
index 0000000..a8b5899
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AesWrapKeyEncryptionAlgorithm.java
@@ -0,0 +1,48 @@
+/**
+ * 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.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.crypto.SecretKey;
+
+import org.apache.cxf.common.util.crypto.CryptoUtils;
+import org.apache.cxf.rs.security.jose.jwa.Algorithm;
+
+public class AesWrapKeyEncryptionAlgorithm extends AbstractWrapKeyEncryptionAlgorithm {
+    private static final Set<String> SUPPORTED_ALGORITHMS = new HashSet<String>(
+        Arrays.asList(Algorithm.A128KW.getJwtName(),
+                      Algorithm.A192KW.getJwtName(),
+                      Algorithm.A256KW.getJwtName()));
+    public AesWrapKeyEncryptionAlgorithm(String encodedKey, String keyAlgoJwt) {    
+        this(CryptoUtils.decodeSequence(encodedKey), keyAlgoJwt);
+    }
+    public AesWrapKeyEncryptionAlgorithm(byte[] keyBytes, String keyAlgoJwt) {
+        this(CryptoUtils.createSecretKeySpec(keyBytes, Algorithm.toJavaName(keyAlgoJwt)),
+             keyAlgoJwt);
+    }
+    public AesWrapKeyEncryptionAlgorithm(SecretKey key, String keyAlgoJwt) {
+        super(key, keyAlgoJwt, SUPPORTED_ALGORITHMS);
+    }
+    
+    
+    
+}

http://git-wip-us.apache.org/repos/asf/cxf/blob/9c053334/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AuthenticationTagProducer.java
----------------------------------------------------------------------
diff --git a/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AuthenticationTagProducer.java b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AuthenticationTagProducer.java
new file mode 100644
index 0000000..897e68c
--- /dev/null
+++ b/rt/rs/security/jose/src/main/java/org/apache/cxf/rs/security/jose/jwe/AuthenticationTagProducer.java
@@ -0,0 +1,24 @@
+/**
+ * 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;
+
+public interface AuthenticationTagProducer {
+    void update(byte[] cipher, int off, int len);
+    byte[] getTag();
+}