001package com.nimbusds.jose.crypto; 002 003 004import java.util.Set; 005 006import javax.crypto.SecretKey; 007import javax.crypto.spec.SecretKeySpec; 008 009import net.jcip.annotations.ThreadSafe; 010 011import com.nimbusds.jose.*; 012import com.nimbusds.jose.jwk.OctetSequenceKey; 013import com.nimbusds.jose.util.Base64URL; 014 015 016/** 017 * AES and AES GCM key wrap decrypter of {@link com.nimbusds.jose.JWEObject JWE 018 * objects}. Expects an AES key. 019 * 020 * <p>Unwraps the encrypted Content Encryption Key (CEK) with the specified AES 021 * key, and then uses the CEK along with the IV and authentication tag to 022 * decrypt the cipher text. See RFC 7518, sections 023 * <a href="https://tools.ietf.org/html/rfc7518#section-4.4">4.4</a> and 024 * <a href="https://tools.ietf.org/html/rfc7518#section-4.7">4.7</a> for more 025 * information. 026 * 027 * <p>This class is thread-safe. 028 * 029 * <p>Supports the following key management algorithms: 030 * 031 * <ul> 032 * <li>{@link com.nimbusds.jose.JWEAlgorithm#A128KW} 033 * <li>{@link com.nimbusds.jose.JWEAlgorithm#A192KW} 034 * <li>{@link com.nimbusds.jose.JWEAlgorithm#A256KW} 035 * <li>{@link com.nimbusds.jose.JWEAlgorithm#A128GCMKW} 036 * <li>{@link com.nimbusds.jose.JWEAlgorithm#A192GCMKW} 037 * <li>{@link com.nimbusds.jose.JWEAlgorithm#A256GCMKW} 038 * </ul> 039 * 040 * <p>Supports the following content encryption algorithms: 041 * 042 * <ul> 043 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 044 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 045 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 046 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 047 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 048 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 049 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 050 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 051 * </ul> 052 * 053 * @author Melisa Halsband 054 * @author Vladimir Dzhuvinov 055 * @version 2015-06-29 056 */ 057@ThreadSafe 058public class AESDecrypter extends AESCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware { 059 060 061 /** 062 * The critical header policy. 063 */ 064 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 065 066 067 /** 068 * Creates a new AES decrypter. 069 * 070 * @param kek The Key Encrypting Key. Must be 128 bits (16 bytes), 192 071 * bits (24 bytes) or 256 bits (32 bytes). Must not be 072 * {@code null}. 073 * 074 * @throws KeyLengthException If the KEK length is invalid. 075 */ 076 public AESDecrypter(final SecretKey kek) 077 throws KeyLengthException { 078 079 this(kek, null); 080 } 081 082 083 /** 084 * Creates a new AES decrypter. 085 * 086 * @param keyBytes The Key Encrypting Key, as a byte array. Must be 128 087 * bits (16 bytes), 192 bits (24 bytes) or 256 bits (32 088 * bytes). Must not be {@code null}. 089 * 090 * @throws KeyLengthException If the KEK length is invalid. 091 */ 092 public AESDecrypter(final byte[] keyBytes) 093 throws KeyLengthException { 094 095 this(new SecretKeySpec(keyBytes, "AES")); 096 } 097 098 099 /** 100 * Creates a new AES decrypter. 101 * 102 * @param octJWK The Key Encryption Key, as a JWK. Must be 128 bits (16 103 * bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384 104 * bits (48 bytes) or 512 bits (64 bytes) long. Must not 105 * be {@code null}. 106 * 107 * @throws KeyLengthException If the KEK length is invalid. 108 */ 109 public AESDecrypter(final OctetSequenceKey octJWK) 110 throws KeyLengthException { 111 112 this(octJWK.toSecretKey("AES")); 113 } 114 115 116 /** 117 * Creates a new AES decrypter. 118 * 119 * @param kek The Key Encrypting Key. Must be 128 bits (16 120 * bytes), 192 bits (24 bytes) or 256 bits (32 121 * bytes). Must not be {@code null}. 122 * @param defCritHeaders The names of the critical header parameters 123 * that are deferred to the application for 124 * processing, empty set or {@code null} if none. 125 * 126 * @throws KeyLengthException If the KEK length is invalid. 127 */ 128 public AESDecrypter(final SecretKey kek, final Set<String> defCritHeaders) 129 throws KeyLengthException { 130 131 super(kek); 132 133 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 134 } 135 136 137 @Override 138 public Set<String> getProcessedCriticalHeaderParams() { 139 140 return critPolicy.getProcessedCriticalHeaderParams(); 141 } 142 143 144 @Override 145 public Set<String> getDeferredCriticalHeaderParams() { 146 147 return critPolicy.getProcessedCriticalHeaderParams(); 148 } 149 150 151 @Override 152 public byte[] decrypt(final JWEHeader header, 153 final Base64URL encryptedKey, 154 final Base64URL iv, 155 final Base64URL cipherText, 156 final Base64URL authTag) 157 throws JOSEException { 158 159 // Validate required JWE parts 160 if (encryptedKey == null) { 161 throw new JOSEException("Missing JWE encrypted key"); 162 } 163 164 if (iv == null) { 165 throw new JOSEException("Missing JWE initialization vector (IV)"); 166 } 167 168 if (authTag == null) { 169 throw new JOSEException("Missing JWE authentication tag"); 170 } 171 172 critPolicy.ensureHeaderPasses(header); 173 174 // Derive the content encryption key 175 JWEAlgorithm alg = header.getAlgorithm(); 176 int keyLength = header.getEncryptionMethod().cekBitLength(); 177 178 final SecretKey cek; 179 180 if (alg.equals(JWEAlgorithm.A128KW) || 181 alg.equals(JWEAlgorithm.A192KW) || 182 alg.equals(JWEAlgorithm.A256KW)) { 183 184 cek = AESKW.unwrapCEK(getKey(), encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider()); 185 186 } else if (alg.equals(JWEAlgorithm.A128GCMKW) || 187 alg.equals(JWEAlgorithm.A192GCMKW) || 188 alg.equals(JWEAlgorithm.A256GCMKW)) { 189 190 if (header.getIV() == null) { 191 throw new JOSEException("Missing JWE \"iv\" header parameter"); 192 } 193 194 byte[] keyIV = header.getIV().decode(); 195 196 if (header.getAuthTag() == null) { 197 throw new JOSEException("Missing JWE \"tag\" header parameter"); 198 } 199 200 byte[] keyTag = header.getAuthTag().decode(); 201 202 AuthenticatedCipherText authEncrCEK = new AuthenticatedCipherText(encryptedKey.decode(), keyTag); 203 cek = AESGCMKW.decryptCEK(getKey(), keyIV, authEncrCEK, keyLength, getJCAContext().getKeyEncryptionProvider()); 204 205 } else { 206 207 throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS)); 208 } 209 210 return ContentCryptoProvider.decrypt(header, encryptedKey, iv, cipherText, authTag, cek, getJCAContext()); 211 } 212}