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.OctetKeyPair;
025import com.nimbusds.jose.util.Base64URL;
026import com.nimbusds.jose.util.Pair;
027import net.jcip.annotations.ThreadSafe;
028
029import javax.crypto.SecretKey;
030import java.util.*;
031
032
033/**
034 * Elliptic Curve Diffie-Hellman Multi-recipient decrypter of
035 * {@link com.nimbusds.jose.JWEObjectJSON JWE objects} for curves using EC JWK
036 * Expects a private {@link OctetKeyPair} key with {@code "crv"} X25519.
037 *
038 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a>
039 * for more information.
040 *
041 * <p>Public Key Authenticated Encryption for JOSE
042 * <a href="https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04">ECDH-1PU</a>
043 * for more information.
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_1PU}
051 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A128KW}
052 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A192KW}
053 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A256KW}
054 * </ul>
055 *
056 * <p>Supports the following elliptic curves:
057 *
058 * <ul>
059 *     <li>{@link Curve#X25519}
060 * </ul>
061 *
062 * <p>Supports the following content encryption algorithms for Direct key agreement mode:
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 * <p>Supports the following content encryption algorithms for Key wrapping mode:
077 *
078 * <ul>
079 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
080 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
081 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
082 * </ul>
083 *
084 * @author Alexander Martynov
085 * @version 2021-08-18
086 */
087@ThreadSafe
088public class ECDH1PUX25519DecrypterMulti extends ECDH1PUCryptoProvider implements JWEDecrypterMulti, CriticalHeaderParamsAware {
089
090
091    /**
092     * The supported EC JWK curves by the ECDH crypto provider class.
093     */
094    public static final Set<Curve> SUPPORTED_ELLIPTIC_CURVES;
095
096
097    static {
098        Set<Curve> curves = new LinkedHashSet<>();
099        curves.add(Curve.X25519);
100        SUPPORTED_ELLIPTIC_CURVES = Collections.unmodifiableSet(curves);
101    }
102
103    /**
104     * The critical header policy.
105     */
106    private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
107
108    /**
109     * The public sender JWK key.
110     */
111    private final OctetKeyPair sender;
112
113    /**
114     * The list of private recipient's keys.
115     */
116    private final List<Pair<UnprotectedHeader, OctetKeyPair>>recipients;
117
118    /**
119     * Creates a curve x25519 Elliptic Curve Diffie-Hellman Multi-recipient decrypter.
120     *
121     * @param sender         The sender public JWK key.
122     * @param recipients     The list of private recipient's keys.
123     *
124     * @throws JOSEException If the key subtype is not supported.
125     */
126    public ECDH1PUX25519DecrypterMulti(final OctetKeyPair sender, final List<Pair<UnprotectedHeader, OctetKeyPair>> recipients)
127            throws JOSEException {
128
129        this(sender, recipients, null);
130    }
131
132    /**
133     * Creates a curve x25519 Elliptic Curve Diffie-Hellman Multi-recipient decrypter.
134     *
135     * @param sender         The sender public JWK key.
136     * @param recipients     The list of private recipient's keys.
137     * @param defCritHeaders The names of the critical header parameters
138     *                       that are deferred to the application for
139     *                       processing, empty set or {@code null} if none.
140     *
141     * @throws JOSEException If the key subtype is not supported.
142     */
143    public ECDH1PUX25519DecrypterMulti(
144            final OctetKeyPair sender,
145            final List<Pair<UnprotectedHeader, OctetKeyPair>>recipients,
146            final Set<String> defCritHeaders)
147
148            throws JOSEException {
149
150        super(sender.getCurve());
151
152        this.sender = sender;
153        this.recipients = recipients;
154        critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
155    }
156
157    @Override
158    public Set<Curve> supportedEllipticCurves() {
159
160        return SUPPORTED_ELLIPTIC_CURVES;
161    }
162
163
164    @Override
165    public Set<String> getProcessedCriticalHeaderParams() {
166
167        return critPolicy.getProcessedCriticalHeaderParams();
168    }
169
170
171    @Override
172    public Set<String> getDeferredCriticalHeaderParams() {
173
174        return critPolicy.getProcessedCriticalHeaderParams();
175    }
176
177
178    @Override
179    public byte[] decrypt(final JWEHeader header,
180                          final List<JWERecipient> recipients,
181                          final Base64URL iv,
182                          final Base64URL cipherText,
183                          final Base64URL authTag)
184            throws JOSEException {
185
186        critPolicy.ensureHeaderPasses(header);
187
188        // Get ephemeral key from header
189        OctetKeyPair ephemeralPublicKey = (OctetKeyPair) header.getEphemeralPublicKey();
190
191        if (ephemeralPublicKey == null) {
192            throw new JOSEException("Missing ephemeral public key epk JWE header parameter");
193        }
194
195        List<Pair<UnprotectedHeader, SecretKey>> sharedKeys = new ArrayList<>();
196
197        for (Pair<UnprotectedHeader, OctetKeyPair> recipient : this.recipients) {
198            SecretKey Z = ECDH1PU.deriveRecipientZ(
199                    recipient.getRight(),
200                    sender.toPublicJWK(),
201                    ephemeralPublicKey
202            );
203
204            sharedKeys.add(Pair.of(recipient.getLeft(), Z));
205        }
206
207        return decryptMulti(header, sharedKeys, recipients, iv, cipherText, authTag);
208    }
209}