001/* 002 * nimbus-jose-jwt 003 * 004 * Copyright 2012-2021, Connect2id Ltd and contributors. 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 com.nimbusds.jose.*; 022import com.nimbusds.jose.crypto.impl.*; 023import com.nimbusds.jose.jwk.Curve; 024import com.nimbusds.jose.jwk.ECKey; 025import com.nimbusds.jose.util.Base64URL; 026import com.nimbusds.jose.util.Pair; 027import net.jcip.annotations.ThreadSafe; 028 029import javax.crypto.SecretKey; 030import java.util.*; 031 032 033/** 034 * Elliptic Curve Diffie-Hellman Multi-recipient decrypter of 035 * {@link com.nimbusds.jose.JWEObjectJSON JWE objects} for curves using EC JWK 036 * keys. Expects a private EC key (with a P-256, P-384 or P-521 curve). 037 * 038 * <p>Public Key Authenticated Encryption for JOSE 039 * <a href="https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04">ECDH-1PU</a> 040 * for more information. 041 * 042 * <p>For Single decryption, see {@link ECDH1PUDecrypter} instead. 043 * 044 * <p>This class is thread-safe. 045 * 046 * <p>Supports the following key management algorithms: 047 * 048 * <ul> 049 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU} 050 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A128KW} 051 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A192KW} 052 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A256KW} 053 * </ul> 054 * 055 * <p>Supports the following elliptic curves: 056 * 057 * <ul> 058 * <li>{@link Curve#P_256} 059 * <li>{@link Curve#P_384} 060 * <li>{@link Curve#P_521} 061 * </ul> 062 * 063 * <p>Supports the following content encryption algorithms for Direct key agreement mode: 064 * 065 * <ul> 066 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 067 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 068 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 069 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 070 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 071 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 072 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 073 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 074 * <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P} 075 * </ul> 076 * 077 * <p>Supports the following content encryption algorithms for Key wrapping mode: 078 * 079 * <ul> 080 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 081 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 082 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 083 * </ul> 084 * 085 * @author Alexander Martynov 086 * @version 2021-08-03 087 */ 088@ThreadSafe 089public class ECDH1PUDecrypterMulti extends ECDH1PUCryptoProvider implements JWEDecrypterMulti, CriticalHeaderParamsAware { 090 091 092 /** 093 * The supported EC JWK curves by the ECDH crypto provider class. 094 */ 095 public static final Set<Curve> SUPPORTED_ELLIPTIC_CURVES; 096 097 098 static { 099 Set<Curve> curves = new LinkedHashSet<>(); 100 curves.add(Curve.P_256); 101 curves.add(Curve.P_384); 102 curves.add(Curve.P_521); 103 SUPPORTED_ELLIPTIC_CURVES = Collections.unmodifiableSet(curves); 104 } 105 106 /** 107 * The critical header policy. 108 */ 109 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 110 111 /** 112 * The public sender JWK key. 113 */ 114 private final ECKey sender; 115 116 /** 117 * The list of private recipient's keys. 118 */ 119 private final List<Pair<UnprotectedHeader, ECKey>> recipients; 120 121 /** 122 * Creates Elliptic Curve Diffie-Hellman Multi-recipient decrypter. 123 * 124 * @param sender The public sender JWK key. 125 * @param recipients The list of private recipient's keys. 126 * 127 * @throws JOSEException If the key subtype is not supported. 128 */ 129 public ECDH1PUDecrypterMulti(final ECKey sender, final List<Pair<UnprotectedHeader, ECKey>>recipients) 130 throws JOSEException { 131 132 this(sender, recipients, null); 133 } 134 135 /** 136 * Creates Elliptic Curve Diffie-Hellman Multi-recipient decrypter. 137 * 138 * @param sender The public sender JWK key. 139 * @param recipients The list of private recipient's keys. 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 * @throws JOSEException If the key subtype is not supported. 145 */ 146 public ECDH1PUDecrypterMulti( 147 final ECKey sender, 148 final List<Pair<UnprotectedHeader, ECKey>>recipients, 149 final Set<String> defCritHeaders) 150 151 throws JOSEException { 152 153 super(sender.getCurve()); 154 155 this.sender = sender; 156 this.recipients = recipients; 157 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 158 } 159 160 @Override 161 public Set<Curve> supportedEllipticCurves() { 162 163 return SUPPORTED_ELLIPTIC_CURVES; 164 } 165 166 167 @Override 168 public Set<String> getProcessedCriticalHeaderParams() { 169 170 return critPolicy.getProcessedCriticalHeaderParams(); 171 } 172 173 174 @Override 175 public Set<String> getDeferredCriticalHeaderParams() { 176 177 return critPolicy.getProcessedCriticalHeaderParams(); 178 } 179 180 181 @Override 182 public byte[] decrypt(final JWEHeader header, 183 final List<JWERecipient> recipients, 184 final Base64URL iv, 185 final Base64URL cipherText, 186 final Base64URL authTag) 187 throws JOSEException { 188 189 critPolicy.ensureHeaderPasses(header); 190 191 // Get ephemeral EC key 192 ECKey ephemeralKey = (ECKey) header.getEphemeralPublicKey(); 193 194 if (ephemeralKey == null) { 195 throw new JOSEException("Missing ephemeral public EC key \"epk\" JWE header parameter"); 196 } 197 198 List<Pair<UnprotectedHeader, SecretKey>> sharedKeys = new ArrayList<>(); 199 200 for (Pair<UnprotectedHeader, ECKey> recipient : this.recipients) { 201 SecretKey Z = ECDH1PU.deriveRecipientZ( 202 recipient.getRight().toECPrivateKey(), 203 sender.toECPublicKey(), 204 ephemeralKey.toECPublicKey(), 205 getJCAContext().getKeyEncryptionProvider() 206 ); 207 208 sharedKeys.add(Pair.of(recipient.getLeft(), Z)); 209 } 210 211 return decryptMulti(header, sharedKeys, recipients, iv, cipherText, authTag); 212 } 213}