Botan 3.7.1
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#if defined(BOTAN_HAS_OAEP) && defined(BOTAN_HAS_SHA_256)
95 const std::string padding = "OAEP(SHA-256)";
96#else
97 const std::string padding = "Raw";
98#endif
99
100 return KeyPair::encryption_consistency_check(rng, *this, padding);
101}
102
103namespace {
104
105/**
106* ElGamal encryption operation
107*/
108class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME {
109 public:
110 ElGamal_Encryption_Operation(const std::shared_ptr<const DL_PublicKey>& key, std::string_view eme) :
111 PK_Ops::Encryption_with_EME(eme), m_key(key) {
112 const size_t powm_window = 4;
113 m_monty_y_p = monty_precompute(m_key->group().monty_params_p(), m_key->public_key(), powm_window);
114 }
115
116 size_t ciphertext_length(size_t /*ptext_len*/) const override { return 2 * m_key->group().p_bytes(); }
117
118 size_t max_ptext_input_bits() const override { return m_key->group().p_bits() - 1; }
119
120 std::vector<uint8_t> raw_encrypt(std::span<const uint8_t> ptext, RandomNumberGenerator& rng) override;
121
122 private:
123 std::shared_ptr<const DL_PublicKey> m_key;
124 std::shared_ptr<const Montgomery_Exponentation_State> m_monty_y_p;
125};
126
127std::vector<uint8_t> ElGamal_Encryption_Operation::raw_encrypt(std::span<const uint8_t> ptext,
128 RandomNumberGenerator& rng) {
129 BigInt m(ptext);
130
131 const auto& group = m_key->group();
132
133 if(m >= group.get_p()) {
134 throw Invalid_Argument("ElGamal encryption: Input is too large");
135 }
136
137 /*
138 Some weird PGP implementations generate keys using bad parameters
139 which result in easily breakable encryption if short exponents are
140 used during encryption. To avoid this problem, always use full size
141 exponents.
142
143 See https://eprint.iacr.org/2021/923
144 */
145 const size_t k_bits = group.p_bits() - 1;
146 const BigInt k(rng, k_bits, false);
147
148 const BigInt a = group.power_g_p(k, k_bits);
149 const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits).value());
150
151 return unlock(BigInt::encode_fixed_length_int_pair(a, b, group.p_bytes()));
152}
153
154/**
155* ElGamal decryption operation
156*/
157class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME {
158 public:
159 ElGamal_Decryption_Operation(const std::shared_ptr<const DL_PrivateKey>& key,
160 std::string_view eme,
161 RandomNumberGenerator& rng) :
162 PK_Ops::Decryption_with_EME(eme),
163 m_key(key),
164 m_blinder(
165 m_key->group()._reducer_mod_p(),
166 rng,
167 [](const BigInt& k) { return k; },
168 [this](const BigInt& k) { return powermod_x_p(k); }) {}
169
170 size_t plaintext_length(size_t /*ctext_len*/) const override { return m_key->group().p_bytes(); }
171
172 secure_vector<uint8_t> raw_decrypt(std::span<const uint8_t> ctext) override;
173
174 private:
175 BigInt powermod_x_p(const BigInt& v) const { return m_key->group().power_b_p(v, m_key->private_key()); }
176
177 std::shared_ptr<const DL_PrivateKey> m_key;
178 Blinder m_blinder;
179};
180
181secure_vector<uint8_t> ElGamal_Decryption_Operation::raw_decrypt(std::span<const uint8_t> ctext) {
182 const auto& group = m_key->group();
183
184 const size_t p_bytes = group.p_bytes();
185
186 if(ctext.size() != 2 * p_bytes) {
187 throw Invalid_Argument("ElGamal decryption: Invalid message");
188 }
189
190 BigInt a(ctext.first(p_bytes));
191 const BigInt b(ctext.last(p_bytes));
192
193 if(a >= group.get_p() || b >= group.get_p()) {
194 throw Invalid_Argument("ElGamal decryption: Invalid message");
195 }
196
197 a = m_blinder.blind(a);
198
199 const BigInt r = group.multiply_mod_p(group.inverse_mod_p(powermod_x_p(a)), b);
200
201 return m_blinder.unblind(r).serialize<secure_vector<uint8_t>>(p_bytes);
202}
203
204} // namespace
205
206std::unique_ptr<PK_Ops::Encryption> ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
207 std::string_view params,
208 std::string_view provider) const {
209 if(provider == "base" || provider.empty()) {
210 return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
211 }
212 throw Provider_Not_Found(algo_name(), provider);
213}
214
216 std::string_view params,
217 std::string_view provider) const {
218 if(provider == "base" || provider.empty()) {
219 return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
220 }
221 throw Provider_Not_Found(algo_name(), provider);
222}
223
224} // namespace Botan
virtual OID object_identifier() const
Definition pk_keys.cpp:22
T serialize(size_t len) const
Definition bigint.h:712
BigInt blind(const BigInt &x) const
Definition blinding.cpp:33
BigInt unblind(const BigInt &x) const
Definition blinding.cpp:49
std::unique_ptr< PK_Ops::Decryption > create_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition elgamal.cpp:215
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:206
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 > unlock(const secure_vector< T > &in)
Definition secmem.h:75
Montgomery_Int monty_execute(const Montgomery_Exponentation_State &precomputed_state, const BigInt &k, size_t max_k_bits)
const SIMD_8x32 & b
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61
std::shared_ptr< const Montgomery_Exponentation_State > monty_precompute(const Montgomery_Int &g, size_t window_bits, bool const_time)