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