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}