001package com.nimbusds.jose.crypto;
002
003
004import java.util.Set;
005import javax.crypto.SecretKey;
006import javax.crypto.spec.SecretKeySpec;
007
008import net.jcip.annotations.ThreadSafe;
009
010import com.nimbusds.jose.*;
011import com.nimbusds.jose.jwk.OctetSequenceKey;
012import com.nimbusds.jose.util.Base64URL;
013
014
015/**
016 * Direct decrypter of {@link com.nimbusds.jose.JWEObject JWE objects} with a
017 * shared symmetric key.
018 *
019 * <p>See RFC 7518
020 * <a href="https://tools.ietf.org/html/rfc7518#section-4.5">section 4.5</a>
021 * for more information.</p>
022 *
023 * <p>This class is thread-safe.
024 *
025 * <p>Supports the following key management algorithms:
026 *
027 * <ul>
028 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR}
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 Vladimir Dzhuvinov
045 * @version 2015-06-29
046 */
047@ThreadSafe
048public class DirectDecrypter extends DirectCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
049
050
051        /**
052         * The critical header policy.
053         */
054        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
055
056
057        /**
058         * Creates a new direct decrypter.
059         *
060         * @param key The symmetric key. Its algorithm must be "AES". Must be
061         *            128 bits (16 bytes), 192 bits (24 bytes), 256 bits (32
062         *            bytes), 384 bits (48 bytes) or 512 bits (64 bytes) long.
063         *            Must not be {@code null}.
064         *
065         * @throws KeyLengthException If the symmetric key length is not
066         *                            compatible.
067         */
068        public DirectDecrypter(final SecretKey key)
069                throws KeyLengthException {
070
071                super(key);
072        }
073
074
075        /**
076         * Creates a new direct decrypter.
077         *
078         * @param keyBytes The symmetric key, as a byte array. Must be 128 bits
079         *                 (16 bytes), 192 bits (24 bytes), 256 bits (32
080         *                 bytes), 384 bits (48 bytes) or 512 bits (64 bytes)
081         *                 long. Must not be {@code null}.
082         *
083         * @throws KeyLengthException If the symmetric key length is not
084         *                            compatible.
085         */
086        public DirectDecrypter(final byte[] keyBytes)
087                throws KeyLengthException {
088
089                this(new SecretKeySpec(keyBytes, "AES"));
090        }
091
092
093        /**
094         * Creates a new direct decrypter.
095         *
096         * @param octJWK The symmetric key, as a JWK. Must be 128 bits (16
097         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
098         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
099         *               be {@code null}.
100         *
101         * @throws KeyLengthException If the symmetric key length is not
102         *                            compatible.
103         */
104        public DirectDecrypter(final OctetSequenceKey octJWK)
105                throws KeyLengthException {
106
107                this(octJWK.toSecretKey("AES"));
108        }
109
110
111        /**
112         * Creates a new direct decrypter.
113         *
114         * @param key            The symmetric key. Its algorithm must be
115         *                       "AES". Must be 128 bits (16 bytes), 192 bits
116         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
117         *                       bytes) or 512 bits (64 bytes) long. Must not
118         *                       be {@code null}.
119         * @param defCritHeaders The names of the critical header parameters
120         *                       that are deferred to the application for
121         *                       processing, empty set or {@code null} if none.
122         *
123         * @throws KeyLengthException If the symmetric key length is not
124         *                            compatible.
125         */
126        public DirectDecrypter(final SecretKey key, final Set<String> defCritHeaders)
127                throws KeyLengthException {
128
129                super(key);
130
131                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
132        }
133
134
135        @Override
136        public Set<String> getProcessedCriticalHeaderParams() {
137
138                return critPolicy.getProcessedCriticalHeaderParams();
139        }
140
141
142        @Override
143        public Set<String> getDeferredCriticalHeaderParams() {
144
145                return critPolicy.getProcessedCriticalHeaderParams();
146        }
147
148
149        @Override
150        public byte[] decrypt(final JWEHeader header,
151                              final Base64URL encryptedKey,
152                              final Base64URL iv,
153                              final Base64URL cipherText,
154                              final Base64URL authTag) 
155                throws JOSEException {
156
157                // Validate required JWE parts
158                if (encryptedKey != null) {
159                        throw new JOSEException("Unexpected present JWE encrypted key");
160                }       
161
162                if (iv == null) {
163                        throw new JOSEException("Unexpected present JWE initialization vector (IV)");
164                }
165
166                if (authTag == null) {
167                        throw new JOSEException("Missing JWE authentication tag");
168                }
169                
170
171                JWEAlgorithm alg = header.getAlgorithm();
172
173                if (! alg.equals(JWEAlgorithm.DIR)) {
174                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
175                }
176
177                critPolicy.ensureHeaderPasses(header);
178
179                return ContentCryptoProvider.decrypt(header, null, iv, cipherText, authTag, getKey(), getJCAContext());
180        }
181}
182