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.AAD;
023import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral;
024import com.nimbusds.jose.crypto.impl.ECDH1PU;
025import com.nimbusds.jose.crypto.impl.ECDH1PUCryptoProvider;
026import com.nimbusds.jose.crypto.opts.OptionUtils;
027import com.nimbusds.jose.jwk.Curve;
028import com.nimbusds.jose.jwk.OctetKeyPair;
029import com.nimbusds.jose.util.Base64URL;
030import net.jcip.annotations.ThreadSafe;
031
032import javax.crypto.SecretKey;
033import java.util.Collections;
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 OKP JWK.
040 * Expects a private {@link OctetKeyPair} key with {@code "crv"} X25519.
041 *
042 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a>
043 * for more information.
044 *
045 * <p>See also {@link ECDH1PUDecrypter} for ECDH on other curves.
046 *
047 * <p>Public Key Authenticated Encryption for JOSE
048 * <a href="https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04">ECDH-1PU</a>
049 * for more information.
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_1PU}
057 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A128KW}
058 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A192KW}
059 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A256KW}
060 * </ul>
061 *
062 * <p>Supports the following elliptic curves:
063 *
064 * <ul>
065 *     <li>{@link Curve#X25519}
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 * @author Vladimir Dzhuvinov
095 * @version 2026-09-16
096 */
097@ThreadSafe
098public class ECDH1PUX25519Decrypter extends ECDH1PUCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
099
100
101    /**
102     * The private key.
103     */
104    private final OctetKeyPair privateKey;
105
106    /**
107     * The public key.
108     */
109    private final OctetKeyPair publicKey;
110
111    /**
112     * The critical header policy.
113     */
114    private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
115
116
117    /**
118     * The configured options, empty set if none.
119     */
120    private final Set<JWEDecrypterOption> opts;
121
122
123    /**
124     * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
125     *
126     * @param privateKey The private key. Must not be {@code null}.
127     * @param publicKey  The private key. Must not be {@code null}.
128     *
129     * @throws JOSEException If the key subtype is not supported.
130     */
131    public ECDH1PUX25519Decrypter(final OctetKeyPair privateKey, final OctetKeyPair publicKey)
132            throws JOSEException {
133
134        this(privateKey, publicKey, null, Collections.<JWEDecrypterOption>emptySet());
135    }
136
137
138    /**
139     * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
140     *
141     * @param privateKey     The private key. Must not be {@code null}.
142     * @param publicKey      The private key. Must not be {@code null}.
143     * @param defCritHeaders The names of the critical header parameters
144     *                       that are deferred to the application for
145     *                       processing, empty set or {@code null} if none.
146     *
147     * @throws JOSEException If the key subtype is not supported.
148     */
149    public ECDH1PUX25519Decrypter(final OctetKeyPair privateKey,
150                                  final OctetKeyPair publicKey,
151                                  final Set<String> defCritHeaders)
152            throws JOSEException {
153
154        this(privateKey, publicKey, defCritHeaders, Collections.<JWEDecrypterOption>emptySet());
155    }
156
157
158    /**
159     * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
160     *
161     * @param privateKey     The private key. Must not be {@code null}.
162     * @param publicKey      The private key. Must not be {@code null}.
163     * @param defCritHeaders The names of the critical header parameters
164     *                       that are deferred to the application for
165     *                       processing, empty set or {@code null} if none.
166     * @param opts           The decryption options, empty or {@code null}
167     *                       if none.
168     *
169     * @throws JOSEException If the key subtype is not supported.
170     */
171    public ECDH1PUX25519Decrypter(final OctetKeyPair privateKey,
172                                  final OctetKeyPair publicKey,
173                                  final Set<String> defCritHeaders,
174                                  final Set<JWEDecrypterOption> opts)
175            throws JOSEException {
176
177        super(privateKey.getCurve(), null);
178
179        this.privateKey = privateKey;
180        this.publicKey = publicKey;
181        this.opts = opts != null ? opts : Collections.<JWEDecrypterOption>emptySet();
182
183        critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
184    }
185
186
187    @Override
188    public Set<Curve> supportedEllipticCurves() {
189
190        return Collections.singleton(Curve.X25519);
191    }
192
193
194    /**
195     * Returns the private key.
196     *
197     * @return The private key.
198     */
199    public OctetKeyPair getPrivateKey() {
200
201        return privateKey;
202    }
203
204    /**
205     * Returns the public key.
206     *
207     * @return The public key.
208     */
209    public OctetKeyPair getPublicKey() {
210
211        return publicKey;
212    }
213
214    @Override
215    public Set<String> getProcessedCriticalHeaderParams() {
216
217        return critPolicy.getProcessedCriticalHeaderParams();
218    }
219
220
221    @Override
222    public Set<String> getDeferredCriticalHeaderParams() {
223
224        return critPolicy.getDeferredCriticalHeaderParams();
225    }
226
227
228    /**
229     * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
230     *
231     * @param header       The JSON Web Encryption (JWE) header. Must
232     *                     specify a supported JWE algorithm and method.
233     *                     Must not be {@code null}.
234     * @param encryptedKey The encrypted key, {@code null} if not required
235     *                     by the JWE algorithm.
236     * @param iv           The initialisation vector, {@code null} if not
237     *                     required by the JWE algorithm.
238     * @param cipherText   The cipher text to decrypt. Must not be
239     *                     {@code null}.
240     * @param authTag      The authentication tag, {@code null} if not
241     *                     required.
242     *
243     * @return The clear text.
244     *
245     * @throws JOSEException If the JWE algorithm or method is not
246     *                       supported, if a critical header parameter is
247     *                       not supported or marked for deferral to the
248     *                       application, or if decryption failed for some
249     *                       other reason.
250     */
251    @Deprecated
252    public byte[] decrypt(final JWEHeader header,
253               final Base64URL encryptedKey,
254               final Base64URL iv,
255               final Base64URL cipherText,
256               final Base64URL authTag)
257        throws JOSEException {
258
259        return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
260    }
261
262
263    @Override
264    public byte[] decrypt(final JWEHeader header,
265                          final Base64URL encryptedKey,
266                          final Base64URL iv,
267                          final Base64URL cipherText,
268                          final Base64URL authTag,
269                          final byte[] aad)
270            throws JOSEException {
271
272        // Check for unrecognizable "crit" properties
273        critPolicy.ensureHeaderPasses(header);
274
275        // Get ephemeral key from header
276        OctetKeyPair ephemeralPublicKey = (OctetKeyPair) header.getEphemeralPublicKey();
277
278        if (ephemeralPublicKey == null) {
279            throw new JOSEException("Missing ephemeral public key \"epk\" JWE header parameter");
280        }
281
282        SecretKey Z = ECDH1PU.deriveRecipientZ(
283                privateKey,
284                publicKey,
285                ephemeralPublicKey
286        );
287
288        int maxDecompressedLength = OptionUtils.resolveMaxDecompressedPlainTextLength(opts);
289
290        return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag, maxDecompressedLength);
291    }
292}