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