001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2015-2016 ForgeRock AS. 015 */ 016 017package org.forgerock.json.jose.jwe.handlers.encryption; 018 019import static java.security.spec.MGF1ParameterSpec.SHA256; 020import static javax.crypto.spec.PSource.PSpecified.DEFAULT; 021import static org.forgerock.json.jose.jwe.JweAlgorithm.RSA_OAEP_256; 022import static org.forgerock.json.jose.jwe.JweAlgorithmType.RSA; 023import static org.forgerock.util.Reject.checkNotNull; 024 025import java.security.GeneralSecurityException; 026import java.security.Key; 027import java.security.interfaces.RSAPublicKey; 028import java.security.spec.AlgorithmParameterSpec; 029 030import javax.crypto.Cipher; 031import javax.crypto.spec.OAEPParameterSpec; 032 033import org.forgerock.json.jose.exceptions.JweDecryptionException; 034import org.forgerock.json.jose.exceptions.JweEncryptionException; 035import org.forgerock.json.jose.jwe.EncryptionMethod; 036import org.forgerock.json.jose.jwe.JweAlgorithm; 037import org.forgerock.json.jose.jwe.JweEncryption; 038import org.forgerock.util.Reject; 039 040/** 041 * Abstract base class for implementations of the RSAES-PKCS1-v1_5 and RSA-OAEP encryption schemes. 042 * 043 * @see <a href="https://tools.ietf.org/html/rfc7518#section-4.2">RFC 7518 Section 4.2 and 4.3</a> 044 */ 045public final class RSAEncryptionHandler implements EncryptionHandler { 046 private static final OAEPParameterSpec RSA_OAEP_256_PARAMS = new OAEPParameterSpec("SHA-256", "MGF1", SHA256, 047 DEFAULT); 048 private final EncryptionMethod encryptionMethod; 049 private final ContentEncryptionHandler contentEncryptionHandler; 050 private final JweAlgorithm jweAlgorithm; 051 private final AlgorithmParameterSpec parameterSpec; 052 053 /** 054 * Constructs a new RSAEncryptionHandler instance. 055 * 056 * @param encryptionMethod the content encryption method. Must not be null. 057 * @param jweAlgorithm the JWE algorithm. Must not be null. Must be an RSA encryption algorithm. 058 */ 059 public RSAEncryptionHandler(EncryptionMethod encryptionMethod, final JweAlgorithm jweAlgorithm) { 060 this.encryptionMethod = checkNotNull(encryptionMethod, "EncryptionMethod must not be null"); 061 this.jweAlgorithm = checkNotNull(jweAlgorithm, "JweAlgorithm must not be null"); 062 Reject.ifFalse(jweAlgorithm.getAlgorithmType() == RSA, "JweAlgorithm type must be RSA"); 063 this.contentEncryptionHandler = ContentEncryptionHandler.getInstance(encryptionMethod); 064 // RSA-OAEP-256 requires non-default algorithm parameters to conform to the JWE spec. The JRE defaults are 065 // correct for all other modes, so leave as null. 066 this.parameterSpec = jweAlgorithm == RSA_OAEP_256 ? RSA_OAEP_256_PARAMS : null; 067 } 068 069 /** 070 * Creates a Content Encryption Key (CEK) by generating a random key value with a length equal to the 071 * EncryptionMethod A128CBC_HS256 key size. 072 * <p> 073 * See point 2 in <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-11#section-5.1"> 074 * Section 5.1</a> of the JWE Specification. 075 * 076 * @return {@inheritDoc} 077 */ 078 @Override 079 public Key getContentEncryptionKey() { 080 return contentEncryptionHandler.generateEncryptionKey(); 081 } 082 083 /** 084 * Generates the JWE Encrypted Key by encrypting the Content Encryption Key (CEK) using the JweAlgorithm 085 * RSAES_PCKCS1_V1_5. 086 * <p> 087 * See point 4 in <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-11#section-5.1"> 088 * Section 5.1</a> of the JWE Specification. 089 * 090 * @param key {@inheritDoc} 091 * @param contentEncryptionKey {@inheritDoc} 092 * @return {@inheritDoc} 093 */ 094 @Override 095 public byte[] generateJWEEncryptedKey(Key key, Key contentEncryptionKey) { 096 return encryptKey((RSAPublicKey) key, contentEncryptionKey); 097 } 098 099 /** 100 * Generates a random JWE Initialisation Vector of the correct size for the encryption algorithm. 101 * <p> 102 * See points 9 in <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-11#section-5.1"> 103 * Section 5.1</a> of the JWE Specification. 104 * 105 * @return {@inheritDoc} 106 */ 107 @Override 108 public byte[] generateInitialisationVector() { 109 return contentEncryptionHandler.generateInitialisationVector(); 110 } 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override 116 public JweEncryption encryptPlaintext(Key contentEncryptionKey, byte[] initialisationVector, byte[] plaintext, 117 byte[] additionalAuthenticatedData) { 118 119 return contentEncryptionHandler.encrypt(contentEncryptionKey, initialisationVector, plaintext, 120 additionalAuthenticatedData); 121 } 122 123 /** 124 * Decrypts the JWE Encrypted Key to produce the Content Encryption Key (CEK). 125 * <p> 126 * See points 10 in <a href="http://tools.ietf.org/html/draft-ietf-jose-json-web-encryption-11#section-5.2"> 127 * Section 5.2</a> of the JWE Specification. 128 * 129 * @param key {@inheritDoc} 130 * @param encryptedContentEncryptionKey {@inheritDoc} 131 * @return {@inheritDoc} 132 */ 133 @Override 134 public Key decryptContentEncryptionKey(Key key, byte[] encryptedContentEncryptionKey) { 135 try { 136 final Cipher cipher = Cipher.getInstance(jweAlgorithm.getAlgorithm()); 137 cipher.init(Cipher.UNWRAP_MODE, key, parameterSpec); 138 return cipher.unwrap(encryptedContentEncryptionKey, encryptionMethod.getEncryptionAlgorithm(), 139 Cipher.SECRET_KEY); 140 } catch (GeneralSecurityException e) { 141 throw new JweDecryptionException(); 142 } 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 public byte[] decryptCiphertext(Key contentEncryptionKey, byte[] initialisationVector, byte[] ciphertext, 150 byte[] authenticationTag, byte[] additionalAuthenticatedData) { 151 return contentEncryptionHandler.decrypt(contentEncryptionKey, initialisationVector, 152 new JweEncryption(ciphertext, authenticationTag), additionalAuthenticatedData); 153 } 154 155 private byte[] encryptKey(final RSAPublicKey keyEncryptionKey, final Key contentKey) { 156 try { 157 final Cipher cipher = Cipher.getInstance(jweAlgorithm.getAlgorithm()); 158 cipher.init(Cipher.WRAP_MODE, keyEncryptionKey, parameterSpec); 159 return cipher.wrap(contentKey); 160 } catch (GeneralSecurityException e) { 161 throw new JweEncryptionException(e); 162 } 163 } 164}