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;
022
023import javax.crypto.SecretKey;
024import javax.crypto.spec.SecretKeySpec;
025
026import com.nimbusds.jose.crypto.impl.*;
027import net.jcip.annotations.ThreadSafe;
028
029import com.nimbusds.jose.*;
030import com.nimbusds.jose.jwk.OctetSequenceKey;
031import com.nimbusds.jose.util.Base64URL;
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 2023-09-10
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         * Creates a new AES decrypter.
089         *
090         * @param kek The Key Encrypting Key. Must be 128 bits (16 bytes), 192
091         *            bits (24 bytes) or 256 bits (32 bytes). Must not be
092         *            {@code null}.
093         *
094         * @throws KeyLengthException If the KEK length is invalid.
095         */
096        public AESDecrypter(final SecretKey kek)
097                throws KeyLengthException {
098
099                this(kek, null);
100        }
101
102
103        /**
104         * Creates a new AES decrypter.
105         *
106         * @param keyBytes The Key Encrypting Key, as a byte array. Must be 128
107         *                 bits (16 bytes), 192 bits (24 bytes) or 256 bits (32
108         *                 bytes). Must not be {@code null}.
109         *
110         * @throws KeyLengthException If the KEK length is invalid.
111         */
112        public AESDecrypter(final byte[] keyBytes)
113                throws KeyLengthException {
114
115                this(new SecretKeySpec(keyBytes, "AES"));
116        }
117
118
119        /**
120         * Creates a new AES decrypter.
121         *
122         * @param octJWK The Key Encryption Key, as a JWK. Must be 128 bits (16
123         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
124         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
125         *               be {@code null}.
126         *
127         * @throws KeyLengthException If the KEK length is invalid.
128         */
129        public AESDecrypter(final OctetSequenceKey octJWK)
130                throws KeyLengthException {
131
132                this(octJWK.toSecretKey("AES"));
133        }
134
135
136        /**
137         * Creates a new AES decrypter.
138         *
139         * @param kek            The Key Encrypting Key. Must be 128 bits (16
140         *                       bytes), 192 bits (24 bytes) or 256 bits (32
141         *                       bytes). Must not be {@code null}.
142         * @param defCritHeaders The names of the critical header parameters
143         *                       that are deferred to the application for
144         *                       processing, empty set or {@code null} if none.
145         *
146         * @throws KeyLengthException If the KEK length is invalid.
147         */
148        public AESDecrypter(final SecretKey kek, final Set<String> defCritHeaders)
149                throws KeyLengthException {
150
151                super(kek, null);
152
153                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
154        }
155
156
157        @Override
158        public Set<String> getProcessedCriticalHeaderParams() {
159
160                return critPolicy.getProcessedCriticalHeaderParams();
161        }
162
163
164        @Override
165        public Set<String> getDeferredCriticalHeaderParams() {
166
167                return critPolicy.getProcessedCriticalHeaderParams();
168        }
169
170
171        /**
172         * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
173         *
174         * @param header       The JSON Web Encryption (JWE) header. Must
175         *                     specify a supported JWE algorithm and method.
176         *                     Must not be {@code null}.
177         * @param encryptedKey The encrypted key, {@code null} if not required
178         *                     by the JWE algorithm.
179         * @param iv           The initialisation vector, {@code null} if not
180         *                     required by the JWE algorithm.
181         * @param cipherText   The cipher text to decrypt. Must not be
182         *                     {@code null}.
183         * @param authTag      The authentication tag, {@code null} if not
184         *                     required.
185         *
186         * @return The clear text.
187         *
188         * @throws JOSEException If the JWE algorithm or method is not
189         *                       supported, if a critical header parameter is
190         *                       not supported or marked for deferral to the
191         *                       application, or if decryption failed for some
192         *                       other reason.
193         */
194        @Deprecated
195        public byte[] decrypt(final JWEHeader header,
196                       final Base64URL encryptedKey,
197                       final Base64URL iv,
198                       final Base64URL cipherText,
199                       final Base64URL authTag)
200                throws JOSEException {
201
202                return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
203        }
204
205
206        @Override
207        public byte[] decrypt(final JWEHeader header,
208                              final Base64URL encryptedKey,
209                              final Base64URL iv,
210                              final Base64URL cipherText,
211                              final Base64URL authTag,
212                              final byte[] aad)
213                throws JOSEException {
214
215                // Validate required JWE parts
216                if (encryptedKey == null) {
217                        throw new JOSEException("Missing JWE encrypted key");
218                }
219
220                if (iv == null) {
221                        throw new JOSEException("Missing JWE initialization vector (IV)");
222                }
223
224                if (authTag == null) {
225                        throw new JOSEException("Missing JWE authentication tag");
226                }
227
228                // Derive the content encryption key
229                JWEAlgorithm alg = JWEHeaderValidation.getAlgorithmAndEnsureNotNull(header);
230
231                critPolicy.ensureHeaderPasses(header);
232
233                int keyLength = header.getEncryptionMethod().cekBitLength();
234
235                final SecretKey cek;
236
237                if (alg.equals(JWEAlgorithm.A128KW) ||
238                    alg.equals(JWEAlgorithm.A192KW) ||
239                    alg.equals(JWEAlgorithm.A256KW))   {
240
241                        cek = AESKW.unwrapCEK(getKey(), encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider());
242
243                } else if (alg.equals(JWEAlgorithm.A128GCMKW) ||
244                           alg.equals(JWEAlgorithm.A192GCMKW) ||
245                           alg.equals(JWEAlgorithm.A256GCMKW)) {
246
247                        if (header.getIV() == null) {
248                                throw new JOSEException("Missing JWE \"iv\" header parameter");
249                        }
250
251                        byte[] keyIV = header.getIV().decode();
252
253                        if (header.getAuthTag() == null) {
254                                throw new JOSEException("Missing JWE \"tag\" header parameter");
255                        }
256
257                        byte[] keyTag = header.getAuthTag().decode();
258
259                        AuthenticatedCipherText authEncrCEK = new AuthenticatedCipherText(encryptedKey.decode(), keyTag);
260                        cek = AESGCMKW.decryptCEK(getKey(), keyIV, authEncrCEK, keyLength, getJCAContext().getKeyEncryptionProvider());
261
262                } else {
263
264                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
265                }
266
267                return ContentCryptoProvider.decrypt(header, aad, encryptedKey, iv, cipherText, authTag, cek, getJCAContext());
268        }
269}