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.CriticalHeaderParamsAware; 030import com.nimbusds.jose.JOSEException; 031import com.nimbusds.jose.JWEDecrypter; 032import com.nimbusds.jose.JWEHeader; 033import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral; 034import com.nimbusds.jose.crypto.impl.ECDH; 035import com.nimbusds.jose.crypto.impl.ECDHCryptoProvider; 036import com.nimbusds.jose.crypto.utils.ECChecks; 037import com.nimbusds.jose.jwk.Curve; 038import com.nimbusds.jose.jwk.ECKey; 039import com.nimbusds.jose.util.Base64URL; 040 041 042/** 043 * Elliptic Curve Diffie-Hellman decrypter of 044 * {@link com.nimbusds.jose.JWEObject JWE objects} for curves using EC JWK 045 * keys. Expects a private EC key (with a P-256, P-384 or P-521 curve). 046 * 047 * <p>See RFC 7518 048 * <a href="https://tools.ietf.org/html/rfc7518#section-4.6">section 4.6</a> 049 * for more information. 050 * 051 * <p>For Curve25519/X25519, see {@link X25519Decrypter} instead. 052 * 053 * <p>This class is thread-safe. 054 * 055 * <p>Supports the following key management algorithms: 056 * 057 * <ul> 058 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES} 059 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A128KW} 060 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A192KW} 061 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A256KW} 062 * </ul> 063 * 064 * <p>Supports the following elliptic curves: 065 * 066 * <ul> 067 * <li>{@link com.nimbusds.jose.jwk.Curve#P_256} 068 * <li>{@link com.nimbusds.jose.jwk.Curve#P_384} 069 * <li>{@link com.nimbusds.jose.jwk.Curve#P_521} 070 * </ul> 071 * 072 * <p>Supports the following content encryption algorithms: 073 * 074 * <ul> 075 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 076 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 077 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 078 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 079 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 080 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 081 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 082 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 083 * </ul> 084 * 085 * @author Vladimir Dzhuvinov 086 * @version 2018-12-12 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()); 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); 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 @Override 233 public byte[] decrypt(final JWEHeader header, 234 final Base64URL encryptedKey, 235 final Base64URL iv, 236 final Base64URL cipherText, 237 final Base64URL authTag) 238 throws JOSEException { 239 240 critPolicy.ensureHeaderPasses(header); 241 242 // Get ephemeral EC key 243 ECKey ephemeralKey = (ECKey) header.getEphemeralPublicKey(); 244 245 if (ephemeralKey == null) { 246 throw new JOSEException("Missing ephemeral public EC key \"epk\" JWE header parameter"); 247 } 248 249 ECPublicKey ephemeralPublicKey = ephemeralKey.toECPublicKey(); 250 251 // Curve check 252 if (getPrivateKey() instanceof ECPrivateKey) { 253 ECPrivateKey ecPrivateKey = (ECPrivateKey)getPrivateKey(); 254 if (!ECChecks.isPointOnCurve(ephemeralPublicKey, ecPrivateKey)) { 255 throw new JOSEException("Invalid ephemeral public EC key: Point(s) not on the expected curve"); 256 } 257 } else { 258 if (!ECChecks.isPointOnCurve(ephemeralPublicKey, getCurve().toECParameterSpec())) { 259 throw new JOSEException("Invalid ephemeral public EC key: Point(s) not on the expected curve"); 260 } 261 } 262 263 // Derive 'Z' 264 SecretKey Z = ECDH.deriveSharedSecret( 265 ephemeralPublicKey, 266 privateKey, 267 getJCAContext().getKeyEncryptionProvider()); 268 269 return decryptWithZ(header, Z, encryptedKey, iv, cipherText, authTag); 270 } 271}