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