001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2026, 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.crypto.opts.OptionUtils;
024import com.nimbusds.jose.jwk.Curve;
025import com.nimbusds.jose.jwk.ECKey;
026import com.nimbusds.jose.util.Base64URL;
027import net.jcip.annotations.ThreadSafe;
028
029import javax.crypto.SecretKey;
030import java.security.PrivateKey;
031import java.security.interfaces.ECPrivateKey;
032import java.security.interfaces.ECPublicKey;
033import java.util.Collections;
034import java.util.LinkedHashSet;
035import java.util.Set;
036
037
038/**
039 * Elliptic Curve Diffie-Hellman decrypter of
040 * {@link com.nimbusds.jose.JWEObject JWE objects} for curves using an EC JWK.
041 * Expects a private EC key (with a P-256, P-384 or P-521 curve).
042 *
043 * <p>Public Key Authenticated Encryption for JOSE
044 * <a href="https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04">ECDH-1PU</a>
045 * for more information.
046 *
047 * <p>For Curve25519/X25519, see {@link ECDH1PUX25519Decrypter} instead.
048 *
049 * <p>This class is thread-safe.
050 *
051 * <p>Supports the following key management algorithms:
052 *
053 * <ul>
054 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU}
055 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A128KW}
056 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A192KW}
057 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A256KW}
058 * </ul>
059 *
060 * <p>Supports the following elliptic curves:
061 *
062 * <ul>
063 *     <li>{@link Curve#P_256}
064 *     <li>{@link Curve#P_384}
065 *     <li>{@link Curve#P_521}
066 * </ul>
067 *
068 * <p>Supports the following content encryption algorithms for Direct key
069 * agreement mode:
070 *
071 * <ul>
072 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
073 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
074 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
075 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
076 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
077 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
078 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
079 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
080 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P}
081 * </ul>
082 *
083 * <p>Supports the following content encryption algorithms for Key wrapping
084 * mode:
085 *
086 * <ul>
087 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
088 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
089 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
090 * </ul>
091 *
092 * @author Alexander Martynov
093 * @author Egor Puzanov
094 * @version 2026-09-16
095 */
096@ThreadSafe
097public class ECDH1PUDecrypter extends ECDH1PUCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
098
099
100        /**
101         * The supported EC JWK curves by the ECDH crypto provider class.
102         */
103        public static final Set<Curve> SUPPORTED_ELLIPTIC_CURVES;
104
105
106        static {
107                Set<Curve> curves = new LinkedHashSet<>();
108                curves.add(Curve.P_256);
109                curves.add(Curve.P_384);
110                curves.add(Curve.P_521);
111                SUPPORTED_ELLIPTIC_CURVES = Collections.unmodifiableSet(curves);
112        }
113
114
115        /**
116         * The private EC key.
117         */
118        private final ECPrivateKey privateKey;
119
120        /**
121         * The public EC key.
122         */
123        private final ECPublicKey publicKey;
124
125        /**
126         * The critical header policy.
127         */
128        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
129
130
131        /**
132         * The configured options, empty set if none.
133         */
134        private final Set<JWEDecrypterOption> opts;
135
136
137        /**
138         * Creates a new Elliptic Curve Diffie-Hellman decrypter.
139         *
140         * @param privateKey The private EC key. Must not be {@code null}.
141         * @param publicKey  The public EC key. Must not be {@code null}.
142         *
143         * @throws JOSEException If the elliptic curve is not supported.
144         */
145        public ECDH1PUDecrypter(final ECPrivateKey privateKey, final ECPublicKey publicKey)
146                throws JOSEException {
147
148                this(privateKey, publicKey, null, Collections.<JWEDecrypterOption>emptySet());
149        }
150
151        /**
152         * Creates a new Elliptic Curve Diffie-Hellman decrypter.
153         *
154         * @param privateKey     The private EC key. Must not be {@code null}.
155         * @param publicKey      The public EC key. Must not be {@code null}.
156         * @param defCritHeaders The names of the critical header parameters
157         *                       that are deferred to the application for
158         *                       processing, empty set or {@code null} if none.
159         *
160         * @throws JOSEException If the elliptic curve is not supported.
161         */
162        public ECDH1PUDecrypter(final ECPrivateKey privateKey,
163                                final ECPublicKey publicKey,
164                                final Set<String> defCritHeaders)
165                throws JOSEException {
166
167                this(privateKey, publicKey, defCritHeaders, Curve.forECParameterSpec(privateKey.getParams()), Collections.<JWEDecrypterOption>emptySet());
168        }
169
170
171        /**
172         * Creates a new Elliptic Curve Diffie-Hellman decrypter.
173         *
174         * @param privateKey     The private EC key. Must not be {@code null}.
175         * @param publicKey      The public EC key. Must not be {@code null}.
176         * @param defCritHeaders The names of the critical header parameters
177         *                       that are deferred to the application for
178         *                       processing, empty set or {@code null} if none.
179         * @param opts           The decryption options, empty or {@code null}
180         *                       if none.
181         *
182         * @throws JOSEException If the elliptic curve is not supported.
183         */
184        public ECDH1PUDecrypter(final ECPrivateKey privateKey,
185                                final ECPublicKey publicKey,
186                                final Set<String> defCritHeaders,
187                                final Set<JWEDecrypterOption> opts)
188                throws JOSEException {
189
190                this(privateKey, publicKey, defCritHeaders, Curve.forECParameterSpec(privateKey.getParams()), opts);
191        }
192
193
194        /**
195         * Creates a new Elliptic Curve Diffie-Hellman decrypter. This
196         * constructor can also accept a private EC key located in a PKCS#11
197         * store that doesn't expose the private key parameters (such as a
198         * smart card or HSM).
199         *
200         * @param privateKey     The private EC key. Must not be {@code null}.
201         * @param publicKey      The public EC key. Must not be {@code null}.
202         * @param defCritHeaders The names of the critical header parameters
203         *                       that are deferred to the application for
204         *                       processing, empty set or {@code null} if none.
205         * @param curve          The key curve. Must not be {@code null}.
206         *
207         * @throws JOSEException If the elliptic curve is not supported.
208         */
209        public ECDH1PUDecrypter(final ECPrivateKey privateKey,
210                                final ECPublicKey publicKey,
211                                final Set<String> defCritHeaders,
212                                final Curve curve)
213                throws JOSEException {
214
215                this(privateKey, publicKey, defCritHeaders, curve, Collections.<JWEDecrypterOption>emptySet());
216        }
217
218
219        /**
220         * Creates a new Elliptic Curve Diffie-Hellman decrypter. This
221         * constructor can also accept a private EC key located in a PKCS#11
222         * store that doesn't expose the private key parameters (such as a
223         * smart card or HSM).
224         *
225         * @param privateKey     The private EC key. Must not be {@code null}.
226         * @param publicKey      The public EC key. Must not be {@code null}.
227         * @param defCritHeaders The names of the critical header parameters
228         *                       that are deferred to the application for
229         *                       processing, empty set or {@code null} if none.
230         * @param curve          The key curve. Must not be {@code null}.
231         * @param opts           The decryption options, empty or {@code null}
232         *                       if none.
233         *
234         * @throws JOSEException If the elliptic curve is not supported.
235         */
236        public ECDH1PUDecrypter(final ECPrivateKey privateKey,
237                                final ECPublicKey publicKey,
238                                final Set<String> defCritHeaders,
239                                final Curve curve,
240                                final Set<JWEDecrypterOption> opts)
241                throws JOSEException {
242
243                super(curve, null);
244
245                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
246
247                this.privateKey = privateKey;
248                this.publicKey = publicKey;
249                this.opts = opts != null ? opts : Collections.<JWEDecrypterOption>emptySet();
250        }
251
252        /**
253         * Returns the public EC key.
254         *
255         * @return The public EC key.
256         */
257        public ECPublicKey getPublicKey() {
258
259                return publicKey;
260        }
261
262
263        /**
264         * Returns the private EC key.
265         *
266         * @return The private EC key. Casting to
267         * {@link ECPrivateKey} may not be
268         * possible if the key is located in a PKCS#11 store that
269         * doesn't expose the private key parameters.
270         */
271        public PrivateKey getPrivateKey() {
272
273                return privateKey;
274        }
275
276
277        @Override
278        public Set<Curve> supportedEllipticCurves() {
279
280                return SUPPORTED_ELLIPTIC_CURVES;
281        }
282
283
284        @Override
285        public Set<String> getProcessedCriticalHeaderParams() {
286
287                return critPolicy.getProcessedCriticalHeaderParams();
288        }
289
290
291        @Override
292        public Set<String> getDeferredCriticalHeaderParams() {
293
294                return critPolicy.getDeferredCriticalHeaderParams();
295        }
296
297
298        /**
299         * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
300         *
301         * @param header       The JSON Web Encryption (JWE) header. Must
302         *                     specify a supported JWE algorithm and method.
303         *                     Must not be {@code null}.
304         * @param encryptedKey The encrypted key, {@code null} if not required
305         *                     by the JWE algorithm.
306         * @param iv           The initialisation vector, {@code null} if not
307         *                     required by the JWE algorithm.
308         * @param cipherText   The cipher text to decrypt. Must not be
309         *                     {@code null}.
310         * @param authTag      The authentication tag, {@code null} if not
311         *                     required.
312         * @return The clear text.
313         * @throws JOSEException If the JWE algorithm or method is not
314         *                       supported, if a critical header parameter is
315         *                       not supported or marked for deferral to the
316         *                       application, or if decryption failed for some
317         *                       other reason.
318         */
319        @Deprecated
320        public byte[] decrypt(final JWEHeader header,
321                              final Base64URL encryptedKey,
322                              final Base64URL iv,
323                              final Base64URL cipherText,
324                              final Base64URL authTag)
325                throws JOSEException {
326
327                return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
328        }
329
330
331        @Override
332        public byte[] decrypt(final JWEHeader header,
333                              final Base64URL encryptedKey,
334                              final Base64URL iv,
335                              final Base64URL cipherText,
336                              final Base64URL authTag,
337                              final byte[] aad)
338                throws JOSEException {
339
340                critPolicy.ensureHeaderPasses(header);
341
342                // Get ephemeral EC key
343                ECKey ephemeralKey = (ECKey) header.getEphemeralPublicKey();
344
345                if (ephemeralKey == null) {
346                        throw new JOSEException("Missing ephemeral public EC key \"epk\" JWE header parameter");
347                }
348
349                ECPublicKey ephemeralPublicKey = ephemeralKey.toECPublicKey();
350
351                SecretKey Z = ECDH1PU.deriveRecipientZ(
352                        privateKey,
353                        publicKey,
354                        ephemeralPublicKey,
355                        getJCAContext().getKeyEncryptionProvider()
356                );
357
358                int maxDecompressedLength = OptionUtils.resolveMaxDecompressedPlainTextLength(opts);
359
360                return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag, maxDecompressedLength);
361        }
362}