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