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 2023-05-17
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     *
136     * @throws JOSEException If the elliptic curve is not supported.
137     */
138    public ECDH1PUDecrypter(final ECPrivateKey privateKey, final ECPublicKey publicKey)
139        throws JOSEException {
140
141        this(privateKey, publicKey, null);
142    }
143
144    /**
145     * Creates a new Elliptic Curve Diffie-Hellman decrypter.
146     *
147     * @param privateKey     The private EC key. Must not be {@code null}.
148     * @param publicKey      The public EC key. Must not be {@code null}.
149     * @param defCritHeaders The names of the critical header parameters
150     *                       that are deferred to the application for
151     *                       processing, empty set or {@code null} if none.
152     *
153     * @throws JOSEException If the elliptic curve is not supported.
154     */
155    public ECDH1PUDecrypter(final ECPrivateKey privateKey,
156                            final ECPublicKey publicKey,
157                            final Set<String> defCritHeaders)
158        throws JOSEException {
159
160        this(privateKey, publicKey, defCritHeaders, Curve.forECParameterSpec(privateKey.getParams()));
161    }
162
163
164    /**
165     * Creates a new Elliptic Curve Diffie-Hellman decrypter. This
166     * constructor can also accept a private EC key located in a PKCS#11
167     * store that doesn't expose the private key parameters (such as a
168     * smart card or HSM).
169     *
170     * @param privateKey     The private EC key. Must not be {@code null}.
171     * @param publicKey      The public EC key. Must not be {@code null}.
172     * @param defCritHeaders The names of the critical header parameters
173     *                       that are deferred to the application for
174     *                       processing, empty set or {@code null} if none.
175     * @param curve          The key curve. Must not be {@code null}.
176     *
177     * @throws JOSEException If the elliptic curve is not supported.
178     */
179    public ECDH1PUDecrypter(final ECPrivateKey privateKey,
180                            final ECPublicKey publicKey,
181                            final Set<String> defCritHeaders,
182                            final Curve curve)
183        throws JOSEException {
184
185        super(curve, null);
186
187        critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
188
189        this.privateKey = privateKey;
190        this.publicKey = publicKey;
191    }
192
193    /**
194     * Returns the public EC key.
195     *
196     * @return The public EC key.
197     */
198    public ECPublicKey getPublicKey() {
199
200        return publicKey;
201    }
202
203    /**
204     * Returns the private EC key.
205     *
206     * @return The private EC key. Casting to
207     *         {@link ECPrivateKey} may not be
208     *         possible if the key is located in a PKCS#11 store that
209     *         doesn't expose the private key parameters.
210     */
211    public PrivateKey getPrivateKey() {
212
213        return privateKey;
214    }
215
216
217    @Override
218    public Set<Curve> supportedEllipticCurves() {
219
220        return SUPPORTED_ELLIPTIC_CURVES;
221    }
222
223
224    @Override
225    public Set<String> getProcessedCriticalHeaderParams() {
226
227        return critPolicy.getProcessedCriticalHeaderParams();
228    }
229
230
231    @Override
232    public Set<String> getDeferredCriticalHeaderParams() {
233
234        return critPolicy.getProcessedCriticalHeaderParams();
235    }
236
237
238    /**
239     * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
240     *
241     * @param header       The JSON Web Encryption (JWE) header. Must
242     *                     specify a supported JWE algorithm and method.
243     *                     Must not be {@code null}.
244     * @param encryptedKey The encrypted key, {@code null} if not required
245     *                     by the JWE algorithm.
246     * @param iv           The initialisation vector, {@code null} if not
247     *                     required by the JWE algorithm.
248     * @param cipherText   The cipher text to decrypt. Must not be
249     *                     {@code null}.
250     * @param authTag      The authentication tag, {@code null} if not
251     *                     required.
252     *
253     * @return The clear text.
254     *
255     * @throws JOSEException If the JWE algorithm or method is not
256     *                       supported, if a critical header parameter is
257     *                       not supported or marked for deferral to the
258     *                       application, or if decryption failed for some
259     *                       other reason.
260     */
261    @Deprecated
262    public byte[] decrypt(final JWEHeader header,
263               final Base64URL encryptedKey,
264               final Base64URL iv,
265               final Base64URL cipherText,
266               final Base64URL authTag)
267        throws JOSEException {
268
269        return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
270    }
271
272
273    @Override
274    public byte[] decrypt(final JWEHeader header,
275                          final Base64URL encryptedKey,
276                          final Base64URL iv,
277                          final Base64URL cipherText,
278                          final Base64URL authTag,
279                          final byte[] aad)
280        throws JOSEException {
281
282        critPolicy.ensureHeaderPasses(header);
283
284        // Get ephemeral EC key
285        ECKey ephemeralKey = (ECKey) header.getEphemeralPublicKey();
286
287        if (ephemeralKey == null) {
288            throw new JOSEException("Missing ephemeral public EC key \"epk\" JWE header parameter");
289        }
290
291        ECPublicKey ephemeralPublicKey = ephemeralKey.toECPublicKey();
292
293        SecretKey Z = ECDH1PU.deriveRecipientZ(
294                privateKey,
295                publicKey,
296                ephemeralPublicKey,
297                getJCAContext().getKeyEncryptionProvider()
298        );
299
300        return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag);
301    }
302}