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.security.interfaces.ECPrivateKey; 023import java.security.interfaces.ECPublicKey; 024import java.util.Collections; 025import java.util.LinkedHashSet; 026import java.util.Set; 027import javax.crypto.SecretKey; 028 029import com.nimbusds.jose.*; 030import com.nimbusds.jose.crypto.impl.AAD; 031import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral; 032import com.nimbusds.jose.crypto.impl.ECDH; 033import com.nimbusds.jose.crypto.impl.ECDHCryptoProvider; 034import com.nimbusds.jose.crypto.utils.ECChecks; 035import com.nimbusds.jose.jwk.Curve; 036import com.nimbusds.jose.jwk.ECKey; 037import com.nimbusds.jose.util.Base64URL; 038 039 040/** 041 * Elliptic Curve Diffie-Hellman decrypter of 042 * {@link com.nimbusds.jose.JWEObject JWE objects} for curves using EC JWK 043 * keys. Expects a private EC key (with a P-256, P-384 or P-521 curve). 044 * 045 * <p>See RFC 7518 046 * <a href="https://tools.ietf.org/html/rfc7518#section-4.6">section 4.6</a> 047 * for more information. 048 * 049 * <p>For Curve25519/X25519, see {@link X25519Decrypter} instead. 050 * 051 * <p>This class is thread-safe. 052 * 053 * <p>Supports the following key management algorithms: 054 * 055 * <ul> 056 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES} 057 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A128KW} 058 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A192KW} 059 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A256KW} 060 * </ul> 061 * 062 * <p>Supports the following elliptic curves: 063 * 064 * <ul> 065 * <li>{@link com.nimbusds.jose.jwk.Curve#P_256} 066 * <li>{@link com.nimbusds.jose.jwk.Curve#P_384} 067 * <li>{@link com.nimbusds.jose.jwk.Curve#P_521} 068 * </ul> 069 * 070 * <p>Supports the following content encryption algorithms: 071 * 072 * <ul> 073 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 074 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 075 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 076 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 077 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 078 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 079 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 080 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 081 * <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P} 082 * </ul> 083 * 084 * @author Vladimir Dzhuvinov 085 * @author Egor Puzanov 086 * @version 2023-05-17 087 */ 088public class ECDHDecrypter extends ECDHCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware { 089 090 091 /** 092 * The supported EC JWK curves by the ECDH crypto provider class. 093 */ 094 public static final Set<Curve> SUPPORTED_ELLIPTIC_CURVES; 095 096 097 static { 098 Set<Curve> curves = new LinkedHashSet<>(); 099 curves.add(Curve.P_256); 100 curves.add(Curve.P_384); 101 curves.add(Curve.P_521); 102 SUPPORTED_ELLIPTIC_CURVES = Collections.unmodifiableSet(curves); 103 } 104 105 106 /** 107 * The private EC key. 108 */ 109 private final PrivateKey privateKey; 110 111 112 /** 113 * The critical header policy. 114 */ 115 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 116 117 118 /** 119 * Creates a new Elliptic Curve Diffie-Hellman decrypter. 120 * 121 * @param privateKey The private EC key. Must not be {@code null}. 122 * 123 * @throws JOSEException If the elliptic curve is not supported. 124 */ 125 public ECDHDecrypter(final ECPrivateKey privateKey) 126 throws JOSEException { 127 128 this(privateKey, null); 129 } 130 131 132 /** 133 * Creates a new Elliptic Curve Diffie-Hellman decrypter. 134 * 135 * @param ecJWK The EC JSON Web Key (JWK). Must contain a private 136 * part. Must not be {@code null}. 137 * 138 * @throws JOSEException If the elliptic curve is not supported. 139 */ 140 public ECDHDecrypter(final ECKey ecJWK) 141 throws JOSEException { 142 143 super(ecJWK.getCurve(), null); 144 145 if (! ecJWK.isPrivate()) { 146 throw new JOSEException("The EC JWK doesn't contain a private part"); 147 } 148 149 this.privateKey = ecJWK.toECPrivateKey(); 150 } 151 152 153 /** 154 * Creates a new Elliptic Curve Diffie-Hellman decrypter. 155 * 156 * @param privateKey The private EC key. Must not be {@code null}. 157 * @param defCritHeaders The names of the critical header parameters 158 * that are deferred to the application for 159 * processing, empty set or {@code null} if none. 160 * 161 * @throws JOSEException If the elliptic curve is not supported. 162 */ 163 public ECDHDecrypter(final ECPrivateKey privateKey, final Set<String> defCritHeaders) 164 throws JOSEException { 165 166 this(privateKey, defCritHeaders, Curve.forECParameterSpec(privateKey.getParams())); 167 } 168 169 170 /** 171 * Creates a new Elliptic Curve Diffie-Hellman decrypter. This 172 * constructor can also accept a private EC key located in a PKCS#11 173 * store that doesn't expose the private key parameters (such as a 174 * smart card or HSM). 175 * 176 * @param privateKey The private EC key. Must not be {@code null}. 177 * @param defCritHeaders The names of the critical header parameters 178 * that are deferred to the application for 179 * processing, empty set or {@code null} if none. 180 * @param curve The key curve. Must not be {@code null}. 181 * 182 * @throws JOSEException If the elliptic curve is not supported. 183 */ 184 public ECDHDecrypter(final PrivateKey privateKey, 185 final Set<String> defCritHeaders, 186 final Curve curve) 187 throws JOSEException { 188 189 super(curve, null); 190 191 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 192 193 this.privateKey = privateKey; 194 } 195 196 197 /** 198 * Returns the private EC key. 199 * 200 * @return The private EC key. Casting to 201 * {@link java.security.interfaces.ECPrivateKey} may not be 202 * possible if the key is located in a PKCS#11 store that 203 * doesn't expose the private key parameters. 204 */ 205 public PrivateKey getPrivateKey() { 206 207 return privateKey; 208 } 209 210 211 @Override 212 public Set<Curve> supportedEllipticCurves() { 213 214 return SUPPORTED_ELLIPTIC_CURVES; 215 } 216 217 218 @Override 219 public Set<String> getProcessedCriticalHeaderParams() { 220 221 return critPolicy.getProcessedCriticalHeaderParams(); 222 } 223 224 225 @Override 226 public Set<String> getDeferredCriticalHeaderParams() { 227 228 return critPolicy.getProcessedCriticalHeaderParams(); 229 } 230 231 232 /** 233 * Decrypts the specified cipher text of a {@link JWEObject JWE 234 * Object}. 235 * 236 * @param header The JSON Web Encryption (JWE) header. Must 237 * specify a supported JWE algorithm and method. 238 * Must not be {@code null}. 239 * @param encryptedKey The encrypted key, {@code null} if not required 240 * by the JWE algorithm. 241 * @param iv The initialisation vector, {@code null} if not 242 * required by the JWE algorithm. 243 * @param cipherText The cipher text to decrypt. Must not be 244 * {@code null}. 245 * @param authTag The authentication tag, {@code null} if not 246 * required. 247 * 248 * @return The clear text. 249 * 250 * @throws JOSEException If the JWE algorithm or method is not 251 * supported, if a critical header parameter is 252 * not supported or marked for deferral to the 253 * application, or if decryption failed for some 254 * other reason. 255 */ 256 @Deprecated 257 public byte[] decrypt(final JWEHeader header, 258 final Base64URL encryptedKey, 259 final Base64URL iv, 260 final Base64URL cipherText, 261 final Base64URL authTag) 262 throws JOSEException { 263 264 return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header)); 265 } 266 267 268 @Override 269 public byte[] decrypt(final JWEHeader header, 270 final Base64URL encryptedKey, 271 final Base64URL iv, 272 final Base64URL cipherText, 273 final Base64URL authTag, 274 final byte[] aad) 275 throws JOSEException { 276 277 critPolicy.ensureHeaderPasses(header); 278 279 // Get ephemeral EC key 280 ECKey ephemeralKey = (ECKey) header.getEphemeralPublicKey(); 281 282 if (ephemeralKey == null) { 283 throw new JOSEException("Missing ephemeral public EC key \"epk\" JWE header parameter"); 284 } 285 286 ECPublicKey ephemeralPublicKey = ephemeralKey.toECPublicKey(); 287 288 // Curve check 289 if (getPrivateKey() instanceof ECPrivateKey) { 290 ECPrivateKey ecPrivateKey = (ECPrivateKey)getPrivateKey(); 291 if (!ECChecks.isPointOnCurve(ephemeralPublicKey, ecPrivateKey)) { 292 throw new JOSEException("Invalid ephemeral public EC key: Point(s) not on the expected curve"); 293 } 294 } else { 295 if (!ECChecks.isPointOnCurve(ephemeralPublicKey, getCurve().toECParameterSpec())) { 296 throw new JOSEException("Invalid ephemeral public EC key: Point(s) not on the expected curve"); 297 } 298 } 299 300 // Derive 'Z' 301 SecretKey Z = ECDH.deriveSharedSecret( 302 ephemeralPublicKey, 303 privateKey, 304 getJCAContext().getKeyEncryptionProvider()); 305 306 return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag); 307 } 308}