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