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}