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.JOSEException; 022import com.nimbusds.jose.JWECryptoParts; 023import com.nimbusds.jose.JWEEncrypter; 024import com.nimbusds.jose.JWEHeader; 025import com.nimbusds.jose.crypto.impl.ECDH; 026import com.nimbusds.jose.crypto.impl.ECDH1PU; 027import com.nimbusds.jose.crypto.impl.ECDH1PUCryptoProvider; 028import com.nimbusds.jose.jwk.Curve; 029import com.nimbusds.jose.jwk.OctetKeyPair; 030import com.nimbusds.jose.jwk.gen.OctetKeyPairGenerator; 031import net.jcip.annotations.ThreadSafe; 032 033import javax.crypto.SecretKey; 034import java.util.Collections; 035import java.util.Set; 036 037 038/** 039 * Elliptic Curve Diffie-Hellman encrypter of 040 * {@link com.nimbusds.jose.JWEObject JWE objects} for curves using an OKP JWK. 041 * Expects a public {@link OctetKeyPair} key with {@code "crv"} X25519. 042 * 043 * <p>See <a href="https://tools.ietf.org/html/rfc8037">RFC 8037</a> 044 * for more information. 045 * 046 * <p>See also {@link ECDH1PUEncrypter} for ECDH on other curves. 047 * 048 * <p>Public Key Authenticated Encryption for JOSE 049 * <a href="https://datatracker.ietf.org/doc/html/draft-madden-jose-ecdh-1pu-04">ECDH-1PU</a> 050 * for more information. 051 * 052 * <p>This class is thread-safe. 053 * 054 * <p>Supports the following key management algorithms: 055 * 056 * <ul> 057 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU} 058 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A128KW} 059 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A192KW} 060 * <li>{@link com.nimbusds.jose.JWEAlgorithm#ECDH_1PU_A256KW} 061 * </ul> 062 * 063 * <p>Supports the following elliptic curves: 064 * 065 * <ul> 066 * <li>{@link Curve#X25519} 067 * </ul> 068 * 069 * <p>Supports the following content encryption algorithms for Direct key 070 * agreement mode: 071 * 072 * <ul> 073 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 074 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 075 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 076 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128GCM} 077 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192GCM} 078 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256GCM} 079 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED} 080 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED} 081 * <li>{@link com.nimbusds.jose.EncryptionMethod#XC20P} 082 * </ul> 083 * 084 * <p>Supports the following content encryption algorithms for Key wrapping 085 * mode: 086 * 087 * <ul> 088 * <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256} 089 * <li>{@link com.nimbusds.jose.EncryptionMethod#A192CBC_HS384} 090 * <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512} 091 * </ul> 092 * 093 * @author Alexander Martynov 094 * @version 2021-08-03 095 */ 096@ThreadSafe 097public class ECDH1PUX25519Encrypter extends ECDH1PUCryptoProvider implements JWEEncrypter { 098 099 100 /** 101 * The public key. 102 */ 103 private final OctetKeyPair publicKey; 104 105 /** 106 * The private key. 107 */ 108 private final OctetKeyPair privateKey; 109 110 /** 111 * The externally supplied AES content encryption key (CEK) to use, 112 * {@code null} to generate a CEK for each JWE. 113 */ 114 private final SecretKey contentEncryptionKey; 115 116 /** 117 * Creates a new Curve25519 Elliptic Curve Diffie-Hellman encrypter. 118 * 119 * @param privateKey The private key. Must not be {@code null}. 120 * @param publicKey The public key. Must not be {@code null}. 121 * 122 * @throws JOSEException If the key subtype is not supported. 123 */ 124 public ECDH1PUX25519Encrypter(final OctetKeyPair privateKey, final OctetKeyPair publicKey) 125 throws JOSEException { 126 127 this(privateKey, publicKey, null); 128 } 129 130 /** 131 * Creates a new Curve25519 Elliptic Curve Diffie-Hellman encrypter. 132 * 133 * @param privateKey The private key. Must not be {@code null}. 134 * @param publicKey The public key. Must not be {@code null}. 135 * @param contentEncryptionKey The content encryption key (CEK) to use. 136 * If specified its algorithm must be "AES" 137 * and its length must match the expected 138 * for the JWE encryption method ("enc"). 139 * If {@code null} a CEK will be generated 140 * for each JWE. 141 * 142 * @throws JOSEException If the key subtype is not supported. 143 */ 144 public ECDH1PUX25519Encrypter(final OctetKeyPair privateKey, 145 final OctetKeyPair publicKey, 146 final SecretKey contentEncryptionKey 147 ) 148 throws JOSEException { 149 150 super(publicKey.getCurve()); 151 152 this.publicKey = publicKey; 153 this.privateKey = privateKey; 154 155 if (contentEncryptionKey != null && (contentEncryptionKey.getAlgorithm() == null || !contentEncryptionKey.getAlgorithm().equals("AES"))) 156 throw new IllegalArgumentException("The algorithm of the content encryption key (CEK) must be AES"); 157 158 this.contentEncryptionKey = contentEncryptionKey; 159 } 160 161 @Override 162 public Set<Curve> supportedEllipticCurves() { 163 164 return Collections.singleton(Curve.X25519); 165 } 166 167 168 /** 169 * Returns the public key. 170 * 171 * @return The public key. 172 */ 173 public OctetKeyPair getPublicKey() { 174 175 return publicKey; 176 } 177 178 /** 179 * Returns the private key. 180 * 181 * @return The private key. 182 */ 183 public OctetKeyPair getPrivateKey() { 184 185 return privateKey; 186 } 187 188 @Override 189 public JWECryptoParts encrypt(final JWEHeader header, final byte[] clearText) 190 throws JOSEException { 191 192 ECDH1PU.validateSameCurve(privateKey, publicKey); 193 194 final OctetKeyPair ephemeralPrivateKey = new OctetKeyPairGenerator(getCurve()).generate(); 195 final OctetKeyPair ephemeralPublicKey = ephemeralPrivateKey.toPublicJWK(); 196 197 // Add the ephemeral public EC key to the header 198 JWEHeader updatedHeader = new JWEHeader.Builder(header). 199 ephemeralPublicKey(ephemeralPublicKey). 200 build(); 201 202 SecretKey Ze = ECDH.deriveSharedSecret( 203 publicKey, 204 ephemeralPrivateKey); 205 206 SecretKey Zs = ECDH.deriveSharedSecret( 207 publicKey, 208 privateKey); 209 210 SecretKey Z = ECDH1PU.deriveZ(Ze, Zs); 211 212 return encryptWithZ(updatedHeader, Z, clearText, contentEncryptionKey); 213 } 214}