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}