001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, Connect2id Ltd.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.crypto;
019
020
021import java.util.Set;
022import javax.crypto.SecretKey;
023import javax.crypto.spec.SecretKeySpec;
024
025import com.nimbusds.jose.*;
026import com.nimbusds.jose.crypto.impl.AlgorithmSupportMessage;
027import com.nimbusds.jose.crypto.impl.ContentCryptoProvider;
028import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral;
029import com.nimbusds.jose.crypto.impl.DirectCryptoProvider;
030import com.nimbusds.jose.jwk.OctetSequenceKey;
031import com.nimbusds.jose.util.Base64URL;
032import net.jcip.annotations.ThreadSafe;
033
034
035/**
036 * Direct decrypter of {@link com.nimbusds.jose.JWEObject JWE objects} with a
037 * shared symmetric key.
038 *
039 * <p>See RFC 7518
040 * <a href="https://tools.ietf.org/html/rfc7518#section-4.5">section 4.5</a>
041 * for more information.</p>
042 *
043 * <p>This class is thread-safe.
044 *
045 * <p>Supports the following key management algorithms:
046 *
047 * <ul>
048 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR}
049 * </ul>
050 *
051 * <p>Supports the following content encryption algorithms:
052 *
053 * <ul>
054 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} (requires 256 bit key)
055 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} (requires 384 bit key)
056 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} (requires 512 bit key)
057 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} (requires 128 bit key)
058 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} (requires 192 bit key)
059 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} (requires 256 bit key)
060 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} (requires 256 bit key)
061 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} (requires 512 bit key)
062 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P} (requires 256 bit key)
063 * </ul>
064 *
065 * <p>Also supports a promiscuous mode to decrypt any JWE by passing the
066 * content encryption key (CEK) directly. The that mode the JWE algorithm
067 * checks for ("alg":"dir") and encrypted key not being present will be
068 * skipped.
069 * 
070 * @author Vladimir Dzhuvinov
071 * @version 2018-07-16
072 */
073@ThreadSafe
074public class DirectDecrypter extends DirectCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
075        
076        
077        /**
078         * If set skips the checks for alg "dir" and encrypted key not present.
079         */
080        private final boolean promiscuousMode;
081
082
083        /**
084         * The critical header policy.
085         */
086        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
087
088
089        /**
090         * Creates a new direct decrypter.
091         *
092         * @param key The symmetric key. Its algorithm should be "AES". Must be
093         *            128 bits (16 bytes), 192 bits (24 bytes), 256 bits (32
094         *            bytes), 384 bits (48 bytes) or 512 bits (64 bytes) long.
095         *            Must not be {@code null}.
096         *
097         * @throws KeyLengthException If the symmetric key length is not
098         *                            compatible.
099         */
100        public DirectDecrypter(final SecretKey key)
101                throws KeyLengthException {
102
103                this(key, false);
104        }
105
106
107        /**
108         * Creates a new direct decrypter with the option to set it in
109         * promiscuous mode.
110         *
111         * @param key             The symmetric key. Its algorithm should be
112         *                        "AES". Must be 128 bits (16 bytes), 192 bits
113         *                        (24 bytes), 256 bits (32 bytes), 384 bits (48
114         *                        bytes) or 512 bits (64 bytes) long. Must not
115         *                        be {@code null}.
116         * @param promiscuousMode If {@code true} set the decrypter in
117         *                        promiscuous mode to permit decryption of any
118         *                        JWE with the supplied symmetric key. The that
119         *                        mode the JWE algorithm checks for
120         *                        ("alg":"dir") and encrypted key not being
121         *                        present will be skipped.
122         *
123         * @throws KeyLengthException If the symmetric key length is not
124         *                            compatible.
125         */
126        public DirectDecrypter(final SecretKey key, final boolean promiscuousMode)
127                throws KeyLengthException {
128
129                super(key);
130                
131                this.promiscuousMode = promiscuousMode;
132        }
133
134
135        /**
136         * Creates a new direct decrypter.
137         *
138         * @param keyBytes The symmetric key, as a byte array. Must be 128 bits
139         *                 (16 bytes), 192 bits (24 bytes), 256 bits (32
140         *                 bytes), 384 bits (48 bytes) or 512 bits (64 bytes)
141         *                 long. Must not be {@code null}.
142         *
143         * @throws KeyLengthException If the symmetric key length is not
144         *                            compatible.
145         */
146        public DirectDecrypter(final byte[] keyBytes)
147                throws KeyLengthException {
148
149                this(new SecretKeySpec(keyBytes, "AES"), false);
150        }
151
152
153        /**
154         * Creates a new direct decrypter.
155         *
156         * @param octJWK The symmetric key, as a JWK. Must be 128 bits (16
157         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
158         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
159         *               be {@code null}.
160         *
161         * @throws KeyLengthException If the symmetric key length is not
162         *                            compatible.
163         */
164        public DirectDecrypter(final OctetSequenceKey octJWK)
165                throws KeyLengthException {
166
167                this(octJWK.toSecretKey("AES"));
168        }
169
170
171        /**
172         * Creates a new direct decrypter with the option to set it in
173         * promiscuous mode.
174         *
175         * @param key            The symmetric key. Its algorithm should be
176         *                       "AES". Must be 128 bits (16 bytes), 192 bits
177         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
178         *                       bytes) or 512 bits (64 bytes) long. Must not
179         *                       be {@code null}.
180         * @param defCritHeaders The names of the critical header parameters
181         *                       that are deferred to the application for
182         *                       processing, empty set or {@code null} if none.
183         *
184         * @throws KeyLengthException If the symmetric key length is not
185         *                            compatible.
186         */
187        public DirectDecrypter(final SecretKey key, final Set<String> defCritHeaders)
188                throws KeyLengthException {
189
190                this(key, defCritHeaders, false);
191        }
192
193
194        /**
195         * Creates a new direct decrypter.
196         *
197         * @param key            The symmetric key. Its algorithm should be
198         *                       "AES". Must be 128 bits (16 bytes), 192 bits
199         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
200         *                       bytes) or 512 bits (64 bytes) long. Must not
201         *                       be {@code null}.
202         * @param defCritHeaders The names of the critical header parameters
203         *                       that are deferred to the application for
204         *                       processing, empty set or {@code null} if none.
205         *@param promiscuousMode If {@code true} set the decrypter in
206         *                       promiscuous mode to permit decryption of any
207         *                       JWE with the supplied symmetric key. The that
208         *                       mode the JWE algorithm checks for
209         *                       ("alg":"dir") and encrypted key not being
210         *                       present will be skipped.
211         *
212         * @throws KeyLengthException If the symmetric key length is not
213         *                            compatible.
214         */
215        public DirectDecrypter(final SecretKey key,
216                               final Set<String> defCritHeaders,
217                               final boolean promiscuousMode)
218                throws KeyLengthException {
219
220                super(key);
221                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
222                this.promiscuousMode = promiscuousMode;
223        }
224
225
226        @Override
227        public Set<String> getProcessedCriticalHeaderParams() {
228
229                return critPolicy.getProcessedCriticalHeaderParams();
230        }
231
232
233        @Override
234        public Set<String> getDeferredCriticalHeaderParams() {
235
236                return critPolicy.getProcessedCriticalHeaderParams();
237        }
238
239
240        @Override
241        public byte[] decrypt(final JWEHeader header,
242                              final Base64URL encryptedKey,
243                              final Base64URL iv,
244                              final Base64URL cipherText,
245                              final Base64URL authTag) 
246                throws JOSEException {
247
248                // Validate required JWE parts
249                if (! promiscuousMode) {
250                        
251                        JWEAlgorithm alg = header.getAlgorithm();
252                        
253                        if (!alg.equals(JWEAlgorithm.DIR)) {
254                                throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
255                        }
256                        
257                        if (encryptedKey != null) {
258                                throw new JOSEException("Unexpected present JWE encrypted key");
259                        }
260                }
261                
262                if (iv == null) {
263                        throw new JOSEException("Unexpected present JWE initialization vector (IV)");
264                }
265
266                if (authTag == null) {
267                        throw new JOSEException("Missing JWE authentication tag");
268                }
269
270                critPolicy.ensureHeaderPasses(header);
271
272                return ContentCryptoProvider.decrypt(header, null, iv, cipherText, authTag, getKey(), getJCAContext());
273        }
274}