10#include <botan/ecies.h>
12#include <botan/cipher_mode.h>
13#include <botan/ecdh.h>
17#include <botan/internal/ct_utils.h>
18#include <botan/internal/pk_ops_impl.h>
36 explicit ECIES_PrivateKey(
const ECDH_PrivateKey& private_key) :
38 EC_PublicKey(private_key), EC_PrivateKey(private_key), PK_Key_Agreement_Key(), m_key(private_key) {}
40 std::vector<uint8_t> public_value()
const override {
return m_key.public_value(); }
42 std::string algo_name()
const override {
return "ECIES"; }
44 std::unique_ptr<Public_Key> public_key()
const override {
return m_key.public_key(); }
48 std::unique_ptr<Private_Key> generate_another(RandomNumberGenerator& rng)
const override {
49 return m_key.generate_another(rng);
52 std::unique_ptr<PK_Ops::Key_Agreement> create_key_agreement_op(RandomNumberGenerator& rng,
53 std::string_view params,
54 std::string_view provider)
const override;
57 ECDH_PrivateKey m_key;
69 ECIES_ECDH_KA_Operation(
const ECIES_PrivateKey& private_key, RandomNumberGenerator& rng) :
70 PK_Ops::Key_Agreement_with_KDF(
"Raw"), m_key(private_key), m_rng(rng) {}
72 size_t agreed_value_size()
const override {
return m_key.domain().get_p_bytes(); }
75 const EC_Group& group = m_key.domain();
77 return input_point->mul(m_key._private_key(), m_rng).x_bytes();
79 throw Decoding_Error(
"ECIES - Invalid elliptic curve point");
84 ECIES_PrivateKey m_key;
85 RandomNumberGenerator& m_rng;
88std::unique_ptr<PK_Ops::Key_Agreement> ECIES_PrivateKey::create_key_agreement_op(
RandomNumberGenerator& rng,
90 std::string_view )
const {
91 return std::make_unique<ECIES_ECDH_KA_Operation>(*
this, rng);
105PK_Key_Agreement create_key_agreement(
const PK_Key_Agreement_Key& private_key,
106 const ECIES_KA_Params& ecies_params,
108 RandomNumberGenerator& rng) {
109 const ECDH_PrivateKey* ecdh_key =
dynamic_cast<const ECDH_PrivateKey*
>(&private_key);
111 if(ecdh_key ==
nullptr &&
112 (ecies_params.cofactor_mode() || ecies_params.old_cofactor_mode() || ecies_params.check_mode())) {
117 throw Invalid_Argument(
"ECIES: cofactor, old cofactor and check mode are only supported for ECDH_PrivateKey");
120 if(ecdh_key !=
nullptr && (for_encryption || !ecies_params.cofactor_mode())) {
122 return PK_Key_Agreement(ECIES_PrivateKey(*ecdh_key), rng,
"Raw");
125 return PK_Key_Agreement(private_key, rng,
"Raw");
133 m_ka(create_key_agreement(private_key, ecies_params, for_encryption, rng)), m_params(ecies_params) {}
135#if defined(BOTAN_HAS_LEGACY_EC_POINT)
140 const EC_Point& other_public_key_point)
const {
141 if(other_public_key_point.
is_zero()) {
147 EC_Point other_point = other_public_key_point;
158 if(!m_params.single_hash_mode()) {
159 derivation_input += eph_public_key_bin;
163 std::vector<uint8_t> other_public_key_bin = other_point.
encode(m_params.point_format());
167 m_ka.derive_key(m_params.group().get_order_bytes(), other_public_key_bin.data(), other_public_key_bin.size());
168 derivation_input.insert(derivation_input.end(), peh.begin(), peh.end());
171 return SymmetricKey(kdf->derive_key(m_params.secret_length(), derivation_input));
184 auto other_point = other_public_key_point;
186 const auto& group = m_params.group();
190 if(m_params.old_cofactor_mode() && group.has_cofactor()) {
193 other_point = other_point.mul(cofactor, null_rng);
199 if(!m_params.single_hash_mode()) {
200 derivation_input.assign(eph_public_key_bin.begin(), eph_public_key_bin.end());
204 std::vector<uint8_t> other_public_key_bin = other_point.serialize(m_params.point_format());
208 m_ka.derive_key(m_params.group().get_order_bytes(), other_public_key_bin.data(), other_public_key_bin.size());
209 derivation_input.insert(derivation_input.end(), peh.
begin(), peh.
end());
212 return SymmetricKey(kdf->derive_key(m_params.secret_length(), derivation_input));
234 m_cofactor_mode(false),
235 m_old_cofactor_mode(false) {}
238 std::string_view
kdf,
239 std::string_view dem_algo_spec,
241 std::string_view mac_spec,
246 m_dem_spec(dem_algo_spec),
247 m_dem_keylen(dem_key_len),
248 m_mac_spec(mac_spec),
249 m_mac_keylen(mac_key_len) {
252 throw Invalid_Argument(
"ECIES: only one of cofactor_mode, old_cofactor_mode and check_mode can be set");
257 std::string_view
kdf,
258 std::string_view dem_algo_spec,
260 std::string_view mac_spec,
265 m_dem_spec(dem_algo_spec),
266 m_dem_keylen(dem_key_len),
267 m_mac_spec(mac_spec),
268 m_mac_keylen(mac_key_len) {}
284 m_ka(private_key, ecies_params, true, rng),
285 m_params(ecies_params),
286 m_eph_public_key_bin(private_key.public_value()) {
290 m_eph_public_key_bin =
291 EC_AffinePoint(m_params.group(), m_eph_public_key_bin).serialize(ecies_params.point_format());
293 m_mac = m_params.create_mac();
311size_t ECIES_Encryptor::ciphertext_length(
size_t ptext_len)
const {
312 return m_eph_public_key_bin.size() + m_mac->output_length() + m_cipher->output_length(ptext_len);
318std::vector<uint8_t> ECIES_Encryptor::enc(
const uint8_t data[],
321 if(!m_other_point.has_value()) {
322 throw Invalid_State(
"ECIES_Encryptor: peer key invalid or not set");
325 const SymmetricKey secret_key = m_ka.derive_secret(m_eph_public_key_bin, m_other_point.value());
329 m_cipher->set_key(
SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
330 if(m_iv.empty() && !m_cipher->valid_nonce_length(m_iv.size())) {
331 throw Invalid_Argument(
"ECIES with " + m_cipher->name() +
" requires an IV be set");
334 m_cipher->start(m_iv.bits_of());
337 m_cipher->finish(encrypted_data);
340 m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
341 m_mac->update(encrypted_data);
342 if(!m_label.empty()) {
343 m_mac->update(m_label);
345 const auto mac = m_mac->final();
348 return concat(m_eph_public_key_bin, encrypted_data, mac);
354 m_ka(key, ecies_params, false, rng), m_params(ecies_params) {
368 m_mac = m_params.create_mac();
379 return 1 + 2 * fe_bytes;
385size_t ECIES_Decryptor::plaintext_length(
size_t ctext_len)
const {
386 const size_t point_size = compute_point_size(m_params.group(), m_params.point_format());
387 const size_t overhead = point_size + m_mac->output_length();
389 if(ctext_len < overhead) {
393 return m_cipher->output_length(ctext_len - overhead);
399secure_vector<uint8_t> ECIES_Decryptor::do_decrypt(uint8_t& valid_mask,
const uint8_t in[],
size_t in_len)
const {
400 const size_t point_size = compute_point_size(m_params.group(), m_params.point_format());
402 if(in_len < point_size + m_mac->output_length()) {
403 throw Decoding_Error(
"ECIES decryption: ciphertext is too short");
407 const std::vector<uint8_t> other_public_key_bin(in, in + point_size);
408 const std::vector<uint8_t> encrypted_data(in + point_size, in + in_len - m_mac->output_length());
409 const std::vector<uint8_t> mac_data(in + in_len - m_mac->output_length(), in + in_len);
412 auto other_public_key = EC_AffinePoint(m_params.group(), other_public_key_bin);
419 const SymmetricKey secret_key = m_ka.derive_secret(other_public_key_bin, other_public_key);
422 m_mac->set_key(secret_key.begin() + m_params.dem_keylen(), m_params.mac_keylen());
423 m_mac->update(encrypted_data);
424 if(!m_label.empty()) {
425 m_mac->update(m_label);
428 valid_mask =
CT::is_equal(mac_data.data(), calculated_mac.data(), mac_data.size()).value();
430 if(valid_mask == 0xFF) {
433 m_cipher->set_key(
SymmetricKey(secret_key.begin(), m_params.dem_keylen()));
434 if(m_iv.empty() && !m_cipher->valid_nonce_length(m_iv.size())) {
435 throw Invalid_Argument(
"ECIES with " + m_cipher->name() +
" requires an IV be set");
437 m_cipher->start(m_iv.bits_of());
443 m_cipher->finish(decrypted_data);
444 return decrypted_data;
#define BOTAN_DIAGNOSTIC_POP
#define BOTAN_DIAGNOSTIC_PUSH
#define BOTAN_DIAGNOSTIC_IGNORE_INHERITED_VIA_DOMINANCE
#define BOTAN_ARG_CHECK(expr, msg)
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)
ECIES_KA_Operation(const PK_Key_Agreement_Key &private_key, const ECIES_KA_Params &ecies_params, bool for_encryption, RandomNumberGenerator &rng)
SymmetricKey derive_secret(std::span< const uint8_t > eph_public_key_bin, const EC_AffinePoint &other_public_key_point) const
bool old_cofactor_mode() const
ECIES_KA_Params(const EC_Group &group, std::string_view kdf_spec, size_t length, EC_Point_Format point_format=EC_Point_Format::Uncompressed, bool single_hash_mode=true)
bool cofactor_mode() const
bool single_hash_mode() const
const EC_Group & group() const
const std::string & kdf() const
EC_Point_Format point_format() const
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
ECIES_System_Params(const EC_Group &group, 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, EC_Point_Format point_format=EC_Point_Format::Uncompressed, bool single_hash_mode=false)
bool is_identity() const
Return true if this point is the identity element.
static std::optional< EC_AffinePoint > deserialize(const EC_Group &group, std::span< const uint8_t > bytes)
const BigInt & get_cofactor() const
bool has_cofactor() const
size_t get_p_bytes() const
std::vector< uint8_t > encode(EC_Point_Format format) const
static EC_Scalar from_bigint(const EC_Group &group, const BigInt &bn)
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="")
const uint8_t * end() const
const uint8_t * begin() const
virtual size_t maximum_input_size() const =0
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
@ SingleHashMode
if set: prefix the input of the (ecdh) key agreement with the encoded (ephemeral) public key
constexpr auto concat(Rs &&... ranges)
std::vector< T, secure_allocator< T > > secure_vector