001package com.nimbusds.jose.crypto; 002 003 004import java.security.SecureRandom; 005import java.security.interfaces.RSAPublicKey; 006 007import javax.crypto.SecretKey; 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.ReadOnlyJWEHeader; 015import com.nimbusds.jose.util.Base64URL; 016import com.nimbusds.jose.util.StringUtils; 017 018 019 020/** 021 * RSA encrypter of {@link com.nimbusds.jose.JWEObject JWE objects}. This class 022 * is thread-safe. 023 * 024 * <p>Supports the following JWE algorithms: 025 * 026 * <ul> 027 * <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA1_5} 028 * <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP} 029 * </ul> 030 * 031 * <p>Supports the following encryption methods: 032 * 033 * <ul> 034 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 035 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 036 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 037 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 038 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 039 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 040 * </ul> 041 * 042 * @author David Ortiz 043 * @author Vladimir Dzhuvinov 044 * @version $version$ (2014-01-28) 045 */ 046public class RSAEncrypter extends RSACryptoProvider implements JWEEncrypter { 047 048 049 /** 050 * The public RSA key. 051 */ 052 private final RSAPublicKey publicKey; 053 054 055 /** 056 * Creates a new RSA encrypter. 057 * 058 * @param publicKey The public RSA key. Must not be {@code null}. 059 * 060 * @throws JOSEException If the underlying secure random generator 061 * couldn't be instantiated. 062 */ 063 public RSAEncrypter(final RSAPublicKey publicKey) 064 throws JOSEException { 065 066 if (publicKey == null) { 067 068 throw new IllegalArgumentException("The public RSA key must not be null"); 069 } 070 071 this.publicKey = publicKey; 072 } 073 074 075 /** 076 * Gets the public RSA key. 077 * 078 * @return The public RSA key. 079 */ 080 public RSAPublicKey getPublicKey() { 081 082 return publicKey; 083 } 084 085 086 @Override 087 public JWECryptoParts encrypt(final ReadOnlyJWEHeader readOnlyJWEHeader, final byte[] bytes) 088 throws JOSEException { 089 090 JWEAlgorithm alg = readOnlyJWEHeader.getAlgorithm(); 091 EncryptionMethod enc = readOnlyJWEHeader.getEncryptionMethod(); 092 093 // Generate and encrypt the CEK according to the enc method 094 SecureRandom randomGen = getSecureRandom(); 095 SecretKey cek = AES.generateKey(enc.cekBitLength(), randomGen); 096 097 Base64URL encryptedKey; // The second JWE part 098 099 if (alg.equals(JWEAlgorithm.RSA1_5)) { 100 101 encryptedKey = Base64URL.encode(RSA1_5.encryptCEK(publicKey, cek, keyEncryptionProvider)); 102 103 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 104 105 encryptedKey = Base64URL.encode(RSA_OAEP.encryptCEK(publicKey, cek, keyEncryptionProvider)); 106 107 } else { 108 109 throw new JOSEException("Unsupported JWE algorithm, must be RSA1_5 or RSA-OAEP"); 110 } 111 112 113 // Apply compression if instructed 114 byte[] plainText = DeflateHelper.applyCompression(readOnlyJWEHeader, bytes); 115 116 // Compose the AAD 117 byte[] aad = StringUtils.toByteArray(readOnlyJWEHeader.toBase64URL().toString()); 118 119 // Encrypt the plain text according to the JWE enc 120 byte[] iv; 121 AuthenticatedCipherText authCipherText; 122 123 if (enc.equals(EncryptionMethod.A128CBC_HS256) || enc.equals(EncryptionMethod.A192CBC_HS384) || enc.equals(EncryptionMethod.A256CBC_HS512)) { 124 125 iv = AESCBC.generateIV(randomGen); 126 127 authCipherText = AESCBC.encryptAuthenticated(cek, iv, plainText, aad, contentEncryptionProvider, macProvider); 128 129 } else if (enc.equals(EncryptionMethod.A128GCM) || enc.equals(EncryptionMethod.A192GCM) || enc.equals(EncryptionMethod.A256GCM)) { 130 131 iv = AESGCM.generateIV(randomGen); 132 133 authCipherText = AESGCM.encrypt(cek, iv, plainText, aad, contentEncryptionProvider); 134 135 } else { 136 137 throw new JOSEException("Unsupported encryption method, must be A128CBC_HS256, A192CBC_HS384, A256CBC_HS512, A128GCM, A192GCM or A256GCM"); 138 } 139 140 return new JWECryptoParts(encryptedKey, 141 Base64URL.encode(iv), 142 Base64URL.encode(authCipherText.getCipherText()), 143 Base64URL.encode(authCipherText.getAuthenticationTag())); 144 } 145}