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