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