001package com.nimbusds.jose.crypto;
002
003
004import java.util.HashSet;
005import java.util.Set;
006import javax.crypto.SecretKey;
007
008import com.nimbusds.jose.EncryptionMethod;
009import com.nimbusds.jose.JOSEException;
010import com.nimbusds.jose.JWEAlgorithm;
011import com.nimbusds.jose.JWEDecrypter;
012import com.nimbusds.jose.JWEHeader;
013import com.nimbusds.jose.util.Base64URL;
014import com.nimbusds.jose.util.StringUtils;
015import net.jcip.annotations.ThreadSafe;
016
017
018/**
019 * Direct decrypter of {@link com.nimbusds.jose.JWEObject JWE objects} with a
020 * shared symmetric key. This class is thread-safe.
021 *
022 * <p>Supports the following JWE algorithms:
023 *
024 * <ul>
025 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#DIR}
026 * </ul>
027 *
028 * <p>Supports the following encryption methods:
029 *
030 * <ul>
031 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
032 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
033 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
034 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
035 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
036 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
037 * </ul>
038 *
039 * <p>Accepts all {@link com.nimbusds.jose.JWEHeader#getRegisteredParameterNames
040 * registered JWE header parameters}. Use {@link #setAcceptedAlgorithms} and
041 * {@link #setAcceptedEncryptionMethods} to restrict the acceptable JWE
042 * algorithms and encryption methods.
043 * 
044 * @author Vladimir Dzhuvinov
045 * @version $version$ (2014-07-08)
046 */
047@ThreadSafe
048public class DirectDecrypter extends DirectCryptoProvider implements JWEDecrypter {
049
050
051        /**
052         * The accepted JWE algorithms.
053         */
054        private Set<JWEAlgorithm> acceptedAlgs =
055                new HashSet<>(supportedAlgorithms());
056
057
058        /**
059         * The accepted encryption methods.
060         */
061        private Set<EncryptionMethod> acceptedEncs =
062                new HashSet<>(supportedEncryptionMethods());
063
064
065        /**
066         * The critical header parameter checker.
067         */
068        private final CriticalHeaderParameterChecker critParamChecker =
069                new CriticalHeaderParameterChecker();
070
071
072        /**
073         * Creates a new direct decrypter.
074         *
075         * @param key The shared symmetric key. Its algorithm must be "AES".
076         *            Must be 128 bits (16 bytes), 192 bits (24 bytes), 256
077         *            bits (32 bytes), 384 bits (48 bytes) or 512 bits
078         *            (64 bytes) long. Must not be {@code null}.
079         *
080         * @throws JOSEException If the key length is unexpected.
081         */
082        public DirectDecrypter(final SecretKey key)
083                throws JOSEException {
084
085                super(key);
086        }
087
088
089        /**
090         * Creates a new direct decrypter.
091         *
092         * @param keyBytes The shared symmetric key, as a byte array. Must be 
093         *                 128 bits (16 bytes), 192 bits (24 bytes), 256 bits
094         *                 (32 bytes), 384 bits (48 bytes) or 512 bits (64
095         *                 bytes) long. Must not be {@code null}.
096         *
097         * @throws JOSEException If the key length is unexpected.
098         */
099        public DirectDecrypter(final byte[] keyBytes)
100                throws JOSEException {
101
102                super(keyBytes);
103        }
104
105
106        @Override
107        public Set<JWEAlgorithm> getAcceptedAlgorithms() {
108
109                return acceptedAlgs;
110        }
111
112
113        @Override
114        public void setAcceptedAlgorithms(final Set<JWEAlgorithm> acceptedAlgs) {
115
116                if (acceptedAlgs == null) {
117                        throw new IllegalArgumentException("The accepted JWE algorithms must not be null");
118                }
119
120                if (! supportedAlgorithms().containsAll(acceptedAlgs)) {
121                        throw new IllegalArgumentException("Unsupported JWE algorithm(s)");
122                }
123
124                this.acceptedAlgs = acceptedAlgs;
125        }
126
127
128        @Override
129        public Set<EncryptionMethod> getAcceptedEncryptionMethods() {
130
131                return acceptedEncs;
132        }
133
134
135        @Override
136        public void setAcceptedEncryptionMethods(final Set<EncryptionMethod> acceptedEncs) {
137
138                if (acceptedEncs == null)
139                        throw new IllegalArgumentException("The accepted encryption methods must not be null");
140
141                if (!supportedEncryptionMethods().containsAll(acceptedEncs)) {
142                        throw new IllegalArgumentException("Unsupported encryption method(s)");
143                }
144
145                this.acceptedEncs = acceptedEncs;
146        }
147
148
149        @Override
150        public Set<String> getIgnoredCriticalHeaderParameters() {
151
152                return critParamChecker.getIgnoredCriticalHeaders();
153        }
154
155
156        @Override
157        public void setIgnoredCriticalHeaderParameters(final Set<String> headers) {
158
159                critParamChecker.setIgnoredCriticalHeaders(headers);
160        }
161
162
163        @Override
164        public byte[] decrypt(final JWEHeader header,
165                              final Base64URL encryptedKey,
166                              final Base64URL iv,
167                              final Base64URL cipherText,
168                              final Base64URL authTag) 
169                throws JOSEException {
170
171                // Validate required JWE parts
172                if (encryptedKey != null) {
173
174                        throw new JOSEException("Unexpected encrypted key, must be omitted");
175                }       
176
177                if (iv == null) {
178
179                        throw new JOSEException("The initialization vector (IV) must not be null");
180                }
181
182                if (authTag == null) {
183
184                        throw new JOSEException("The authentication tag must not be null");
185                }
186                
187
188                JWEAlgorithm alg = header.getAlgorithm();
189
190                if (! alg.equals(JWEAlgorithm.DIR)) {
191
192                        throw new JOSEException("Unsupported algorithm, must be \"dir\"");
193                }
194
195                if (! critParamChecker.headerPasses(header)) {
196
197                        throw new JOSEException("Unsupported critical header parameter");
198                }
199
200                // Compose the AAD
201                byte[] aad = StringUtils.toByteArray(header.toBase64URL().toString());
202
203                // Decrypt the cipher text according to the JWE enc
204                EncryptionMethod enc = header.getEncryptionMethod();
205
206                byte[] plainText;
207
208                if (enc.equals(EncryptionMethod.A128CBC_HS256) || enc.equals(EncryptionMethod.A192CBC_HS384) || enc.equals(EncryptionMethod.A256CBC_HS512)) {
209
210                        plainText = AESCBC.decryptAuthenticated(getKey(), iv.decode(), cipherText.decode(), aad, authTag.decode(), contentEncryptionProvider, macProvider);
211
212                } else if (enc.equals(EncryptionMethod.A128GCM) || enc.equals(EncryptionMethod.A192GCM) || enc.equals(EncryptionMethod.A256GCM)) {
213
214                        plainText = AESGCM.decrypt(getKey(), iv.decode(), cipherText.decode(), aad, authTag.decode(), contentEncryptionProvider);
215
216                } else {
217
218                        throw new JOSEException("Unsupported encryption method, must be A128CBC_HS256, A192CBC_HS384, A256CBC_HS512, A128GCM, A192GCM or A128GCM");
219                }
220
221
222                // Apply decompression if requested
223                return DeflateHelper.applyDecompression(header, plainText);
224        }
225}
226