Botan 3.6.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 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 std::vector<uint8_t> raw_encrypt(std::span<const uint8_t> ptext, 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
121std::vector<uint8_t> ElGamal_Encryption_Operation::raw_encrypt(std::span<const uint8_t> ptext,
122 RandomNumberGenerator& rng) {
123 BigInt m(ptext);
124
125 const auto& group = m_key->group();
126
127 if(m >= group.get_p()) {
128 throw Invalid_Argument("ElGamal encryption: Input is too large");
129 }
130
131 /*
132 Some weird PGP implementations generate keys using bad parameters
133 which result in easily breakable encryption if short exponents are
134 used during encryption. To avoid this problem, always use full size
135 exponents.
136
137 See https://eprint.iacr.org/2021/923
138 */
139 const size_t k_bits = group.p_bits() - 1;
140 const BigInt k(rng, k_bits, false);
141
142 const BigInt a = group.power_g_p(k, k_bits);
143 const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits));
144
145 return unlock(BigInt::encode_fixed_length_int_pair(a, b, group.p_bytes()));
146}
147
148/**
149* ElGamal decryption operation
150*/
151class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME {
152 public:
153 ElGamal_Decryption_Operation(const std::shared_ptr<const DL_PrivateKey>& key,
154 std::string_view eme,
155 RandomNumberGenerator& rng) :
156 PK_Ops::Decryption_with_EME(eme),
157 m_key(key),
158 m_blinder(
159 m_key->group().get_p(),
160 rng,
161 [](const BigInt& k) { return k; },
162 [this](const BigInt& k) { return powermod_x_p(k); }) {}
163
164 size_t plaintext_length(size_t /*ctext_len*/) const override { return m_key->group().p_bytes(); }
165
166 secure_vector<uint8_t> raw_decrypt(std::span<const uint8_t> ctext) override;
167
168 private:
169 BigInt powermod_x_p(const BigInt& v) const { return m_key->group().power_b_p(v, m_key->private_key()); }
170
171 std::shared_ptr<const DL_PrivateKey> m_key;
172 Blinder m_blinder;
173};
174
175secure_vector<uint8_t> ElGamal_Decryption_Operation::raw_decrypt(std::span<const uint8_t> ctext) {
176 const auto& group = m_key->group();
177
178 const size_t p_bytes = group.p_bytes();
179
180 if(ctext.size() != 2 * p_bytes) {
181 throw Invalid_Argument("ElGamal decryption: Invalid message");
182 }
183
184 BigInt a(ctext.first(p_bytes));
185 const BigInt b(ctext.last(p_bytes));
186
187 if(a >= group.get_p() || b >= group.get_p()) {
188 throw Invalid_Argument("ElGamal decryption: Invalid message");
189 }
190
191 a = m_blinder.blind(a);
192
193 const BigInt r = group.multiply_mod_p(group.inverse_mod_p(powermod_x_p(a)), b);
194
195 return m_blinder.unblind(r).serialize<secure_vector<uint8_t>>(p_bytes);
196}
197
198} // namespace
199
200std::unique_ptr<PK_Ops::Encryption> ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
201 std::string_view params,
202 std::string_view provider) const {
203 if(provider == "base" || provider.empty()) {
204 return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
205 }
206 throw Provider_Not_Found(algo_name(), provider);
207}
208
210 std::string_view params,
211 std::string_view provider) const {
212 if(provider == "base" || provider.empty()) {
213 return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
214 }
215 throw Provider_Not_Found(algo_name(), provider);
216}
217
218} // 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: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:209
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:200
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
const SIMD_8x32 & b
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)