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 * @author Vladimir Dzhuvinov 079 * @version 2026-02-19 080 */ 081public class X25519Decrypter extends ECDHCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware { 082 083 084 /** 085 * The private key. 086 */ 087 private final OctetKeyPair privateKey; 088 089 090 /** 091 * The critical header policy. 092 */ 093 private final CriticalHeaderParamsDeferral critPolicy = new CriticalHeaderParamsDeferral(); 094 095 096 /** 097 * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter. 098 * 099 * @param privateKey The private key. Must not be {@code null}. 100 * 101 * @throws JOSEException If the key subtype is not supported. 102 */ 103 public X25519Decrypter(final OctetKeyPair privateKey) 104 throws JOSEException { 105 106 this(privateKey, null); 107 } 108 109 110 /** 111 * Creates a new Curve25519 Elliptic Curve Diffie-Hellman decrypter. 112 * 113 * @param privateKey The private key. Must not be {@code null}. 114 * @param defCritHeaders The names of the critical header parameters 115 * that are deferred to the application for 116 * processing, empty set or {@code null} if none. 117 * 118 * @throws JOSEException If the key subtype is not supported. 119 */ 120 public X25519Decrypter(final OctetKeyPair privateKey, final Set<String> defCritHeaders) 121 throws JOSEException { 122 123 super(privateKey.getCurve(), null); 124 125 if (! Curve.X25519.equals(privateKey.getCurve())) { 126 throw new JOSEException("X25519Decrypter only supports OctetKeyPairs with crv=X25519"); 127 } 128 129 if (! privateKey.isPrivate()) { 130 throw new JOSEException("The OctetKeyPair doesn't contain a private part"); 131 } 132 133 this.privateKey = privateKey; 134 135 critPolicy.setDeferredCriticalHeaderParams(defCritHeaders); 136 } 137 138 139 @Override 140 public Set<Curve> supportedEllipticCurves() { 141 142 return Collections.singleton(Curve.X25519); 143 } 144 145 146 /** 147 * Returns the private key. 148 * 149 * @return The private key. 150 */ 151 public OctetKeyPair getPrivateKey() { 152 153 return privateKey; 154 } 155 156 157 @Override 158 public Set<String> getProcessedCriticalHeaderParams() { 159 160 return critPolicy.getProcessedCriticalHeaderParams(); 161 } 162 163 164 @Override 165 public Set<String> getDeferredCriticalHeaderParams() { 166 167 return critPolicy.getDeferredCriticalHeaderParams(); 168 } 169 170 171 /** 172 * Decrypts the specified cipher text of a {@link JWEObject JWE Object}. 173 * 174 * @param header The JSON Web Encryption (JWE) header. Must 175 * specify a supported JWE algorithm and method. 176 * Must not be {@code null}. 177 * @param encryptedKey The encrypted key, {@code null} if not required 178 * by the JWE algorithm. 179 * @param iv The initialisation vector, {@code null} if not 180 * required by the JWE algorithm. 181 * @param cipherText The cipher text to decrypt. Must not be 182 * {@code null}. 183 * @param authTag The authentication tag, {@code null} if not 184 * required. 185 * 186 * @return The clear text. 187 * 188 * @throws JOSEException If the JWE algorithm or method is not 189 * supported, if a critical header parameter is 190 * not supported or marked for deferral to the 191 * application, or if decryption failed for some 192 * other reason. 193 */ 194 @Deprecated 195 public byte[] decrypt(final JWEHeader header, 196 final Base64URL encryptedKey, 197 final Base64URL iv, 198 final Base64URL cipherText, 199 final Base64URL authTag) 200 throws JOSEException { 201 202 return decrypt(header, encryptedKey, iv, cipherText, authTag, AAD.compute(header)); 203 } 204 205 206 @Override 207 public byte[] decrypt(final JWEHeader header, 208 final Base64URL encryptedKey, 209 final Base64URL iv, 210 final Base64URL cipherText, 211 final Base64URL authTag, 212 final byte[] aad) 213 throws JOSEException { 214 215 // Check for unrecognizable "crit" properties 216 critPolicy.ensureHeaderPasses(header); 217 218 // Get ephemeral key from header 219 OctetKeyPair ephemeralPublicKey = (OctetKeyPair) header.getEphemeralPublicKey(); 220 221 if (ephemeralPublicKey == null) { 222 throw new JOSEException("Missing ephemeral public key epk JWE header parameter"); 223 } 224 225 if (! privateKey.getCurve().equals(ephemeralPublicKey.getCurve())) { 226 throw new JOSEException("Curve of ephemeral public key does not match curve of private key"); 227 } 228 229 // Derive 'Z' 230 // Note: X25519 does not require public key validation 231 // See https://cr.yp.to/ecdh.html#validate 232 SecretKey Z = ECDH.deriveSharedSecret(ephemeralPublicKey, privateKey); 233 234 return decryptWithZ(header, aad, Z, encryptedKey, iv, cipherText, authTag); 235 } 236}