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. This class is thread-safe.
018 *
019 * <p>Supports the following key management algorithms:
020 *
021 * <ul>
022 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR}
023 * </ul>
024 *
025 * <p>Supports the following content encryption algorithms:
026 *
027 * <ul>
028 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
029 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
030 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
031 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
032 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
033 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
034 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
035 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
036 * </ul>
037 * 
038 * @author Vladimir Dzhuvinov
039 * @version 2015-06-29
040 */
041@ThreadSafe
042public class DirectDecrypter extends DirectCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
043
044
045        /**
046         * The critical header policy.
047         */
048        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
049
050
051        /**
052         * Creates a new direct decrypter.
053         *
054         * @param key The symmetric key. Its algorithm must be "AES". Must be
055         *            128 bits (16 bytes), 192 bits (24 bytes), 256 bits (32
056         *            bytes), 384 bits (48 bytes) or 512 bits (64 bytes) long.
057         *            Must not be {@code null}.
058         *
059         * @throws KeyLengthException If the symmetric key length is not
060         *                            compatible.
061         */
062        public DirectDecrypter(final SecretKey key)
063                throws KeyLengthException {
064
065                super(key);
066        }
067
068
069        /**
070         * Creates a new direct decrypter.
071         *
072         * @param keyBytes The symmetric key, as a byte array. Must be 128 bits
073         *                 (16 bytes), 192 bits (24 bytes), 256 bits (32
074         *                 bytes), 384 bits (48 bytes) or 512 bits (64 bytes)
075         *                 long. Must not be {@code null}.
076         *
077         * @throws KeyLengthException If the symmetric key length is not
078         *                            compatible.
079         */
080        public DirectDecrypter(final byte[] keyBytes)
081                throws KeyLengthException {
082
083                this(new SecretKeySpec(keyBytes, "AES"));
084        }
085
086
087        /**
088         * Creates a new direct decrypter.
089         *
090         * @param octJWK The symmetric key, as a JWK. Must be 128 bits (16
091         *               bytes), 192 bits (24 bytes), 256 bits (32 bytes), 384
092         *               bits (48 bytes) or 512 bits (64 bytes) long. Must not
093         *               be {@code null}.
094         *
095         * @throws KeyLengthException If the symmetric key length is not
096         *                            compatible.
097         */
098        public DirectDecrypter(final OctetSequenceKey octJWK)
099                throws KeyLengthException {
100
101                this(octJWK.toSecretKey("AES"));
102        }
103
104
105        /**
106         * Creates a new direct decrypter.
107         *
108         * @param key            The symmetric key. Its algorithm must be
109         *                       "AES". Must be 128 bits (16 bytes), 192 bits
110         *                       (24 bytes), 256 bits (32 bytes), 384 bits (48
111         *                       bytes) or 512 bits (64 bytes) long. Must not
112         *                       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 symmetric key length is not
118         *                            compatible.
119         */
120        public DirectDecrypter(final SecretKey key, final Set<String> defCritHeaders)
121                throws KeyLengthException {
122
123                super(key);
124
125                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
126        }
127
128
129        @Override
130        public Set<String> getProcessedCriticalHeaderParams() {
131
132                return critPolicy.getProcessedCriticalHeaderParams();
133        }
134
135
136        @Override
137        public Set<String> getDeferredCriticalHeaderParams() {
138
139                return critPolicy.getProcessedCriticalHeaderParams();
140        }
141
142
143        @Override
144        public byte[] decrypt(final JWEHeader header,
145                              final Base64URL encryptedKey,
146                              final Base64URL iv,
147                              final Base64URL cipherText,
148                              final Base64URL authTag) 
149                throws JOSEException {
150
151                // Validate required JWE parts
152                if (encryptedKey != null) {
153                        throw new JOSEException("Unexpected present JWE encrypted key");
154                }       
155
156                if (iv == null) {
157                        throw new JOSEException("Unexpected present JWE initialization vector (IV)");
158                }
159
160                if (authTag == null) {
161                        throw new JOSEException("Missing JWE authentication tag");
162                }
163                
164
165                JWEAlgorithm alg = header.getAlgorithm();
166
167                if (! alg.equals(JWEAlgorithm.DIR)) {
168                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
169                }
170
171                critPolicy.ensureHeaderPasses(header);
172
173                return ContentCryptoProvider.decrypt(header, null, iv, cipherText, authTag, getKey(), getJCAContext());
174        }
175}
176