9#include <botan/ecies.h>
11#include <botan/cipher_mode.h>
13#include <botan/numthry.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/pk_ops_impl.h>
16#include <botan/internal/stl_util.h>
29class ECIES_PrivateKey
final :
public EC_PrivateKey,
30 public PK_Key_Agreement_Key {
32 explicit ECIES_PrivateKey(
const ECDH_PrivateKey& private_key) :
33 EC_PublicKey(private_key), EC_PrivateKey(private_key), PK_Key_Agreement_Key(), m_key(private_key) {}
35 std::vector<uint8_t> public_value()
const override {
return m_key.public_value(); }
37 std::string algo_name()
const override {
return "ECIES"; }
39 std::unique_ptr<Public_Key> public_key()
const override {
return m_key.public_key(); }
43 std::unique_ptr<Private_Key> generate_another(RandomNumberGenerator& rng)
const override {
44 return m_key.generate_another(rng);
47 std::unique_ptr<PK_Ops::Key_Agreement> create_key_agreement_op(RandomNumberGenerator& rng,
48 std::string_view params,
49 std::string_view provider)
const override;
52 ECDH_PrivateKey m_key;
60class ECIES_ECDH_KA_Operation
final :
public PK_Ops::Key_Agreement_with_KDF {
62 ECIES_ECDH_KA_Operation(
const ECIES_PrivateKey& private_key, RandomNumberGenerator& rng) :
63 PK_Ops::Key_Agreement_with_KDF(
"Raw"), m_key(private_key), m_rng(rng) {}
65 size_t agreed_value_size()
const override {
return m_key.domain().get_p_bytes(); }
68 const EC_Group& group = m_key.domain();
70 return input_point->mul(m_key._private_key(), m_rng, m_ws).x_bytes();
72 throw Decoding_Error(
"ECIES - Invalid elliptic curve point");
77 ECIES_PrivateKey m_key;
78 RandomNumberGenerator& m_rng;
79 std::vector<BigInt> m_ws;
82std::unique_ptr<PK_Ops::Key_Agreement> ECIES_PrivateKey::create_key_agreement_op(RandomNumberGenerator& rng,
84 std::string_view )
const {
85 return std::make_unique<ECIES_ECDH_KA_Operation>(*
this, rng);
97PK_Key_Agreement create_key_agreement(
const PK_Key_Agreement_Key& private_key,
98 const ECIES_KA_Params& ecies_params,
100 RandomNumberGenerator& rng) {
101 const ECDH_PrivateKey* ecdh_key =
dynamic_cast<const ECDH_PrivateKey*
>(&private_key);
103 if(ecdh_key ==
nullptr &&
104 (ecies_params.cofactor_mode() || ecies_params.old_cofactor_mode() || ecies_params.check_mode())) {
109 throw Invalid_Argument(
"ECIES: cofactor, old cofactor and check mode are only supported for ECDH_PrivateKey");
112 if(ecdh_key && (for_encryption || !ecies_params.cofactor_mode())) {
114 return PK_Key_Agreement(ECIES_PrivateKey(*ecdh_key), rng,
"Raw");
117 return PK_Key_Agreement(private_key, rng,
"Raw");
125 m_ka(create_key_agreement(private_key, ecies_params, for_encryption, rng)), m_params(ecies_params) {}
131 const EC_Point& other_public_key_point)
const {
132 if(other_public_key_point.
is_zero()) {
138 EC_Point other_point = other_public_key_point;
149 derivation_input += eph_public_key_bin;
158 derivation_input.insert(derivation_input.end(), peh.
begin(), peh.
end());
165 std::string_view kdf_spec,
169 m_domain(domain), m_kdf_spec(kdf_spec), m_length(length), m_compression_mode(compression_type), m_flags(flags) {}
172 std::string_view kdf_spec,
173 std::string_view dem_algo_spec,
175 std::string_view mac_spec,
179 ECIES_KA_Params(domain, kdf_spec, dem_key_len + mac_key_len, compression_type, flags),
180 m_dem_spec(dem_algo_spec),
181 m_dem_keylen(dem_key_len),
182 m_mac_spec(mac_spec),
183 m_mac_keylen(mac_key_len) {
186 throw Invalid_Argument(
"ECIES: only one of cofactor_mode, old_cofactor_mode and check_mode can be set");
191 std::string_view kdf_spec,
192 std::string_view dem_algo_spec,
194 std::string_view mac_spec,
195 size_t mac_key_len) :
219 m_ka(private_key, ecies_params, true, rng),
220 m_params(ecies_params),
221 m_eph_public_key_bin(private_key.public_value()),
228 m_eph_public_key_bin = m_params.domain().OS2ECP(m_eph_public_key_bin).encode(ecies_params.compression_type());
240size_t ECIES_Encryptor::maximum_input_size()
const {
248size_t ECIES_Encryptor::ciphertext_length(
size_t ptext_len)
const {
249 return m_eph_public_key_bin.size() + m_mac->output_length() + m_cipher->output_length(ptext_len);
255std::vector<uint8_t> ECIES_Encryptor::enc(
const uint8_t data[],
257 RandomNumberGenerator& )
const {
259 throw Invalid_State(
"ECIES: the other key is zero");
267 if(m_iv.
empty() && !m_cipher->valid_nonce_length(m_iv.
size())) {
268 throw Invalid_Argument(
"ECIES with " + m_cipher->name() +
" requires an IV be set");
271 m_cipher->start(m_iv.
bits_of());
274 m_cipher->finish(encrypted_data);
278 m_mac->update(encrypted_data);
279 if(!m_label.empty()) {
280 m_mac->update(m_label);
282 const auto mac = m_mac->final();
285 return concat(m_eph_public_key_bin, encrypted_data, mac);
291 m_ka(key, ecies_params, false, rng), m_params(ecies_params), m_iv(), m_label() {
294 const BigInt& cofactor = m_params.domain().get_cofactor();
295 if(cofactor > 1 && gcd(cofactor, m_params.domain().get_order()) != 1) {
296 throw Invalid_Argument(
"ECIES: gcd of cofactor and order must be 1 if check_mode is 0");
300 m_mac = m_params.create_mac();
306size_t compute_point_size(
const EC_Group& group, EC_Point_Format format) {
307 const size_t fe_bytes = group.get_p_bytes();
308 if(format == EC_Point_Format::Compressed) {
311 return 1 + 2 * fe_bytes;
317size_t ECIES_Decryptor::plaintext_length(
size_t ctext_len)
const {
318 const size_t point_size = compute_point_size(m_params.domain(), m_params.compression_type());
319 const size_t overhead = point_size + m_mac->output_length();
321 if(ctext_len < overhead) {
325 return m_cipher->output_length(ctext_len - overhead);
331secure_vector<uint8_t> ECIES_Decryptor::do_decrypt(uint8_t& valid_mask,
const uint8_t in[],
size_t in_len)
const {
332 const size_t point_size = compute_point_size(m_params.domain(), m_params.compression_type());
334 if(in_len < point_size + m_mac->output_length()) {
335 throw Decoding_Error(
"ECIES decryption: ciphertext is too short");
339 const std::vector<uint8_t> other_public_key_bin(in, in + point_size);
340 const std::vector<uint8_t> encrypted_data(in + point_size, in + in_len - m_mac->output_length());
341 const std::vector<uint8_t> mac_data(in + in_len - m_mac->output_length(), in + in_len);
344 EC_Point other_public_key = m_params.domain().OS2ECP(other_public_key_bin);
347 if(m_params.check_mode() && !other_public_key.on_the_curve()) {
348 throw Decoding_Error(
"ECIES decryption: received public key is not on the curve");
353 const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key);
356 m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
357 m_mac->update(encrypted_data);
358 if(!m_label.empty()) {
359 m_mac->update(m_label);
361 const secure_vector<uint8_t> calculated_mac = m_mac->final();
362 valid_mask = CT::is_equal(mac_data.data(), calculated_mac.data(), mac_data.size()).value();
367 m_cipher->set_key(
SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
368 if(m_iv.empty() && !m_cipher->valid_nonce_length(m_iv.size())) {
369 throw Invalid_Argument(
"ECIES with " + m_cipher->name() +
" requires an IV be set");
371 m_cipher->start(m_iv.bits_of());
376 secure_vector<uint8_t> decrypted_data(encrypted_data.begin(), encrypted_data.end());
377 m_cipher->finish(decrypted_data);
378 return decrypted_data;
383 return secure_vector<uint8_t>();
static std::unique_ptr< Cipher_Mode > create_or_throw(std::string_view algo, Cipher_Dir direction, std::string_view provider="")
ECIES_Decryptor(const PK_Key_Agreement_Key &private_key, const ECIES_System_Params &ecies_params, RandomNumberGenerator &rng)
ECIES_Encryptor(const PK_Key_Agreement_Key &private_key, const ECIES_System_Params &ecies_params, RandomNumberGenerator &rng)
SymmetricKey derive_secret(const std::vector< uint8_t > &eph_public_key_bin, const EC_Point &other_public_key_point) const
ECIES_KA_Operation(const PK_Key_Agreement_Key &private_key, const ECIES_KA_Params &ecies_params, bool for_encryption, RandomNumberGenerator &rng)
ECIES_KA_Params(const EC_Group &domain, std::string_view kdf_spec, size_t length, EC_Point_Format compression_type, ECIES_Flags flags)
size_t secret_length() const
bool old_cofactor_mode() const
EC_Point_Format compression_type() const
bool cofactor_mode() const
bool single_hash_mode() const
const std::string & kdf_spec() const
const EC_Group & domain() const
size_t dem_keylen() const
returns the length of the key used by the data encryption method
ECIES_System_Params(const EC_Group &domain, std::string_view kdf_spec, std::string_view dem_algo_spec, size_t dem_key_len, std::string_view mac_spec, size_t mac_key_len)
size_t mac_keylen() const
returns the length of the key used by the message authentication code
std::unique_ptr< Cipher_Mode > create_cipher(Cipher_Dir direction) const
creates an instance of the data encryption method
std::unique_ptr< MessageAuthenticationCode > create_mac() const
creates an instance of the message authentication code
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
const BigInt & get_cofactor() const
size_t get_order_bytes() const
std::vector< uint8_t > encode(EC_Point_Format format) const
static std::unique_ptr< KDF > create_or_throw(std::string_view algo_spec, std::string_view provider="")
static std::unique_ptr< MessageAuthenticationCode > create_or_throw(std::string_view algo_spec, std::string_view provider="")
secure_vector< uint8_t > bits_of() const
const uint8_t * end() const
const uint8_t * begin() const
SymmetricKey derive_key(size_t key_len, const uint8_t in[], size_t in_len, const uint8_t params[], size_t params_len) const
int(* final)(unsigned char *, CTX *)
#define BOTAN_DIAGNOSTIC_POP
#define BOTAN_DIAGNOSTIC_PUSH
#define BOTAN_DIAGNOSTIC_IGNORE_INHERITED_VIA_DOMINANCE
constexpr auto concat(Rs &&... ranges)
std::vector< T, secure_allocator< T > > secure_vector