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