Botan 3.0.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#include <botan/internal/dl_scheme.h>
10#include <botan/internal/pk_ops_impl.h>
11#include <botan/internal/monty_exp.h>
12#include <botan/internal/keypair.h>
13#include <botan/internal/blinding.h>
14
15namespace Botan {
16
17ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& group, const BigInt& y)
18 {
19 m_public_key = std::make_shared<DL_PublicKey>(group, y);
20 }
21
22ElGamal_PublicKey::ElGamal_PublicKey(const AlgorithmIdentifier& alg_id,
23 std::span<const uint8_t> key_bits)
24 {
25 m_public_key = std::make_shared<DL_PublicKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
26 }
27
29 {
30 return m_public_key->estimated_strength();
31 }
32
34 {
35 return m_public_key->p_bits();
36 }
37
39 {
42 m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
43 }
44
45std::vector<uint8_t> ElGamal_PublicKey::public_key_bits() const
46 {
47 return m_public_key->DER_encode();
48 }
49
50const BigInt& ElGamal_PublicKey::get_int_field(std::string_view field) const
51 {
52 return m_public_key->get_int_field(algo_name(), field);
53 }
54
56 {
57 return m_public_key->check_key(rng, strong);
58 }
59
61 const DL_Group& group)
62 {
63 m_private_key = std::make_shared<DL_PrivateKey>(group, rng);
64 m_public_key = m_private_key->public_key();
65 }
66
68 const BigInt& x)
69 {
70 m_private_key = std::make_shared<DL_PrivateKey>(group, x);
71 m_public_key = m_private_key->public_key();
72 }
73
75 std::span<const uint8_t> key_bits)
76 {
77 m_private_key = std::make_shared<DL_PrivateKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
78 m_public_key = m_private_key->public_key();
79 }
80
81std::unique_ptr<Public_Key> ElGamal_PrivateKey::public_key() const
82 {
83 return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(m_public_key));
84 }
85
86const BigInt& ElGamal_PrivateKey::get_int_field(std::string_view field) const
87 {
88 return m_private_key->get_int_field(algo_name(), field);
89 }
90
92 {
93 return m_private_key->DER_encode();
94 }
95
97 {
98 return m_private_key->raw_private_key_bits();
99 }
100
102 bool strong) const
103 {
104 if(!m_private_key->check_key(rng, strong))
105 return false;
106
107 return KeyPair::encryption_consistency_check(rng, *this, "OAEP(SHA-256)");
108 }
109
110namespace {
111
112/**
113* ElGamal encryption operation
114*/
115class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME
116 {
117 public:
118
119 ElGamal_Encryption_Operation(const std::shared_ptr<const DL_PublicKey>& key,
120 std::string_view eme) :
121 PK_Ops::Encryption_with_EME(eme),
122 m_key(key)
123 {
124 const size_t powm_window = 4;
125 m_monty_y_p = monty_precompute(m_key->group().monty_params_p(),
126 m_key->public_key(),
127 powm_window);
128 }
129
130 size_t ciphertext_length(size_t /*ptext_len*/) const override
131 {
132 return 2*m_key->group().p_bytes();
133 }
134
135 size_t max_ptext_input_bits() const override
136 {
137 return m_key->group().p_bits() - 1;
138 }
139
140 secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t msg_len,
141 RandomNumberGenerator& rng) override;
142
143 private:
144 std::shared_ptr<const DL_PublicKey> m_key;
145 std::shared_ptr<const Montgomery_Exponentation_State> m_monty_y_p;
146 };
147
148secure_vector<uint8_t>
149ElGamal_Encryption_Operation::raw_encrypt(const uint8_t msg[], size_t msg_len,
150 RandomNumberGenerator& rng)
151 {
152 BigInt m(msg, msg_len);
153
154 const auto& group = m_key->group();
155
156 if(m >= group.get_p())
157 throw Invalid_Argument("ElGamal encryption: Input is too large");
158
159 /*
160 Some weird PGP implementations generate keys using bad parameters
161 which result in easily breakable encryption if short exponents are
162 used during encryption. To avoid this problem, always use full size
163 exponents.
164
165 See https://eprint.iacr.org/2021/923
166 */
167 const size_t k_bits = group.p_bits() - 1;
168 const BigInt k(rng, k_bits, false);
169
170 const BigInt a = group.power_g_p(k, k_bits);
171 const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits));
172
173 return BigInt::encode_fixed_length_int_pair(a, b, group.p_bytes());
174 }
175
176/**
177* ElGamal decryption operation
178*/
179class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME
180 {
181 public:
182
183 ElGamal_Decryption_Operation(const std::shared_ptr<const DL_PrivateKey>& key,
184 std::string_view eme,
185 RandomNumberGenerator& rng) :
186 PK_Ops::Decryption_with_EME(eme),
187 m_key(key),
188 m_blinder(m_key->group().get_p(),
189 rng,
190 [](const BigInt& k) { return k; },
191 [this](const BigInt& k) { return powermod_x_p(k); })
192 {}
193
194 size_t plaintext_length(size_t /*ctext_len*/) const override
195 {
196 return m_key->group().p_bytes();
197 }
198
199 secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override;
200 private:
201 BigInt powermod_x_p(const BigInt& v) const
202 {
203 return m_key->group().power_b_p(v, m_key->private_key());
204 }
205
206 std::shared_ptr<const DL_PrivateKey> m_key;
207 Blinder m_blinder;
208 };
209
210secure_vector<uint8_t>
211ElGamal_Decryption_Operation::raw_decrypt(const uint8_t msg[], size_t msg_len)
212 {
213 const auto& group = m_key->group();
214
215 const size_t p_bytes = group.p_bytes();
216
217 if(msg_len != 2 * p_bytes)
218 throw Invalid_Argument("ElGamal decryption: Invalid message");
219
220 BigInt a(msg, p_bytes);
221 const BigInt b(msg + p_bytes, p_bytes);
222
223 if(a >= group.get_p() || b >= group.get_p())
224 throw Invalid_Argument("ElGamal decryption: Invalid message");
225
226 a = m_blinder.blind(a);
227
228 const BigInt r = group.multiply_mod_p(group.inverse_mod_p(powermod_x_p(a)), b);
229
230 return BigInt::encode_1363(m_blinder.unblind(r), p_bytes);
231 }
232
233}
234
235std::unique_ptr<PK_Ops::Encryption>
237 std::string_view params,
238 std::string_view provider) const
239 {
240 if(provider == "base" || provider.empty())
241 return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
242 throw Provider_Not_Found(algo_name(), provider);
243 }
244
245std::unique_ptr<PK_Ops::Decryption>
247 std::string_view params,
248 std::string_view provider) const
249 {
250 if(provider == "base" || provider.empty())
251 return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
252 throw Provider_Not_Found(algo_name(), provider);
253 }
254
255}
static SIMD_4x64 y
virtual OID object_identifier() const
Definition: pk_keys.cpp:22
static secure_vector< uint8_t > encode_fixed_length_int_pair(const BigInt &n1, const BigInt &n2, size_t bytes)
Definition: big_code.cpp:129
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition: big_code.cpp:107
BigInt blind(const BigInt &x) const
Definition: blinding.cpp:35
BigInt unblind(const BigInt &x) const
Definition: blinding.cpp:58
std::unique_ptr< PK_Ops::Decryption > create_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition: elgamal.cpp:246
secure_vector< uint8_t > private_key_bits() const override
Definition: elgamal.cpp:91
const BigInt & get_int_field(std::string_view field) const override
Definition: elgamal.cpp:86
std::unique_ptr< Public_Key > public_key() const override
Definition: elgamal.cpp:81
secure_vector< uint8_t > raw_private_key_bits() const override
Definition: elgamal.cpp:96
bool check_key(RandomNumberGenerator &rng, bool) const override
Definition: elgamal.cpp:101
std::unique_ptr< PK_Ops::Encryption > create_encryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition: elgamal.cpp:236
const BigInt & get_int_field(std::string_view field) const override
Definition: elgamal.cpp:50
std::vector< uint8_t > public_key_bits() const override
Definition: elgamal.cpp:45
friend class ElGamal_PrivateKey
Definition: elgamal.h:65
size_t estimated_strength() const override
Definition: elgamal.cpp:28
bool check_key(RandomNumberGenerator &rng, bool strong) const override
Definition: elgamal.cpp:55
AlgorithmIdentifier algorithm_identifier() const override
Definition: elgamal.cpp:38
size_t key_length() const override
Definition: elgamal.cpp:33
std::string algo_name() const override
Definition: elgamal.h:55
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:17
Definition: alg_id.cpp:12
BigInt monty_execute(const Montgomery_Exponentation_State &precomputed_state, const BigInt &k, size_t max_k_bits)
Definition: monty_exp.cpp:162
std::vector< T, secure_allocator< T > > secure_vector
Definition: secmem.h:64
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)
Definition: monty_exp.cpp:154