001package com.nimbusds.jose.crypto;
002
003
004import java.security.interfaces.RSAPublicKey;
005import javax.crypto.SecretKey;
006
007import net.jcip.annotations.ThreadSafe;
008
009import com.nimbusds.jose.EncryptionMethod;
010import com.nimbusds.jose.JOSEException;
011import com.nimbusds.jose.JWEAlgorithm;
012import com.nimbusds.jose.JWECryptoParts;
013import com.nimbusds.jose.JWEEncrypter;
014import com.nimbusds.jose.JWEHeader;
015import com.nimbusds.jose.jwk.RSAKey;
016import com.nimbusds.jose.util.Base64URL;
017
018
019/**
020 * RSA encrypter of {@link com.nimbusds.jose.JWEObject JWE objects}. Expects a
021 * public RSA key.
022 *
023 * <p>Encrypts the plain text with a generated AES key (the Content Encryption
024 * Key) according to the specified JOSE encryption method, then encrypts the
025 * CEK with the public RSA key and returns it alongside the IV, cipher text and
026 * authentication tag. See RFC 7518, sections
027 * <a href="https://tools.ietf.org/html/rfc7518#section-4.2">4.2</a> and
028 * <a href="https://tools.ietf.org/html/rfc7518#section-4.3">4.3</a> for more
029 * information.
030 *
031 * <p>This class is thread-safe.
032 *
033 * <p>Supports the following key management algorithms:
034 *
035 * <ul>
036 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA1_5}
037 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP}
038 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_256}
039 * </ul>
040 *
041 * <p>Supports the following content encryption algorithms:
042 *
043 * <ul>
044 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
045 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
046 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
047 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
048 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
049 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
050 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
051 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
052 * </ul>
053 *
054 * @author David Ortiz
055 * @author Vladimir Dzhuvinov
056 * @version 2015-06-08
057 */
058@ThreadSafe
059public class RSAEncrypter extends RSACryptoProvider implements JWEEncrypter {
060
061
062        /**
063         * The public RSA key.
064         */
065        private final RSAPublicKey publicKey;
066
067
068        /**
069         * Creates a new RSA encrypter.
070         *
071         * @param publicKey The public RSA key. Must not be {@code null}.
072         */
073        public RSAEncrypter(final RSAPublicKey publicKey) {
074
075                if (publicKey == null) {
076                        throw new IllegalArgumentException("The public RSA key must not be null");
077                }
078
079                this.publicKey = publicKey;
080        }
081
082
083        /**
084         * Creates a new RSA encrypter.
085         *
086         *  @param rsaJWK The RSA JSON Web Key (JWK). Must not be {@code null}.
087         *
088         * @throws JOSEException If the RSA JWK extraction failed.
089         */
090        public RSAEncrypter(final RSAKey rsaJWK)
091                throws JOSEException {
092
093                this(rsaJWK.toRSAPublicKey());
094        }
095
096
097        /**
098         * Gets the public RSA key.
099         *
100         * @return The public RSA key.
101         */
102        public RSAPublicKey getPublicKey() {
103
104                return publicKey;
105        }
106
107
108        @Override
109        public JWECryptoParts encrypt(final JWEHeader header, final byte[] clearText)
110                throws JOSEException {
111
112                final JWEAlgorithm alg = header.getAlgorithm();
113                final EncryptionMethod enc = header.getEncryptionMethod();
114
115                // Generate and encrypt the CEK according to the enc method
116                final SecretKey cek = ContentCryptoProvider.generateCEK(enc, getJCAContext().getSecureRandom());
117
118                final Base64URL encryptedKey; // The second JWE part
119
120                if (alg.equals(JWEAlgorithm.RSA1_5)) {
121
122                        encryptedKey = Base64URL.encode(RSA1_5.encryptCEK(publicKey, cek, getJCAContext().getKeyEncryptionProvider()));
123
124                } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) {
125
126                        encryptedKey = Base64URL.encode(RSA_OAEP.encryptCEK(publicKey, cek, getJCAContext().getKeyEncryptionProvider()));
127
128                } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) {
129                        
130                        encryptedKey = Base64URL.encode(RSA_OAEP_256.encryptCEK(publicKey, cek, getJCAContext().getKeyEncryptionProvider()));
131                        
132                } else {
133
134                        throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS));
135                }
136
137                return ContentCryptoProvider.encrypt(header, clearText, cek, encryptedKey, getJCAContext());
138        }
139}