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