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.ECDH1PU;
024import com.nimbusds.jose.crypto.impl.ECDH1PUCryptoProvider;
025import com.nimbusds.jose.jwk.Curve;
026import com.nimbusds.jose.jwk.OctetKeyPair;
027import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator;
028import net.jcip.annotations.ThreadSafe;
029
030import javax.crypto.SecretKey;
031import java.util.Arrays;
032import java.util.Collections;
033import java.util.Set;
034
035
036/**
037 * Elliptic Curve Diffie-Hellman encrypter of
038 * {@link com.nimbusds.jose.JWEObject JWE objects} for curves using an OKP JWK.
039 * Expects a public {@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 ECDH1PUEncrypter} 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 * @version 2023-05-17
094 */
095@ThreadSafe
096public class ECDH1PUX25519Encrypter extends ECDH1PUCryptoProvider implements JWEEncrypter {
097
098
099    /**
100     * The public key.
101     */
102    private final OctetKeyPair publicKey;
103
104    /**
105     * The private key.
106     */
107    private final OctetKeyPair privateKey;
108
109    /**
110     * Creates a new Curve25519 Elliptic Curve Diffie-Hellman encrypter.
111     *
112     * @param privateKey The private key. Must not be {@code null}.
113     * @param publicKey The public key. Must not be {@code null}.
114     *
115     * @throws JOSEException If the key subtype is not supported.
116     */
117    public ECDH1PUX25519Encrypter(final OctetKeyPair privateKey, final OctetKeyPair publicKey)
118            throws JOSEException {
119
120        this(privateKey, publicKey, null);
121    }
122
123    /**
124     * Creates a new Curve25519 Elliptic Curve Diffie-Hellman encrypter.
125     *
126     * @param privateKey The private key. Must not be {@code null}.
127     * @param publicKey The public key. Must not be {@code null}.
128     * @param contentEncryptionKey The content encryption key (CEK) to use.
129     *                             If specified its algorithm must be "AES"
130     *                             and its length must match the expected
131     *                             for the JWE encryption method ("enc").
132     *                             If {@code null} a CEK will be generated
133     *                             for each JWE.
134     *
135     * @throws JOSEException If the key subtype is not supported.
136     */
137    public ECDH1PUX25519Encrypter(final OctetKeyPair privateKey,
138                                  final OctetKeyPair publicKey,
139                                  final SecretKey contentEncryptionKey
140                                  )
141            throws JOSEException {
142
143        super(publicKey.getCurve(), contentEncryptionKey);
144
145        this.publicKey = publicKey;
146        this.privateKey = privateKey;
147    }
148
149    @Override
150    public Set<Curve> supportedEllipticCurves() {
151
152        return Collections.singleton(Curve.X25519);
153    }
154
155
156    /**
157     * Returns the public key.
158     *
159     * @return The public key.
160     */
161    public OctetKeyPair getPublicKey() {
162
163        return publicKey;
164    }
165
166    /**
167     * Returns the private key.
168     *
169     * @return The private key.
170     */
171    public OctetKeyPair getPrivateKey() {
172
173        return privateKey;
174    }
175
176
177    /**
178     * Encrypts the specified clear text of a {@link JWEObject JWE object}.
179     *
180     * @param header    The JSON Web Encryption (JWE) header. Must specify
181     *                  a supported JWE algorithm and method. Must not be
182     *                  {@code null}.
183     * @param clearText The clear text to encrypt. Must not be {@code null}.
184     *
185     * @return The resulting JWE crypto parts.
186     *
187     * @throws JOSEException If the JWE algorithm or method is not
188     *                       supported or if encryption failed for some
189     *                       other internal reason.
190     */
191    @Deprecated
192    public JWECryptoParts encrypt(final JWEHeader header, final byte[] clearText)
193        throws JOSEException {
194
195        return encrypt(header, clearText, AAD.compute(header));
196    }
197
198
199    @Override
200    public JWECryptoParts encrypt(final JWEHeader header, final byte[] clearText, final byte[] aad)
201            throws JOSEException {
202
203        final OctetKeyPair ephemeralPrivateKey = new OctetKeyPairGenerator(getCurve()).generate();
204        final OctetKeyPair ephemeralPublicKey = ephemeralPrivateKey.toPublicJWK();
205
206        // Add the ephemeral public EC key to the header
207        JWEHeader updatedHeader = new JWEHeader.Builder(header).
208                ephemeralPublicKey(ephemeralPublicKey).
209                build();
210
211        SecretKey Z = ECDH1PU.deriveSenderZ(
212                privateKey,
213                publicKey,
214                ephemeralPrivateKey
215        );
216
217        // for JWEObject we need update the AAD as well
218        final byte[] updatedAAD = Arrays.equals(AAD.compute(header), aad) ? AAD.compute(updatedHeader) : aad;
219
220        return encryptWithZ(updatedHeader, Z, clearText, updatedAAD);
221    }
222}