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