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 com.nimbusds.jose.*;
022import com.nimbusds.jose.crypto.impl.*;
023import com.nimbusds.jose.crypto.opts.OptionUtils;
024import com.nimbusds.jose.jwk.OctetSequenceKey;
025import com.nimbusds.jose.util.Base64URL;
026import net.jcip.annotations.ThreadSafe;
027
028import javax.crypto.SecretKey;
029import javax.crypto.spec.SecretKeySpec;
030import java.util.Collections;
031import java.util.Set;
032
033
034/**
035 * AES and AES GCM key wrap decrypter of {@link com.nimbusds.jose.JWEObject JWE
036 * objects}. Expects an AES key.
037 *
038 * <p>Unwraps the encrypted Content Encryption Key (CEK) with the specified AES
039 * key, and then uses the CEK along with the IV and authentication tag to
040 * decrypt the cipher text. See RFC 7518, sections
041 * <a href="https://tools.ietf.org/html/rfc7518#section-4.4">4.4</a> and
042 * <a href="https://tools.ietf.org/html/rfc7518#section-4.7">4.7</a> for more
043 * information.
044 *
045 * <p>This class is thread-safe.
046 *
047 * <p>Supports the following key management algorithms:
048 *
049 * <ul>
050 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#A128KW}
051 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#A192KW}
052 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#A256KW}
053 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#A128GCMKW}
054 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#A192GCMKW}
055 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#A256GCMKW}
056 * </ul>
057 *
058 * <p>Supports the following content encryption algorithms:
059 *
060 * <ul>
061 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
062 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
063 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
064 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
065 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
066 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
067 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
068 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
069 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P}
070 * </ul>
071 *
072 * @author Melisa Halsband
073 * @author Vladimir Dzhuvinov
074 * @author Egor Puzanov
075 * @version 2026-09-16
076 */
077@ThreadSafe
078public class AESDecrypter extends AESCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
079
080
081        /**
082         * The critical header policy.
083         */
084        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
085
086
087        /**
088         * The configured options, empty set if none.
089         */
090        private final Set<JWEDecrypterOption> opts;
091
092
093        /**
094         * Creates a new AES decrypter.
095         *
096         * @param kek The Key Encrypting Key. Must be 128 bits (16 bytes), 192
097         *            bits (24 bytes) or 256 bits (32 bytes). Must not be
098         *            {@code null}.
099         *
100         * @throws KeyLengthException If the KEK length is invalid.
101         */
102        public AESDecrypter(final SecretKey kek)
103                throws KeyLengthException {
104
105                this(kek, null, Collections.<JWEDecrypterOption>emptySet());
106        }
107
108
109        /**
110         * Creates a new AES decrypter.
111         *
112         * @param keyBytes The Key Encrypting Key, as a byte array. Must be 128
113         *                 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32
114         *                 bytes). Must not be {@code null}.
115         *
116         * @throws KeyLengthException If the KEK length is invalid.
117         */
118        public AESDecrypter(final byte[] keyBytes)
119                throws KeyLengthException {
120
121                this(new SecretKeySpec(keyBytes, "AES"));
122        }
123
124
125        /**
126         * Creates a new AES decrypter.
127         *
128         * @param octJWK The Key Encryption Key, as a JWK. Must be 128 bits (16
129         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
130         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
131         *               be {@code null}.
132         *
133         * @throws KeyLengthException If the KEK length is invalid.
134         */
135        public AESDecrypter(final OctetSequenceKey octJWK)
136                throws KeyLengthException {
137
138                this(octJWK.toSecretKey("AES"));
139        }
140
141
142        /**
143         * Creates a new AES decrypter.
144         *
145         * @param kek            The Key Encrypting Key. Must be 128 bits (16
146         *                       bytes), 192 bits (24 bytes) or 256 bits (32
147         *                       bytes). Must not be {@code null}.
148         * @param defCritHeaders The names of the critical header parameters
149         *                       that are deferred to the application for
150         *                       processing, empty set or {@code null} if none.
151         *
152         * @throws KeyLengthException If the KEK length is invalid.
153         */
154        public AESDecrypter(final SecretKey kek, final Set<String> defCritHeaders)
155                throws KeyLengthException {
156
157                this(kek, defCritHeaders, Collections.<JWEDecrypterOption>emptySet());
158        }
159
160
161        /**
162         * Creates a new AES decrypter.
163         *
164         * @param kek            The Key Encrypting Key. Must be 128 bits (16
165         *                       bytes), 192 bits (24 bytes) or 256 bits (32
166         *                       bytes). Must not be {@code null}.
167         * @param defCritHeaders The names of the critical header parameters
168         *                       that are deferred to the application for
169         *                       processing, empty set or {@code null} if none.
170         * @param opts           The decryption options, empty or {@code null}
171         *                       if none.
172         *
173         * @throws KeyLengthException If the KEK length is invalid.
174         */
175        public AESDecrypter(final SecretKey kek,
176                            final Set<String> defCritHeaders,
177                            final Set<JWEDecrypterOption> opts)
178                throws KeyLengthException {
179
180                super(kek, null);
181
182                this.opts = opts != null ? opts : Collections.<JWEDecrypterOption>emptySet();
183
184                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
185        }
186
187
188        /**
189         * Creates a new AES decrypter.
190         *
191         * @param keyBytes The Key Encrypting Key, as a byte array. Must be 128
192         *                 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32
193         *                 bytes). Must not be {@code null}.
194         * @param opts     The decryption options, empty or {@code null} if
195         *                 none.
196         *
197         * @throws KeyLengthException If the KEK length is invalid.
198         */
199        public AESDecrypter(final byte[] keyBytes,
200                            final Set<JWEDecrypterOption> opts)
201                throws KeyLengthException {
202
203                this(new SecretKeySpec(keyBytes, "AES"), null, opts);
204        }
205
206
207        /**
208         * Creates a new AES decrypter.
209         *
210         * @param octJWK The Key Encryption Key, as a JWK. Must be 128 bits (16
211         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
212         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
213         *               be {@code null}.
214         * @param opts   The decryption options, empty or {@code null} if none.
215         *
216         * @throws KeyLengthException If the KEK length is invalid.
217         */
218        public AESDecrypter(final OctetSequenceKey octJWK,
219                            final Set<JWEDecrypterOption> opts)
220                throws KeyLengthException {
221
222                this(octJWK.toSecretKey("AES"), null, opts);
223        }
224
225
226        /**
227         * Creates a new AES decrypter.
228         *
229         * @param octJWK         The Key Encryption Key, as a JWK. Must be 128
230         *                       bits (16 bytes), 192 bits (24 bytes), 256 bits
231         *                       (32 bytes), 384 bits (48 bytes) or 512 bits
232         *                       (64 bytes) long. Must not be {@code null}.
233         * @param defCritHeaders The names of the critical header parameters
234         *                       that are deferred to the application for
235         *                       processing, empty set or {@code null} if none.
236         * @param opts           The decryption options, empty or {@code null}
237         *                       if none.
238         *
239         * @throws KeyLengthException If the KEK length is invalid.
240         */
241        public AESDecrypter(final OctetSequenceKey octJWK,
242                            final Set<String> defCritHeaders,
243                            final Set<JWEDecrypterOption> opts)
244                throws KeyLengthException {
245
246                this(octJWK.toSecretKey("AES"), defCritHeaders, opts);
247        }
248
249
250        @Override
251        public Set<String> getProcessedCriticalHeaderParams() {
252
253                return critPolicy.getProcessedCriticalHeaderParams();
254        }
255
256
257        @Override
258        public Set<String> getDeferredCriticalHeaderParams() {
259
260                return critPolicy.getDeferredCriticalHeaderParams();
261        }
262
263
264        /**
265         * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
266         *
267         * @param header       The JSON Web Encryption (JWE) header. Must
268         *                     specify a supported JWE algorithm and method.
269         *                     Must not be {@code null}.
270         * @param encryptedKey The encrypted key, {@code null} if not required
271         *                     by the JWE algorithm.
272         * @param iv           The initialisation vector, {@code null} if not
273         *                     required by the JWE algorithm.
274         * @param cipherText   The cipher text to decrypt. Must not be
275         *                     {@code null}.
276         * @param authTag      The authentication tag, {@code null} if not
277         *                     required.
278         *
279         * @return The clear text.
280         *
281         * @throws JOSEException If the JWE algorithm or method is not
282         *                       supported, if a critical header parameter is
283         *                       not supported or marked for deferral to the
284         *                       application, or if decryption failed for some
285         *                       other reason.
286         */
287        @Deprecated
288        public byte[] decrypt(final JWEHeader header,
289                       final Base64URL encryptedKey,
290                       final Base64URL iv,
291                       final Base64URL cipherText,
292                       final Base64URL authTag)
293                throws JOSEException {
294
295                return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
296        }
297
298
299        @Override
300        public byte[] decrypt(final JWEHeader header,
301                              final Base64URL encryptedKey,
302                              final Base64URL iv,
303                              final Base64URL cipherText,
304                              final Base64URL authTag,
305                              final byte[] aad)
306                throws JOSEException {
307
308                // Validate required JWE parts
309                if (encryptedKey == null) {
310                        throw new JOSEException("Missing JWE encrypted key");
311                }
312
313                if (iv == null) {
314                        throw new JOSEException("Missing JWE initialization vector (IV)");
315                }
316
317                if (authTag == null) {
318                        throw new JOSEException("Missing JWE authentication tag");
319                }
320
321                // Derive the content encryption key
322                JWEAlgorithm alg = JWEHeaderValidation.getAlgorithmAndEnsureNotNull(header);
323
324                critPolicy.ensureHeaderPasses(header);
325
326                int keyLength = header.getEncryptionMethod().cekBitLength();
327
328                final SecretKey cek;
329
330                if (alg.equals(JWEAlgorithm.A128KW) ||
331                    alg.equals(JWEAlgorithm.A192KW) ||
332                    alg.equals(JWEAlgorithm.A256KW))   {
333
334                        cek = AESKW.unwrapCEK(getKey(), encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider());
335
336                } else if (alg.equals(JWEAlgorithm.A128GCMKW) ||
337                           alg.equals(JWEAlgorithm.A192GCMKW) ||
338                           alg.equals(JWEAlgorithm.A256GCMKW)) {
339
340                        if (header.getIV() == null) {
341                                throw new JOSEException("Missing JWE \"iv\" header parameter");
342                        }
343
344                        byte[] keyIV = header.getIV().decode();
345
346                        if (header.getAuthTag() == null) {
347                                throw new JOSEException("Missing JWE \"tag\" header parameter");
348                        }
349
350                        byte[] keyTag = header.getAuthTag().decode();
351
352                        AuthenticatedCipherText authEncrCEK = new AuthenticatedCipherText(encryptedKey.decode(), keyTag);
353                        cek = AESGCMKW.decryptCEK(getKey(), keyIV, authEncrCEK, keyLength, getJCAContext().getKeyEncryptionProvider());
354
355                } else {
356
357                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
358                }
359
360                int maxDecompressedLength = OptionUtils.resolveMaxDecompressedPlainTextLength(opts);
361
362                return ContentCryptoProvider.decrypt(header, aad, encryptedKey, iv, cipherText, authTag, cek, getJCAContext(), maxDecompressedLength);
363        }
364}