001/*
002 * nimbus-jose-jwt
003 *
004 * Copyright 2012-2018, Connect2id Ltd.
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 java.util.Collections;
022import java.util.Set;
023import javax.crypto.SecretKey;
024
025import com.nimbusds.jose.*;
026import com.nimbusds.jose.crypto.impl.AAD;
027import com.nimbusds.jose.crypto.impl.CriticalHeaderParamsDeferral;
028import com.nimbusds.jose.crypto.impl.ECDH;
029import com.nimbusds.jose.crypto.impl.ECDHCryptoProvider;
030import com.nimbusds.jose.jwk.Curve;
031import com.nimbusds.jose.jwk.OctetKeyPair;
032import com.nimbusds.jose.util.Base64URL;
033
034
035/**
036 * Curve25519 Elliptic Curve Diffie-Hellman decrypter of
037 * {@link com.nimbusds.jose.JWEObject JWE objects}.
038 * Expects a private {@link OctetKeyPair} key with {@code "crv"} X25519.
039 *
040 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a>
041 * for more information.
042 *
043 * <p>See also {@link ECDHDecrypter} for ECDH on other curves.
044 *
045 * <p>This class is thread-safe.
046 *
047 * <p>Supports the following key management algorithms:
048 *
049 * <ul>
050 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES}
051 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A128KW}
052 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A192KW}
053 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A256KW}
054 * </ul>
055 *
056 * <p>Supports the following elliptic curve:
057 *
058 * <ul>
059 *     <li>{@link com.nimbusds.jose.jwk.Curve#X25519} (Curve25519)
060 * </ul>
061 *
062 * <p>Supports the following content encryption algorithms:
063 *
064 * <ul>
065 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
066 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
067 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
068 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
069 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
070 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
071 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
072 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
073 *     <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P}
074 * </ul>
075 *
076 * @author Tim McLean
077 * @author Egor Puzanov
078 * @version 2023-03-26
079 */
080public class X25519Decrypter extends ECDHCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
081
082
083        /**
084         * The private key.
085         */
086        private final OctetKeyPair privateKey;
087
088
089        /**
090         * The critical header policy.
091         */
092        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
093
094
095        /**
096         * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
097         *
098         * @param privateKey The private key. Must not be {@code null}.
099         *
100         * @throws JOSEException If the key subtype is not supported.
101         */
102        public X25519Decrypter(final OctetKeyPair privateKey)
103                throws JOSEException {
104
105                this(privateKey, null);
106        }
107
108
109        /**
110         * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
111         *
112         * @param privateKey     The private key. Must not be {@code null}.
113         * @param defCritHeaders The names of the critical header parameters
114         *                       that are deferred to the application for
115         *                       processing, empty set or {@code null} if none.
116         *
117         * @throws JOSEException If the key subtype is not supported.
118         */
119        public X25519Decrypter(final OctetKeyPair privateKey, final Set<String> defCritHeaders)
120                throws JOSEException {
121
122                super(privateKey.getCurve(), null);
123
124                if (! Curve.X25519.equals(privateKey.getCurve())) {
125                        throw new JOSEException("X25519Decrypter only supports OctetKeyPairs with crv=X25519");
126                }
127
128                if (! privateKey.isPrivate()) {
129                        throw new JOSEException("The OctetKeyPair doesn't contain a private part");
130                }
131
132                this.privateKey = privateKey;
133
134                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
135        }
136
137
138        @Override
139        public Set<Curve> supportedEllipticCurves() {
140
141                return Collections.singleton(Curve.X25519);
142        }
143
144
145        /**
146         * Returns the private key.
147         *
148         * @return The private key.
149         */
150        public OctetKeyPair getPrivateKey() {
151
152                return privateKey;
153        }
154
155
156        @Override
157        public Set<String> getProcessedCriticalHeaderParams() {
158
159                return critPolicy.getProcessedCriticalHeaderParams();
160        }
161
162
163        @Override
164        public Set<String> getDeferredCriticalHeaderParams() {
165
166                return critPolicy.getProcessedCriticalHeaderParams();
167        }
168
169
170        /**
171         * Decrypts the specified cipher text of a {@link JWEObject JWE Object}.
172         *
173         * @param header       The JSON Web Encryption (JWE) header. Must
174         *                     specify a supported JWE algorithm and method.
175         *                     Must not be {@code null}.
176         * @param encryptedKey The encrypted key, {@code null} if not required
177         *                     by the JWE algorithm.
178         * @param iv           The initialisation vector, {@code null} if not
179         *                     required by the JWE algorithm.
180         * @param cipherText   The cipher text to decrypt. Must not be
181         *                     {@code null}.
182         * @param authTag      The authentication tag, {@code null} if not
183         *                     required.
184         *
185         * @return The clear text.
186         *
187         * @throws JOSEException If the JWE algorithm or method is not
188         *                       supported, if a critical header parameter is
189         *                       not supported or marked for deferral to the
190         *                       application, or if decryption failed for some
191         *                       other reason.
192         */
193        @Deprecated
194        public byte[] decrypt(final JWEHeader header,
195                       final Base64URL encryptedKey,
196                       final Base64URL iv,
197                       final Base64URL cipherText,
198                       final Base64URL authTag)
199                throws JOSEException {
200
201                return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header));
202        }
203
204
205        @Override
206        public byte[] decrypt(final JWEHeader header,
207                              final Base64URL encryptedKey,
208                              final Base64URL iv,
209                              final Base64URL cipherText,
210                              final Base64URL authTag,
211                              final byte[] aad)
212                throws JOSEException {
213
214                // Check for unrecognizable "crit" properties
215                critPolicy.ensureHeaderPasses(header);
216
217                // Get ephemeral key from header
218                OctetKeyPair ephemeralPublicKey = (OctetKeyPair) header.getEphemeralPublicKey();
219
220                if (ephemeralPublicKey == null) {
221                        throw new JOSEException("Missing ephemeral public key epk JWE header parameter");
222                }
223
224                if (! privateKey.getCurve().equals(ephemeralPublicKey.getCurve())) {
225                        throw new JOSEException("Curve of ephemeral public key does not match curve of private key");
226                }
227
228                // Derive 'Z'
229                // Note: X25519 does not require public key validation
230                // See https://cr.yp.to/ecdh.html#validate
231                SecretKey Z = ECDH.deriveSharedSecret(ephemeralPublicKey, privateKey);
232
233                return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag);
234        }
235}