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 net.jcip.annotations.ThreadSafe;
027
028import javax.crypto.SecretKey;
029import java.security.PrivateKey;
030import java.security.interfaces.ECPrivateKey;
031import java.security.interfaces.ECPublicKey;
032import java.util.Collections;
033import java.util.LinkedHashSet;
034import java.util.Set;
035
036
037/**
038 * Elliptic Curve Diffie-Hellman decrypter of
039 * {@link com.nimbusds.jose.JWEObject JWE objects} for curves using an EC JWK.
040 * Expects a private EC key (with a P-256, P-384 or P-521 curve).
041 *
042 * <p>Public Key Authenticated Encryption for JOSE
043 * <a href="https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04">ECDH-1PU</a>
044 * for more information.
045 *
046 * <p>For Curve25519/X25519, see {@link ECDH1PUX25519Decrypter} instead.
047 *
048 * <p>This class is thread-safe.
049 *
050 * <p>Supports the following key management algorithms:
051 *
052 * <ul>
053 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU}
054 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A128KW}
055 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A192KW}
056 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A256KW}
057 * </ul>
058 *
059 * <p>Supports the following elliptic curves:
060 *
061 * <ul>
062 *     <li>{@link Curve#P_256}
063 *     <li>{@link Curve#P_384}
064 *     <li>{@link Curve#P_521}
065 * </ul>
066 *
067 * <p>Supports the following content encryption algorithms for Direct key
068 * agreement mode:
069 *
070 * <ul>
071 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
072 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
073 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
074 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
075 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
076 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
077 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
078 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
079 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P}
080 * </ul>
081 *
082 * <p>Supports the following content encryption algorithms for Key wrapping
083 * mode:
084 *
085 * <ul>
086 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
087 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
088 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
089 * </ul>
090 *
091 * @author Alexander Martynov
092 * @author Egor Puzanov
093 * @version 2026-02-19
094 */
095@ThreadSafe
096public class ECDH1PUDecrypter extends ECDH1PUCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
097
098
099        /**
100         * The supported EC JWK curves by the ECDH crypto provider class.
101         */
102        public static final Set<Curve> SUPPORTED_ELLIPTIC_CURVES;
103
104
105        static {
106                Set<Curve> curves = new LinkedHashSet<>();
107                curves.add(Curve.P_256);
108                curves.add(Curve.P_384);
109                curves.add(Curve.P_521);
110                SUPPORTED_ELLIPTIC_CURVES = Collections.unmodifiableSet(curves);
111        }
112
113
114        /**
115         * The private EC key.
116         */
117        private final ECPrivateKey privateKey;
118
119        /**
120         * The public EC key.
121         */
122        private final ECPublicKey publicKey;
123
124        /**
125         * The critical header policy.
126         */
127        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
128
129
130        /**
131         * Creates a new Elliptic Curve Diffie-Hellman decrypter.
132         *
133         * @param privateKey The private EC key. Must not be {@code null}.
134         * @param publicKey  The public EC key. Must not be {@code null}.
135         * @throws JOSEException If the elliptic curve is not supported.
136         */
137        public ECDH1PUDecrypter(final ECPrivateKey privateKey, final ECPublicKey publicKey)
138                throws JOSEException {
139
140                this(privateKey, publicKey, null);
141        }
142
143        /**
144         * Creates a new Elliptic Curve Diffie-Hellman decrypter.
145         *
146         * @param privateKey     The private EC key. Must not be {@code null}.
147         * @param publicKey      The public EC key. Must not be {@code null}.
148         * @param defCritHeaders The names of the critical header parameters
149         *                       that are deferred to the application for
150         *                       processing, empty set or {@code null} if none.
151         * @throws JOSEException If the elliptic curve is not supported.
152         */
153        public ECDH1PUDecrypter(final ECPrivateKey privateKey,
154                                final ECPublicKey publicKey,
155                                final Set<String> defCritHeaders)
156                throws JOSEException {
157
158                this(privateKey, publicKey, defCritHeaders, Curve.forECParameterSpec(privateKey.getParams()));
159        }
160
161
162        /**
163         * Creates a new Elliptic Curve Diffie-Hellman decrypter. This
164         * constructor can also accept a private EC key located in a PKCS#11
165         * store that doesn't expose the private key parameters (such as a
166         * smart card or HSM).
167         *
168         * @param privateKey     The private EC key. Must not be {@code null}.
169         * @param publicKey      The public EC key. Must not be {@code null}.
170         * @param defCritHeaders The names of the critical header parameters
171         *                       that are deferred to the application for
172         *                       processing, empty set or {@code null} if none.
173         * @param curve          The key curve. Must not be {@code null}.
174         * @throws JOSEException If the elliptic curve is not supported.
175         */
176        public ECDH1PUDecrypter(final ECPrivateKey privateKey,
177                                final ECPublicKey publicKey,
178                                final Set<String> defCritHeaders,
179                                final Curve curve)
180                throws JOSEException {
181
182                super(curve, null);
183
184                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
185
186                this.privateKey = privateKey;
187                this.publicKey = publicKey;
188        }
189
190        /**
191         * Returns the public EC key.
192         *
193         * @return The public EC key.
194         */
195        public ECPublicKey getPublicKey() {
196
197                return publicKey;
198        }
199
200        /**
201         * Returns the private EC key.
202         *
203         * @return The private EC key. Casting to
204         * {@link ECPrivateKey} may not be
205         * possible if the key is located in a PKCS#11 store that
206         * doesn't expose the private key parameters.
207         */
208        public PrivateKey getPrivateKey() {
209
210                return privateKey;
211        }
212
213
214        @Override
215        public Set<Curve> supportedEllipticCurves() {
216
217                return SUPPORTED_ELLIPTIC_CURVES;
218        }
219
220
221        @Override
222        public Set<String> getProcessedCriticalHeaderParams() {
223
224                return critPolicy.getProcessedCriticalHeaderParams();
225        }
226
227
228        @Override
229        public Set<String> getDeferredCriticalHeaderParams() {
230
231                return critPolicy.getDeferredCriticalHeaderParams();
232        }
233
234
235        /**
236         * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
237         *
238         * @param header       The JSON Web Encryption (JWE) header. Must
239         *                     specify a supported JWE algorithm and method.
240         *                     Must not be {@code null}.
241         * @param encryptedKey The encrypted key, {@code null} if not required
242         *                     by the JWE algorithm.
243         * @param iv           The initialisation vector, {@code null} if not
244         *                     required by the JWE algorithm.
245         * @param cipherText   The cipher text to decrypt. Must not be
246         *                     {@code null}.
247         * @param authTag      The authentication tag, {@code null} if not
248         *                     required.
249         * @return The clear text.
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                SecretKey Z = ECDH1PU.deriveRecipientZ(
289                        privateKey,
290                        publicKey,
291                        ephemeralPublicKey,
292                        getJCAContext().getKeyEncryptionProvider()
293                );
294
295                return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag);
296        }
297}