Botan 3.5.0
Crypto and TLS for C&
elgamal.cpp
Go to the documentation of this file.
1/*
2* ElGamal
3* (C) 1999-2007,2018,2019,2023 Jack Lloyd
4*
5* Botan is released under the Simplified BSD License (see license.txt)
6*/
7
8#include <botan/elgamal.h>
9
10#include <botan/internal/blinding.h>
11#include <botan/internal/dl_scheme.h>
12#include <botan/internal/keypair.h>
13#include <botan/internal/monty_exp.h>
14#include <botan/internal/pk_ops_impl.h>
15
16namespace Botan {
17
18ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& group, const BigInt& y) {
19 m_public_key = std::make_shared<DL_PublicKey>(group, y);
20}
21
22ElGamal_PublicKey::ElGamal_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
23 m_public_key = std::make_shared<DL_PublicKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
24}
25
27 return m_public_key->estimated_strength();
28}
29
31 return m_public_key->p_bits();
32}
33
37
38std::vector<uint8_t> ElGamal_PublicKey::raw_public_key_bits() const {
39 return m_public_key->public_key_as_bytes();
40}
41
42std::vector<uint8_t> ElGamal_PublicKey::public_key_bits() const {
43 return m_public_key->DER_encode();
44}
45
46const BigInt& ElGamal_PublicKey::get_int_field(std::string_view field) const {
47 return m_public_key->get_int_field(algo_name(), field);
48}
49
50std::unique_ptr<Private_Key> ElGamal_PublicKey::generate_another(RandomNumberGenerator& rng) const {
51 return std::make_unique<ElGamal_PrivateKey>(rng, m_public_key->group());
52}
53
55 return m_public_key->check_key(rng, strong);
56}
57
59 m_private_key = std::make_shared<DL_PrivateKey>(group, rng);
60 m_public_key = m_private_key->public_key();
61}
62
64 m_private_key = std::make_shared<DL_PrivateKey>(group, x);
65 m_public_key = m_private_key->public_key();
66}
67
68ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
69 m_private_key = std::make_shared<DL_PrivateKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
70 m_public_key = m_private_key->public_key();
71}
72
73std::unique_ptr<Public_Key> ElGamal_PrivateKey::public_key() const {
74 return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(m_public_key));
75}
76
77const BigInt& ElGamal_PrivateKey::get_int_field(std::string_view field) const {
78 return m_private_key->get_int_field(algo_name(), field);
79}
80
82 return m_private_key->DER_encode();
83}
84
86 return m_private_key->raw_private_key_bits();
87}
88
90 if(!m_private_key->check_key(rng, strong)) {
91 return false;
92 }
93
94 return KeyPair::encryption_consistency_check(rng, *this, "OAEP(SHA-256)");
95}
96
97namespace {
98
99/**
100* ElGamal encryption operation
101*/
102class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME {
103 public:
104 ElGamal_Encryption_Operation(const std::shared_ptr<const DL_PublicKey>& key, std::string_view eme) :
105 PK_Ops::Encryption_with_EME(eme), m_key(key) {
106 const size_t powm_window = 4;
107 m_monty_y_p = monty_precompute(m_key->group().monty_params_p(), m_key->public_key(), powm_window);
108 }
109
110 size_t ciphertext_length(size_t /*ptext_len*/) const override { return 2 * m_key->group().p_bytes(); }
111
112 size_t max_ptext_input_bits() const override { return m_key->group().p_bits() - 1; }
113
114 secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override;
115
116 private:
117 std::shared_ptr<const DL_PublicKey> m_key;
118 std::shared_ptr<const Montgomery_Exponentation_State> m_monty_y_p;
119};
120
121secure_vector<uint8_t> ElGamal_Encryption_Operation::raw_encrypt(const uint8_t msg[],
122 size_t msg_len,
123 RandomNumberGenerator& rng) {
124 BigInt m(msg, msg_len);
125
126 const auto& group = m_key->group();
127
128 if(m >= group.get_p()) {
129 throw Invalid_Argument("ElGamal encryption: Input is too large");
130 }
131
132 /*
133 Some weird PGP implementations generate keys using bad parameters
134 which result in easily breakable encryption if short exponents are
135 used during encryption. To avoid this problem, always use full size
136 exponents.
137
138 See https://eprint.iacr.org/2021/923
139 */
140 const size_t k_bits = group.p_bits() - 1;
141 const BigInt k(rng, k_bits, false);
142
143 const BigInt a = group.power_g_p(k, k_bits);
144 const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits));
145
146 return BigInt::encode_fixed_length_int_pair(a, b, group.p_bytes());
147}
148
149/**
150* ElGamal decryption operation
151*/
152class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME {
153 public:
154 ElGamal_Decryption_Operation(const std::shared_ptr<const DL_PrivateKey>& key,
155 std::string_view eme,
156 RandomNumberGenerator& rng) :
157 PK_Ops::Decryption_with_EME(eme),
158 m_key(key),
159 m_blinder(
160 m_key->group().get_p(),
161 rng,
162 [](const BigInt& k) { return k; },
163 [this](const BigInt& k) { return powermod_x_p(k); }) {}
164
165 size_t plaintext_length(size_t /*ctext_len*/) const override { return m_key->group().p_bytes(); }
166
167 secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override;
168
169 private:
170 BigInt powermod_x_p(const BigInt& v) const { return m_key->group().power_b_p(v, m_key->private_key()); }
171
172 std::shared_ptr<const DL_PrivateKey> m_key;
173 Blinder m_blinder;
174};
175
176secure_vector<uint8_t> ElGamal_Decryption_Operation::raw_decrypt(const uint8_t msg[], size_t msg_len) {
177 const auto& group = m_key->group();
178
179 const size_t p_bytes = group.p_bytes();
180
181 if(msg_len != 2 * p_bytes) {
182 throw Invalid_Argument("ElGamal decryption: Invalid message");
183 }
184
185 BigInt a(msg, p_bytes);
186 const BigInt b(msg + p_bytes, p_bytes);
187
188 if(a >= group.get_p() || b >= group.get_p()) {
189 throw Invalid_Argument("ElGamal decryption: Invalid message");
190 }
191
192 a = m_blinder.blind(a);
193
194 const BigInt r = group.multiply_mod_p(group.inverse_mod_p(powermod_x_p(a)), b);
195
196 return m_blinder.unblind(r).serialize<secure_vector<uint8_t>>(p_bytes);
197}
198
199} // namespace
200
201std::unique_ptr<PK_Ops::Encryption> ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
202 std::string_view params,
203 std::string_view provider) const {
204 if(provider == "base" || provider.empty()) {
205 return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
206 }
207 throw Provider_Not_Found(algo_name(), provider);
208}
209
211 std::string_view params,
212 std::string_view provider) const {
213 if(provider == "base" || provider.empty()) {
214 return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
215 }
216 throw Provider_Not_Found(algo_name(), provider);
217}
218
219} // namespace Botan
virtual OID object_identifier() const
Definition pk_keys.cpp:22
T serialize(size_t len) const
Definition bigint.h:711
BigInt blind(const BigInt &x) const
Definition blinding.cpp:33
BigInt unblind(const BigInt &x) const
Definition blinding.cpp:53
std::unique_ptr< PK_Ops::Decryption > create_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition elgamal.cpp:210
secure_vector< uint8_t > private_key_bits() const override
Definition elgamal.cpp:81
const BigInt & get_int_field(std::string_view field) const override
Definition elgamal.cpp:77
std::unique_ptr< Public_Key > public_key() const override
Definition elgamal.cpp:73
secure_vector< uint8_t > raw_private_key_bits() const override
Definition elgamal.cpp:85
bool check_key(RandomNumberGenerator &rng, bool) const override
Definition elgamal.cpp:89
std::unique_ptr< PK_Ops::Encryption > create_encryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition elgamal.cpp:201
const BigInt & get_int_field(std::string_view field) const override
Definition elgamal.cpp:46
std::vector< uint8_t > public_key_bits() const override
Definition elgamal.cpp:42
friend class ElGamal_PrivateKey
Definition elgamal.h:62
size_t estimated_strength() const override
Definition elgamal.cpp:26
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition elgamal.cpp:54
AlgorithmIdentifier algorithm_identifier() const override
Definition elgamal.cpp:34
std::vector< uint8_t > raw_public_key_bits() const override
Definition elgamal.cpp:38
size_t key_length() const override
Definition elgamal.cpp:30
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
Definition elgamal.cpp:50
std::string algo_name() const override
Definition elgamal.h:51
int(* final)(unsigned char *, CTX *)
bool encryption_consistency_check(RandomNumberGenerator &rng, const Private_Key &private_key, const Public_Key &public_key, std::string_view padding)
Definition keypair.cpp:18
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
BigInt monty_execute(const Montgomery_Exponentation_State &precomputed_state, const BigInt &k, size_t max_k_bits)
std::shared_ptr< const Montgomery_Exponentation_State > monty_precompute(const std::shared_ptr< const Montgomery_Params > &params, const BigInt &g, size_t window_bits, bool const_time)