001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2016, Connect2id Ltd.
005 *
006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
007 * this file except in compliance with the License. You may obtain a copy of the
008 * License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software distributed
013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the
015 * specific language governing permissions and limitations under the License.
016 */
017
018package com.nimbusds.jose.crypto;
019
020
021import java.security.PrivateKey;
022import java.util.Set;
023import javax.crypto.SecretKey;
024
025import static com.nimbusds.jose.jwk.gen.RSAKeyGenerator.MIN_KEY_SIZE_BITS;
026
027import com.nimbusds.jose.*;
028import com.nimbusds.jose.crypto.impl.*;
029import com.nimbusds.jose.jwk.RSAKey;
030import com.nimbusds.jose.util.Base64URL;
031import net.jcip.annotations.ThreadSafe;
032
033
034/**
035 * RSA decrypter of {@link com.nimbusds.jose.JWEObject JWE objects}. Expects a
036 * private RSA key.
037 *
038 * <p>Decrypts the encrypted Content Encryption Key (CEK) with the private RSA
039 * key, and then uses the CEK along with the IV and authentication tag to
040 * decrypt the cipher text. See RFC 7518, sections
041 * <a href="https://tools.ietf.org/html/rfc7518#section-4.2">4.2</a> and
042 * <a href="https://tools.ietf.org/html/rfc7518#section-4.3">4.3</a> for more
043 * information.
044 *
045 * <p>This class is thread-safe.
046 *
047 * <p>Supports the following key management algorithms:
048 *
049 * <ul>
050 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_256}
051 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_512}
052 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP} (deprecated)
053 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA1_5} (deprecated)
054 * </ul>
055 *
056 * <p>Supports the following content encryption algorithms:
057 *
058 * <ul>
059 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
060 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
061 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
062 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
063 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
064 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
065 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
066 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
067 * </ul>
068 * 
069 * @author David Ortiz
070 * @author Vladimir Dzhuvinov
071 * @author Dimitar A. Stoikov
072 * @version 2021-09-23
073 */
074@ThreadSafe
075public class RSADecrypter extends RSACryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
076
077
078        /**
079         * The critical header policy.
080         */
081        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
082
083
084        /**
085         * The private RSA key.
086         */
087        private final PrivateKey privateKey;
088        
089        
090        /**
091         * Stores a CEK decryption exception is one was encountered during the
092         * last {@link #decrypt} run.
093         */
094        private Exception cekDecryptionException;
095
096
097        /**
098         * Creates a new RSA decrypter. This constructor can also accept a
099         * private RSA key located in a PKCS#11 store that doesn't expose the
100         * private key parameters (such as a smart card or HSM).
101         *
102         * @param privateKey The private RSA key. Its algorithm must be "RSA"
103         *                   and its length at least 2048 bits. Note that the
104         *                   length of an RSA key in a PKCS#11 store cannot be
105         *                   checked. Must not be {@code null}.
106         */
107        public RSADecrypter(final PrivateKey privateKey) {
108
109                this(privateKey, null, false);
110        }
111
112
113        /**
114         * Creates a new RSA decrypter.
115         *
116         * @param rsaJWK The RSA JSON Web Key (JWK). Must contain or reference
117         *               a private part. Its length must be at least 2048 bits.
118         *               Note that the length of an RSA key in a PKCS#11 store
119         *               cannot be checked. Must not be {@code null}.
120         *
121         * @throws JOSEException If the RSA JWK doesn't contain a private part
122         *                       or its extraction failed.
123         */
124        public RSADecrypter(final RSAKey rsaJWK)
125                throws JOSEException {
126
127                this(RSAKeyUtils.toRSAPrivateKey(rsaJWK));
128        }
129
130
131        /**
132         * Creates a new RSA decrypter. This constructor can also accept a
133         * private RSA key located in a PKCS#11 store that doesn't expose the
134         * private key parameters (such as a smart card or HSM).
135         *
136         * @param privateKey     The private RSA key. Its algorithm must be
137         *                       "RSA" and its length at least 2048 bits. Note
138         *                       that the length of an RSA key in a PKCS#11
139         *                       store cannot be checked. Must not be
140         *                       {@code null}.
141         * @param defCritHeaders The names of the critical header parameters
142         *                       that are deferred to the application for
143         *                       processing, empty set or {@code null} if none.
144         */
145        public RSADecrypter(final PrivateKey privateKey,
146                            final Set<String> defCritHeaders) {
147
148                this(privateKey, defCritHeaders, false);
149        }
150
151
152        /**
153         * Creates a new RSA decrypter. This constructor can also accept a
154         * private RSA key located in a PKCS#11 store that doesn't expose the
155         * private key parameters (such as a smart card or HSM).
156         *
157         * @param privateKey     The private RSA key. Its algorithm must be
158         *                       "RSA" and its length at least 2048 bits. Note
159         *                       that the length of an RSA key in a PKCS#11
160         *                       store cannot be checked. Must not be
161         *                       {@code null}.
162         * @param defCritHeaders The names of the critical header parameters
163         *                       that are deferred to the application for
164         *                       processing, empty set or {@code null} if none.
165         * @param allowWeakKey   {@code true} to allow an RSA key shorter than
166         *                       2048 bits.
167         */
168        public RSADecrypter(final PrivateKey privateKey,
169                            final Set<String> defCritHeaders,
170                            final boolean allowWeakKey) {
171
172                if (! privateKey.getAlgorithm().equalsIgnoreCase("RSA")) {
173                        throw new IllegalArgumentException("The private key algorithm must be RSA");
174                }
175                
176                if (! allowWeakKey) {
177                        
178                        int keyBitLength = RSAKeyUtils.keyBitLength(privateKey);
179                        
180                        if (keyBitLength > 0 && keyBitLength < MIN_KEY_SIZE_BITS) {
181                                throw new IllegalArgumentException("The RSA key size must be at least " + MIN_KEY_SIZE_BITS + " bits");
182                        }
183                }
184
185                this.privateKey = privateKey;
186
187                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
188        }
189
190
191        /**
192         * Gets the private RSA key.
193         *
194         * @return The private RSA key. Casting to
195         *         {@link java.security.interfaces.RSAPrivateKey} may not be
196         *         possible if the key is located in a PKCS#11 store that
197         *         doesn't expose the private key parameters.
198         */
199        public PrivateKey getPrivateKey() {
200
201                return privateKey;
202        }
203
204
205        @Override
206        public Set<String> getProcessedCriticalHeaderParams() {
207
208                return critPolicy.getProcessedCriticalHeaderParams();
209        }
210
211
212        @Override
213        public Set<String> getDeferredCriticalHeaderParams() {
214
215                return critPolicy.getProcessedCriticalHeaderParams();
216        }
217
218
219        @Override
220        public byte[] decrypt(final JWEHeader header,
221                              final Base64URL encryptedKey,
222                              final Base64URL iv,
223                              final Base64URL cipherText,
224                              final Base64URL authTag) 
225                throws JOSEException {
226
227                // Validate required JWE parts
228                if (encryptedKey == null) {
229                        throw new JOSEException("Missing JWE encrypted key");
230                }       
231
232                if (iv == null) {
233                        throw new JOSEException("Missing JWE initialization vector (IV)");
234                }
235
236                if (authTag == null) {
237                        throw new JOSEException("Missing JWE authentication tag");
238                }
239
240                critPolicy.ensureHeaderPasses(header);
241                
242
243                // Derive the content encryption key
244                JWEAlgorithm alg = header.getAlgorithm();
245
246                SecretKey cek;
247
248                if (alg.equals(JWEAlgorithm.RSA1_5)) {
249
250                        int keyLength = header.getEncryptionMethod().cekBitLength();
251
252                        // Protect against MMA attack by generating random CEK to be used on decryption failure,
253                        // see http://www.ietf.org/mail-archive/web/jose/current/msg01832.html
254                        final SecretKey randomCEK = ContentCryptoProvider.generateCEK(header.getEncryptionMethod(), getJCAContext().getSecureRandom());
255
256                        try {
257                                cek = RSA1_5.decryptCEK(privateKey, encryptedKey.decode(), keyLength, getJCAContext().getKeyEncryptionProvider());
258
259                                if (cek == null) {
260                                        // CEK length mismatch, signalled by null instead of
261                                        // exception to prevent MMA attack
262                                        cek = randomCEK;
263                                }
264
265                        } catch (Exception e) {
266                                // continue
267                                cekDecryptionException = e;
268                                cek = randomCEK;
269                        }
270                        
271                        cekDecryptionException = null;
272                
273                } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) {
274
275                        cek = RSA_OAEP.decryptCEK(privateKey, encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider());
276
277                } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) {
278                        
279                        cek = RSA_OAEP_256.decryptCEK(privateKey, encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider());
280                        
281                } else if (alg.equals(JWEAlgorithm.RSA_OAEP_512)){
282
283                        cek = RSA_OAEP_512.decryptCEK(privateKey, encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider());
284
285                } else {
286                
287                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
288                }
289
290                return ContentCryptoProvider.decrypt(header, encryptedKey, iv, cipherText, authTag, cek, getJCAContext());
291        }
292        
293        
294        /**
295         * Returns the Content Encryption Key (CEK) decryption exception if one
296         * was encountered during the last {@link #decrypt} run. Intended for
297         * logging and debugging purposes.
298         *
299         * @return The recorded exception, {@code null} if none.
300         */
301        public Exception getCEKDecryptionException() {
302                
303                return cekDecryptionException;
304        }
305}
306