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}