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.PrivateKey; 022import java.util.Set; 023import javax.crypto.SecretKey; 024 025import com.nimbusds.jose.*; 026import com.nimbusds.jose.jwk.RSAKey; 027import com.nimbusds.jose.util.Base64URL; 028import net.jcip.annotations.ThreadSafe; 029 030 031/** 032 * RSA decrypter of {@link com.nimbusds.jose.JWEObject JWE objects}. Expects a 033 * private RSA key. 034 * 035 * <p>Decrypts the encrypted Content Encryption Key (CEK) with the private RSA 036 * key, and then uses the CEK along with the IV and authentication tag to 037 * decrypt the cipher text. See RFC 7518, sections 038 * <a href="https://tools.ietf.org/html/rfc7518#section-4.2">4.2</a> and 039 * <a href="https://tools.ietf.org/html/rfc7518#section-4.3">4.3</a> for more 040 * information. 041 * 042 * <p>This class is thread-safe. 043 * 044 * <p>Supports the following key management algorithms: 045 * 046 * <ul> 047 * <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP_256} 048 * <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA_OAEP} (deprecated) 049 * <li>{@link com.nimbusds.jose.JWEAlgorithm#RSA1_5} (deprecated) 050 * </ul> 051 * 052 * <p>Supports the following content encryption algorithms: 053 * 054 * <ul> 055 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 056 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 057 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 058 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 059 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 060 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 061 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 062 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 063 * </ul> 064 * 065 * @author David Ortiz 066 * @author Vladimir Dzhuvinov 067 * @author Dimitar A. Stoikov 068 * @version 2016-12-01 069 */ 070@ThreadSafe 071public class RSADecrypter extends RSACryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware { 072 073 074 /** 075 * The critical header policy. 076 */ 077 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 078 079 080 /** 081 * The private RSA key. 082 */ 083 private final PrivateKey privateKey; 084 085 086 /** 087 * Stores a CEK decryption exception is one was encountered during the 088 * last {@link #decrypt} run. 089 */ 090 private Exception cekDecryptionException; 091 092 093 /** 094 * Creates a new RSA decrypter. This constructor can also accept a 095 * private RSA key located in a PKCS#11 store that doesn't expose the 096 * private key parameters (such as a smart card or HSM). 097 * 098 * @param privateKey The private RSA key. Must not be {@code null}. 099 */ 100 public RSADecrypter(final PrivateKey privateKey) { 101 102 this(privateKey, null); 103 } 104 105 106 /** 107 * Creates a new RSA decrypter. 108 * 109 * @param rsaJWK The RSA JSON Web Key (JWK). Must contain a private 110 * part. Must not be {@code null}. 111 * 112 * @throws JOSEException If the RSA JWK doesn't contain a private part 113 * or its extraction failed. 114 */ 115 public RSADecrypter(final RSAKey rsaJWK) 116 throws JOSEException { 117 118 if (! rsaJWK.isPrivate()) { 119 throw new JOSEException("The RSA JWK doesn't contain a private part"); 120 } 121 122 privateKey = rsaJWK.toPrivateKey(); 123 } 124 125 126 /** 127 * Creates a new RSA decrypter. This constructor can also accept a 128 * private RSA key located in a key store that doesn't expose the 129 * private key parameters (such as a smart card or HSM). 130 * 131 * @param privateKey The private RSA key. Its algorithm must be 132 * "RSA". Must not be {@code null}. 133 * @param defCritHeaders The names of the critical header parameters 134 * that are deferred to the application for 135 * processing, empty set or {@code null} if none. 136 */ 137 public RSADecrypter(final PrivateKey privateKey, 138 final Set<String> defCritHeaders) { 139 140 if (privateKey == null) { 141 throw new IllegalArgumentException("The private RSA key must not be null"); 142 } 143 144 if (! privateKey.getAlgorithm().equalsIgnoreCase("RSA")) { 145 throw new IllegalArgumentException("The private key algorithm must be RSA"); 146 } 147 148 this.privateKey = privateKey; 149 150 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 151 } 152 153 154 /** 155 * Gets the private RSA key. 156 * 157 * @return The private RSA key. Casting to 158 * {@link java.security.interfaces.RSAPrivateKey} may not be 159 * possible if the key is located in a PKCS#11 store that 160 * doesn't expose the private key parameters. 161 */ 162 public PrivateKey getPrivateKey() { 163 164 return privateKey; 165 } 166 167 168 @Override 169 public Set<String> getProcessedCriticalHeaderParams() { 170 171 return critPolicy.getProcessedCriticalHeaderParams(); 172 } 173 174 175 @Override 176 public Set<String> getDeferredCriticalHeaderParams() { 177 178 return critPolicy.getProcessedCriticalHeaderParams(); 179 } 180 181 182 @Override 183 public byte[] decrypt(final JWEHeader header, 184 final Base64URL encryptedKey, 185 final Base64URL iv, 186 final Base64URL cipherText, 187 final Base64URL authTag) 188 throws JOSEException { 189 190 // Validate required JWE parts 191 if (encryptedKey == null) { 192 throw new JOSEException("Missing JWE encrypted key"); 193 } 194 195 if (iv == null) { 196 throw new JOSEException("Missing JWE initialization vector (IV)"); 197 } 198 199 if (authTag == null) { 200 throw new JOSEException("Missing JWE authentication tag"); 201 } 202 203 critPolicy.ensureHeaderPasses(header); 204 205 206 // Derive the content encryption key 207 JWEAlgorithm alg = header.getAlgorithm(); 208 209 SecretKey cek; 210 211 if (alg.equals(JWEAlgorithm.RSA1_5)) { 212 213 int keyLength = header.getEncryptionMethod().cekBitLength(); 214 215 // Protect against MMA attack by generating random CEK to be used on decryption failure, 216 // see http://www.ietf.org/mail-archive/web/jose/current/msg01832.html 217 final SecretKey randomCEK = ContentCryptoProvider.generateCEK(header.getEncryptionMethod(), getJCAContext().getSecureRandom()); 218 219 try { 220 cek = RSA1_5.decryptCEK(privateKey, encryptedKey.decode(), keyLength, getJCAContext().getKeyEncryptionProvider()); 221 222 if (cek == null) { 223 // CEK length mismatch, signalled by null instead of 224 // exception to prevent MMA attack 225 cek = randomCEK; 226 } 227 228 } catch (Exception e) { 229 // continue 230 cekDecryptionException = e; 231 cek = randomCEK; 232 } 233 234 cekDecryptionException = null; 235 236 } else if (alg.equals(JWEAlgorithm.RSA_OAEP)) { 237 238 cek = RSA_OAEP.decryptCEK(privateKey, encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider()); 239 240 } else if (alg.equals(JWEAlgorithm.RSA_OAEP_256)) { 241 242 cek = RSA_OAEP_256.decryptCEK(privateKey, encryptedKey.decode(), getJCAContext().getKeyEncryptionProvider()); 243 244 } else { 245 246 throw new JOSEException(AlgorithmSupportMessage.unsupportedJWEAlgorithm(alg, SUPPORTED_ALGORITHMS)); 247 } 248 249 return ContentCryptoProvider.decrypt(header, encryptedKey, iv, cipherText, authTag, cek, getJCAContext()); 250 } 251 252 253 /** 254 * Returns the Content Encryption Key (CEK) decryption exception if one 255 * was encountered during the last {@link #decrypt} run. Intended for 256 * logging and debugging purposes. 257 * 258 * @return The recorded exception, {@code null} if none. 259 */ 260 public Exception getCEKDecryptionException() { 261 262 return cekDecryptionException; 263 } 264} 265