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.jwk.Curve;
027import com.nimbusds.jose.jwk.OctetKeyPair;
028import com.nimbusds.jose.util.Base64URL;
029
030
031/**
032 * Curve25519 Elliptic Curve Diffie-Hellman decrypter of
033 * {@link com.nimbusds.jose.JWEObject JWE objects}.
034 * Expects a private {@link OctetKeyPair} key with {@code "crv"} X25519.
035 *
036 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a>
037 * for more information.
038 *
039 * <p>See also {@link ECDHDecrypter} for ECDH on other curves.
040 *
041 * <p>This class is thread-safe.
042 *
043 * <p>Supports the following key management algorithms:
044 *
045 * <ul>
046 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES}
047 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A128KW}
048 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A192KW}
049 *     <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_ES_A256KW}
050 * </ul>
051 *
052 * <p>Supports the following elliptic curve:
053 *
054 * <ul>
055 *     <li>{@link com.nimbusds.jose.jwk.Curve#X25519} (Curve25519)
056 * </ul>
057 *
058 * <p>Supports the following content encryption algorithms:
059 *
060 * <ul>
061 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256}
062 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384}
063 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512}
064 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM}
065 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM}
066 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM}
067 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
068 *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
069 * </ul>
070 *
071 * @author Tim McLean
072 * @version 2018-07-12
073 */
074public class X25519Decrypter extends ECDHCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
075
076
077        /**
078         * The private key.
079         */
080        private final OctetKeyPair privateKey;
081
082
083        /**
084         * The critical header policy.
085         */
086        private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral();
087
088
089        /**
090         * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
091         *
092         * @param privateKey The private key. Must not be {@code null}.
093         *
094         * @throws JOSEException If the key subtype is not supported.
095         */
096        public X25519Decrypter(final OctetKeyPair privateKey)
097                throws JOSEException {
098
099                this(privateKey, null);
100        }
101
102
103        /**
104         * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter.
105         *
106         * @param privateKey     The private key. Must not be {@code null}.
107         * @param defCritHeaders The names of the critical header parameters
108         *                       that are deferred to the application for
109         *                       processing, empty set or {@code null} if none.
110         *
111         * @throws JOSEException If the key subtype is not supported.
112         */
113        public X25519Decrypter(final OctetKeyPair privateKey, final Set<String> defCritHeaders)
114                throws JOSEException {
115
116                super(privateKey.getCurve());
117
118                if (! Curve.X25519.equals(privateKey.getCurve())) {
119                        throw new JOSEException("X25519Decrypter only supports OctetKeyPairs with crv=X25519");
120                }
121
122                if (! privateKey.isPrivate()) {
123                        throw new JOSEException("The OctetKeyPair doesn't contain a private part");
124                }
125
126                this.privateKey = privateKey;
127
128                critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
129        }
130
131
132        @Override
133        public Set<Curve> supportedEllipticCurves() {
134
135                return Collections.singleton(Curve.X25519);
136        }
137
138
139        /**
140         * Returns the private key.
141         *
142         * @return The private key.
143         */
144        public OctetKeyPair getPrivateKey() {
145
146                return privateKey;
147        }
148
149
150        @Override
151        public Set<String> getProcessedCriticalHeaderParams() {
152
153                return critPolicy.getProcessedCriticalHeaderParams();
154        }
155
156
157        @Override
158        public Set<String> getDeferredCriticalHeaderParams() {
159
160                return critPolicy.getProcessedCriticalHeaderParams();
161        }
162
163
164        @Override
165        public byte[] decrypt(final JWEHeader header,
166                              final Base64URL encryptedKey,
167                              final Base64URL iv,
168                              final Base64URL cipherText,
169                              final Base64URL authTag)
170                throws JOSEException {
171
172                // Check for unrecognizable "crit" properties
173                critPolicy.ensureHeaderPasses(header);
174
175                // Get ephemeral key from header
176                OctetKeyPair ephemeralPublicKey = (OctetKeyPair) header.getEphemeralPublicKey();
177
178                if (ephemeralPublicKey == null) {
179                        throw new JOSEException("Missing ephemeral public key \"epk\" JWE header parameter");
180                }
181
182                if (! privateKey.getCurve().equals(ephemeralPublicKey.getCurve())) {
183                        throw new JOSEException("Curve of ephemeral public key does not match curve of private key");
184                }
185
186                // Derive 'Z'
187                // Note: X25519 does not require public key validation
188                // See https://cr.yp.to/ecdh.html#validate
189                SecretKey Z = ECDH.deriveSharedSecret(ephemeralPublicKey, privateKey);
190
191                return decryptWithZ(header, Z, encryptedKey, iv, cipherText, authTag);
192        }
193}