001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2026, 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.Collections;
022import java.util.Set;
023import javax.crypto.SecretKey;
024import javax.crypto.spec.SecretKeySpec;
025
026import com.nimbusds.jose.*;
027import com.nimbusds.jose.crypto.impl.*;
028import com.nimbusds.jose.crypto.opts.OptionUtils;
029import com.nimbusds.jose.jwk.OctetSequenceKey;
030import com.nimbusds.jose.util.Base64URL;
031import net.jcip.annotations.ThreadSafe;
032
033
034/**
035 * Direct decrypter of {@link com.nimbusds.jose.JWEObject JWE objects} with a
036 * shared symmetric key.
037 *
038 * <p>See RFC 7518
039 * <a href="https://tools.ietf.org/html/rfc7518#section-4.5">section 4.5</a>
040 * for more information.</p>
041 *
042 * <p>This class is thread-safe.
043 *
044 * <p>Supports the following key management algorithms:
045 *
046 * <ul>
047 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR}
048 * </ul>
049 *
050 * <p>Supports the following content encryption algorithms:
051 *
052 * <ul>
053 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} (requires 256 bit key)
054 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} (requires 384 bit key)
055 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} (requires 512 bit key)
056 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} (requires 128 bit key)
057 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} (requires 192 bit key)
058 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} (requires 256 bit key)
059 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} (requires 256 bit key)
060 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} (requires 512 bit key)
061 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P} (requires 256 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 * @author Egor Puzanov
071 * @version 2026-09-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         * The configured options, empty set if none.
091         */
092        private final Set<JWEDecrypterOption> opts;
093
094
095        /**
096         * Creates a new direct decrypter.
097         *
098         * @param key The symmetric key. Its algorithm should be "AES". Must be
099         *            128 bits (16 bytes), 192 bits (24 bytes), 256 bits (32
100         *            bytes), 384 bits (48 bytes) or 512 bits (64 bytes) long.
101         *            Must not be {@code null}.
102         *
103         * @throws KeyLengthException If the symmetric key length is not
104         *                            compatible.
105         */
106        public DirectDecrypter(final SecretKey key)
107                throws KeyLengthException {
108
109                this(key, false);
110        }
111
112
113        /**
114         * Creates a new direct decrypter with the option to set it in
115         * promiscuous mode.
116         *
117         * @param key             The symmetric key. Its algorithm should be
118         *                        "AES". Must be 128 bits (16 bytes), 192 bits
119         *                        (24 bytes), 256 bits (32 bytes), 384 bits (48
120         *                        bytes) or 512 bits (64 bytes) long. Must not
121         *                        be {@code null}.
122         * @param promiscuousMode If {@code true} set the decrypter in
123         *                        promiscuous mode to permit decryption of any
124         *                        JWE with the supplied symmetric key. In that
125         *                        mode the JWE algorithm checks for
126         *                        ("alg":"dir") and encrypted key not being
127         *                        present will be skipped.
128         *
129         * @throws KeyLengthException If the symmetric key length is not
130         *                            compatible.
131         */
132        public DirectDecrypter(final SecretKey key, final boolean promiscuousMode)
133                throws KeyLengthException {
134
135                this(key, null, promiscuousMode, Collections.<JWEDecrypterOption>emptySet());
136        }
137
138
139        /**
140         * Creates a new direct decrypter.
141         *
142         * @param keyBytes The symmetric key, as a byte array. Must be 128 bits
143         *                 (16 bytes), 192 bits (24 bytes), 256 bits (32
144         *                 bytes), 384 bits (48 bytes) or 512 bits (64 bytes)
145         *                 long. Must not be {@code null}.
146         *
147         * @throws KeyLengthException If the symmetric key length is not
148         *                            compatible.
149         */
150        public DirectDecrypter(final byte[] keyBytes)
151                throws KeyLengthException {
152
153                this(new SecretKeySpec(keyBytes, "AES"), false);
154        }
155
156
157        /**
158         * Creates a new direct decrypter.
159         *
160         * @param octJWK The symmetric key, as a JWK. Must be 128 bits (16
161         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
162         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
163         *               be {@code null}.
164         *
165         * @throws KeyLengthException If the symmetric key length is not
166         *                            compatible.
167         */
168        public DirectDecrypter(final OctetSequenceKey octJWK)
169                throws KeyLengthException {
170
171                this(octJWK.toSecretKey("AES"));
172        }
173
174
175        /**
176         * Creates a new direct decrypter with the option to set it in
177         * promiscuous mode.
178         *
179         * @param key            The symmetric key. Its algorithm should be
180         *                       "AES". Must be 128 bits (16 bytes), 192 bits
181         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
182         *                       bytes) or 512 bits (64 bytes) long. Must not
183         *                       be {@code null}.
184         * @param defCritHeaders The names of the critical header parameters
185         *                       that are deferred to the application for
186         *                       processing, empty set or {@code null} if none.
187         *
188         * @throws KeyLengthException If the symmetric key length is not
189         *                            compatible.
190         */
191        public DirectDecrypter(final SecretKey key, final Set<String> defCritHeaders)
192                throws KeyLengthException {
193
194                this(key, defCritHeaders, false);
195        }
196
197
198        /**
199         * Creates a new direct decrypter.
200         *
201         * @param key            The symmetric key. Its algorithm should be
202         *                       "AES". Must be 128 bits (16 bytes), 192 bits
203         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
204         *                       bytes) or 512 bits (64 bytes) long. Must not
205         *                       be {@code null}.
206         * @param defCritHeaders The names of the critical header parameters
207         *                       that are deferred to the application for
208         *                       processing, empty set or {@code null} if none.
209         *@param promiscuousMode If {@code true} set the decrypter in
210         *                       promiscuous mode to permit decryption of any
211         *                       JWE with the supplied symmetric key. In that
212         *                       mode the JWE algorithm checks for
213         *                       ("alg":"dir") and encrypted key not being
214         *                       present will be skipped.
215         *
216         * @throws KeyLengthException If the symmetric key length is not
217         *                            compatible.
218         */
219        public DirectDecrypter(final SecretKey key,
220                               final Set<String> defCritHeaders,
221                               final boolean promiscuousMode)
222                throws KeyLengthException {
223
224                this(key, defCritHeaders, promiscuousMode, Collections.<JWEDecrypterOption>emptySet());
225        }
226
227
228        /**
229         * Creates a new direct decrypter.
230         *
231         * @param key            The symmetric key. Its algorithm should be
232         *                       "AES". Must be 128 bits (16 bytes), 192 bits
233         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
234         *                       bytes) or 512 bits (64 bytes) long. Must not
235         *                       be {@code null}.
236         * @param defCritHeaders The names of the critical header parameters
237         *                       that are deferred to the application for
238         *                       processing, empty set or {@code null} if none.
239         * @param promiscuousMode If {@code true} set the decrypter in
240         *                       promiscuous mode to permit decryption of any
241         *                       JWE with the supplied symmetric key. The that
242         *                       mode the JWE algorithm checks for
243         *                       ("alg":"dir") and encrypted key not being
244         *                       present will be skipped.
245         * @param opts           The decryption options, empty or {@code null}
246         *                       if none.
247         *
248         * @throws KeyLengthException If the symmetric key length is not
249         *                            compatible.
250         */
251        public DirectDecrypter(final SecretKey key,
252                               final Set<String> defCritHeaders,
253                               final boolean promiscuousMode,
254                               final Set<JWEDecrypterOption> opts)
255                throws KeyLengthException {
256
257                super(key);
258                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
259                this.promiscuousMode = promiscuousMode;
260                this.opts = opts != null ? opts : Collections.<JWEDecrypterOption>emptySet();
261        }
262
263
264        /**
265         * Creates a new direct decrypter.
266         *
267         * @param key            The symmetric key. Its algorithm should be
268         *                       "AES". Must be 128 bits (16 bytes), 192 bits
269         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
270         *                       bytes) or 512 bits (64 bytes) long. Must not
271         *                       be {@code null}.
272         * @param defCritHeaders The names of the critical header parameters
273         *                       that are deferred to the application for
274         *                       processing, empty set or {@code null} if none.
275         * @param opts           The decryption options, empty or {@code null}
276         *                       if none.
277         *
278         * @throws KeyLengthException If the symmetric key length is not
279         *                            compatible.
280         */
281        public DirectDecrypter(final SecretKey key,
282                               final Set<String> defCritHeaders,
283                               final Set<JWEDecrypterOption> opts)
284                throws KeyLengthException {
285
286                this(key, defCritHeaders, false, opts);
287        }
288
289
290        /**
291         * Creates a new direct decrypter with the option to set it in
292         * promiscuous mode.
293         *
294         * @param key             The symmetric key. Its algorithm should be
295         *                        "AES". Must be 128 bits (16 bytes), 192 bits
296         *                        (24 bytes), 256 bits (32 bytes), 384 bits (48
297         *                        bytes) or 512 bits (64 bytes) long. Must not
298         *                        be {@code null}.
299         * @param promiscuousMode If {@code true} set the decrypter in
300         *                        promiscuous mode to permit decryption of any
301         *                        JWE with the supplied symmetric key. In that
302         *                        mode the JWE algorithm checks for
303         *                        ("alg":"dir") and encrypted key not being
304         *                        present will be skipped.
305         * @param opts            The decryption options, empty or {@code null}
306         *                        if none.
307         *
308         * @throws KeyLengthException If the symmetric key length is not
309         *                            compatible.
310         */
311        public DirectDecrypter(final SecretKey key,
312                               final boolean promiscuousMode,
313                               final Set<JWEDecrypterOption> opts)
314                throws KeyLengthException {
315
316                this(key, null, promiscuousMode, opts);
317        }
318
319
320        /**
321         * Creates a new direct decrypter.
322         *
323         * @param keyBytes The symmetric key, as a byte array. Must be 128 bits
324         *                 (16 bytes), 192 bits (24 bytes), 256 bits (32
325         *                 bytes), 384 bits (48 bytes) or 512 bits (64 bytes)
326         *                 long. Must not be {@code null}.
327         * @param opts     The decryption options, empty or {@code null} if
328         *                 none.
329         *
330         * @throws KeyLengthException If the symmetric key length is not
331         *                            compatible.
332         */
333        public DirectDecrypter(final byte[] keyBytes,
334                               final Set<JWEDecrypterOption> opts)
335                throws KeyLengthException {
336
337                this(new SecretKeySpec(keyBytes, "AES"), null, false, opts);
338        }
339
340
341        /**
342         * Creates a new direct decrypter.
343         *
344         * @param octJWK The symmetric key, as a JWK. Must be 128 bits (16
345         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
346         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
347         *               be {@code null}.
348         * @param opts   The decryption options, empty or {@code null} if none.
349         *
350         * @throws KeyLengthException If the symmetric key length is not
351         *                            compatible.
352         */
353        public DirectDecrypter(final OctetSequenceKey octJWK,
354                               final Set<JWEDecrypterOption> opts)
355                throws KeyLengthException {
356
357                this(octJWK.toSecretKey("AES"), null, false, opts);
358        }
359
360
361        /**
362         * Creates a new direct decrypter.
363         *
364         * @param octJWK         The symmetric key, as a JWK. Must be 128 bits
365         *                       (16 bytes), 192 bits (24 bytes), 256 bits (32
366         *                       bytes), 384 bits (48 bytes) or 512 bits (64
367         *                       bytes) long. Must not be {@code null}.
368         * @param defCritHeaders The names of the critical header parameters
369         *                       that are deferred to the application for
370         *                       processing, empty set or {@code null} if none.
371         * @param opts           The decryption options, empty or {@code null}
372         *                       if none.
373         *
374         * @throws KeyLengthException If the symmetric key length is not
375         *                            compatible.
376         */
377        public DirectDecrypter(final OctetSequenceKey octJWK,
378                               final Set<String> defCritHeaders,
379                               final Set<JWEDecrypterOption> opts)
380                throws KeyLengthException {
381
382                this(octJWK.toSecretKey("AES"), defCritHeaders, false, opts);
383        }
384
385
386        @Override
387        public Set<String> getProcessedCriticalHeaderParams() {
388
389                return critPolicy.getProcessedCriticalHeaderParams();
390        }
391
392
393        @Override
394        public Set<String> getDeferredCriticalHeaderParams() {
395
396                return critPolicy.getDeferredCriticalHeaderParams();
397        }
398
399
400        /**
401         * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
402         *
403         * @param header       The JSON Web Encryption (JWE) header. Must
404         *                     specify a supported JWE algorithm and method.
405         *                     Must not be {@code null}.
406         * @param encryptedKey The encrypted key, {@code null} if not required
407         *                     by the JWE algorithm.
408         * @param iv           The initialisation vector, {@code null} if not
409         *                     required by the JWE algorithm.
410         * @param cipherText   The cipher text to decrypt. Must not be
411         *                     {@code null}.
412         * @param authTag      The authentication tag, {@code null} if not
413         *                     required.
414         *
415         * @return The clear text.
416         *
417         * @throws JOSEException If the JWE algorithm or method is not
418         *                       supported, if a critical header parameter is
419         *                       not supported or marked for deferral to the
420         *                       application, or if decryption failed for some
421         *                       other reason.
422         */
423        @Deprecated
424        public byte[] decrypt(final JWEHeader header,
425                       final Base64URL encryptedKey,
426                       final Base64URL iv,
427                       final Base64URL cipherText,
428                       final Base64URL authTag)
429                throws JOSEException {
430
431                return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
432        }
433
434
435        @Override
436        public byte[] decrypt(final JWEHeader header,
437                              final Base64URL encryptedKey,
438                              final Base64URL iv,
439                              final Base64URL cipherText,
440                              final Base64URL authTag,
441                              final byte[] aad)
442                throws JOSEException {
443
444                // Validate required JWE parts
445                if (! promiscuousMode) {
446                        
447                        JWEAlgorithm alg = JWEHeaderValidation.getAlgorithmAndEnsureNotNull(header);
448                        
449                        if (!alg.equals(JWEAlgorithm.DIR)) {
450                                throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
451                        }
452                        
453                        if (encryptedKey != null) {
454                                throw new JOSEException("Unexpected present JWE encrypted key");
455                        }
456                }
457                
458                if (iv == null) {
459                        throw new JOSEException("Unexpected present JWE initialization vector (IV)");
460                }
461
462                if (authTag == null) {
463                        throw new JOSEException("Missing JWE authentication tag");
464                }
465
466                critPolicy.ensureHeaderPasses(header);
467
468                int maxDecompressedLength = OptionUtils.resolveMaxDecompressedPlainTextLength(opts);
469
470                return ContentCryptoProvider.decrypt(header, aad, null, iv, cipherText, authTag, getKey(), getJCAContext(), maxDecompressedLength);
471        }
472}