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.interfaces.RSAPublicKey;
022import javax.crypto.SecretKey;
023
024import com.nimbusds.jose.*;
025import com.nimbusds.jose.crypto.impl.*;
026import net.jcip.annotations.ThreadSafe;
027
028import com.nimbusds.jose.jwk.RSAKey;
029import com.nimbusds.jose.util.Base64URL;
030
031
032/**
033 * RSA encrypter of {@link com.nimbusds.jose.JWEObject JWE objects}. Expects a
034 * public RSA key.
035 *
036 * <p>Encrypts the plain text with a generated AES key (the Content Encryption
037 * Key) according to the specified JOSE encryption method, then encrypts the
038 * CEK with the public RSA key and returns it alongside the IV, cipher text and
039 * authentication tag. See RFC 7518, sections
040 * <a href="https://tools.ietf.org/html/rfc7518#section-4.2">4.2</a> and
041 * <a href="https://tools.ietf.org/html/rfc7518#section-4.3">4.3</a> for more
042 * information.
043 *
044 * <p>This class is thread-safe.
045 *
046 * <p>Supports the following key management algorithms:
047 *
048 * <ul>
049 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_256}
050 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_384}
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 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P}
068 * </ul>
069 *
070 * @author David Ortiz
071 * @author Vladimir Dzhuvinov
072 * @author Jun Yu
073 * @author Egor Puzanov
074 * @version 2023-09-10
075 */
076@ThreadSafe
077public class RSAEncrypter extends RSACryptoProvider implements JWEEncrypter {
078
079
080        /**
081         * The public RSA key.
082         */
083        private final RSAPublicKey publicKey;
084
085
086        
087        /**
088         * Creates a new RSA encrypter.
089         *
090         * @param publicKey The public RSA key. Must not be {@code null}.
091         */
092        public RSAEncrypter(final RSAPublicKey publicKey) {
093
094                this(publicKey, null);
095        }
096
097
098        /**
099         * Creates a new RSA encrypter.
100         *
101         *  @param rsaJWK The RSA JSON Web Key (JWK). Must not be {@code null}.
102         *
103         * @throws JOSEException If the RSA JWK extraction failed.
104         */
105        public RSAEncrypter(final RSAKey rsaJWK)
106                throws JOSEException {
107
108                this(rsaJWK.toRSAPublicKey());
109        }
110
111
112        /**
113         * Creates a new RSA encrypter with an optionally specified content
114         * encryption key (CEK).
115         *
116         * @param publicKey            The public RSA key. Must not be
117         *                             {@code null}.
118         * @param contentEncryptionKey The content encryption key (CEK) to use.
119         *                             If specified its algorithm must be "AES"
120         *                             or "ChaCha20" and its length must match
121         *                             the expected for the JWE encryption
122         *                             method ("enc"). If {@code null} a CEK
123         *                             will be generated for each JWE.
124         */
125        public RSAEncrypter(final RSAPublicKey publicKey, final SecretKey contentEncryptionKey) {
126
127                super(contentEncryptionKey);
128
129                if (publicKey == null) {
130                        throw new IllegalArgumentException("The public RSA key must not be null");
131                }
132                this.publicKey = publicKey;
133        }
134        
135        
136        /**
137         * Gets the public RSA key.
138         *
139         * @return The public RSA key.
140         */
141        public RSAPublicKey getPublicKey() {
142                
143                return publicKey;
144        }
145
146
147        /**
148         * Encrypts the specified clear text of a {@link JWEObject JWE object}.
149         *
150         * @param header    The JSON Web Encryption (JWE) header. Must specify
151         *                  a supported JWE algorithm and method. Must not be
152         *                  {@code null}.
153         * @param clearText The clear text to encrypt. Must not be {@code null}.
154         *
155         * @return The resulting JWE crypto parts.
156         *
157         * @throws JOSEException If the JWE algorithm or method is not
158         *                       supported or if encryption failed for some
159         *                       other internal reason.
160         */
161        @Deprecated
162        public JWECryptoParts encrypt(final JWEHeader header, final byte[] clearText)
163                throws JOSEException {
164
165                return encrypt(header, clearText, AAD.compute(header));
166        }
167
168
169        @Override
170        public JWECryptoParts encrypt(final JWEHeader header, final byte[] clearText, final byte[] aad)
171                throws JOSEException {
172
173                final JWEAlgorithm alg = JWEHeaderValidation.getAlgorithmAndEnsureNotNull(header);
174                final EncryptionMethod enc = header.getEncryptionMethod();
175                final SecretKey cek = getCEK(enc); // Generate and encrypt the CEK according to the enc method
176
177                final Base64URL encryptedKey; // The second JWE part
178
179                if (alg.equals(JWEAlgorithm.RSA1_5)) {
180                        encryptedKey = Base64URL.encode(RSA1_5.encryptCEK(publicKey, cek, getJCAContext().getKeyEncryptionProvider()));
181                } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) {
182                        encryptedKey = Base64URL.encode(RSA_OAEP.encryptCEK(publicKey, cek, getJCAContext().getKeyEncryptionProvider()));
183                } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) {
184                        encryptedKey = Base64URL.encode(RSA_OAEP_SHA2.encryptCEK(publicKey, cek, 256, getJCAContext().getKeyEncryptionProvider()));
185                } else if (alg.equals(JWEAlgorithm.RSA_OAEP_384)) {
186                        encryptedKey = Base64URL.encode(RSA_OAEP_SHA2.encryptCEK(publicKey, cek, 384, getJCAContext().getKeyEncryptionProvider()));
187                } else if (alg.equals(JWEAlgorithm.RSA_OAEP_512)) {
188                        encryptedKey = Base64URL.encode(RSA_OAEP_SHA2.encryptCEK(publicKey, cek, 512, getJCAContext().getKeyEncryptionProvider()));
189                } else {
190                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
191                }
192
193                return ContentCryptoProvider.encrypt(header, clearText, aad, cek, encryptedKey, getJCAContext());
194        }
195}