Coverage Report

Created: 2026-05-30 06:42

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/botan/src/lib/pubkey/elgamal/elgamal.cpp
Line
Count
Source
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
17
namespace Botan {
18
19
0
ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& group, const BigInt& y) {
20
0
   m_public_key = std::make_shared<DL_PublicKey>(group, y);
21
0
}
Unexecuted instantiation: Botan::ElGamal_PublicKey::ElGamal_PublicKey(Botan::DL_Group const&, Botan::BigInt const&)
Unexecuted instantiation: Botan::ElGamal_PublicKey::ElGamal_PublicKey(Botan::DL_Group const&, Botan::BigInt const&)
22
23
0
ElGamal_PublicKey::ElGamal_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
24
0
   m_public_key = std::make_shared<DL_PublicKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
25
0
}
Unexecuted instantiation: Botan::ElGamal_PublicKey::ElGamal_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Unexecuted instantiation: Botan::ElGamal_PublicKey::ElGamal_PublicKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
26
27
0
size_t ElGamal_PublicKey::estimated_strength() const {
28
0
   return m_public_key->estimated_strength();
29
0
}
30
31
0
size_t ElGamal_PublicKey::key_length() const {
32
0
   return m_public_key->p_bits();
33
0
}
34
35
0
AlgorithmIdentifier ElGamal_PublicKey::algorithm_identifier() const {
36
0
   return AlgorithmIdentifier(object_identifier(), m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
37
0
}
38
39
0
std::vector<uint8_t> ElGamal_PublicKey::raw_public_key_bits() const {
40
0
   return m_public_key->public_key_as_bytes();
41
0
}
42
43
0
std::vector<uint8_t> ElGamal_PublicKey::public_key_bits() const {
44
0
   return m_public_key->DER_encode();
45
0
}
46
47
0
const BigInt& ElGamal_PublicKey::get_int_field(std::string_view field) const {
48
0
   return m_public_key->get_int_field(algo_name(), field);
49
0
}
50
51
0
std::unique_ptr<Private_Key> ElGamal_PublicKey::generate_another(RandomNumberGenerator& rng) const {
52
0
   return std::make_unique<ElGamal_PrivateKey>(rng, m_public_key->group());
53
0
}
54
55
0
bool ElGamal_PublicKey::check_key(RandomNumberGenerator& rng, bool strong) const {
56
0
   return m_public_key->check_key(rng, strong);
57
0
}
58
59
0
ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group) {
60
0
   m_private_key = std::make_shared<DL_PrivateKey>(group, rng);
61
0
   m_public_key = m_private_key->public_key();
62
0
}
Unexecuted instantiation: Botan::ElGamal_PrivateKey::ElGamal_PrivateKey(Botan::RandomNumberGenerator&, Botan::DL_Group const&)
Unexecuted instantiation: Botan::ElGamal_PrivateKey::ElGamal_PrivateKey(Botan::RandomNumberGenerator&, Botan::DL_Group const&)
63
64
0
ElGamal_PrivateKey::ElGamal_PrivateKey(const DL_Group& group, const BigInt& x) {
65
0
   m_private_key = std::make_shared<DL_PrivateKey>(group, x);
66
0
   m_public_key = m_private_key->public_key();
67
0
}
Unexecuted instantiation: Botan::ElGamal_PrivateKey::ElGamal_PrivateKey(Botan::DL_Group const&, Botan::BigInt const&)
Unexecuted instantiation: Botan::ElGamal_PrivateKey::ElGamal_PrivateKey(Botan::DL_Group const&, Botan::BigInt const&)
68
69
0
ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
70
0
   m_private_key = std::make_shared<DL_PrivateKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
71
0
   m_public_key = m_private_key->public_key();
72
0
}
Unexecuted instantiation: Botan::ElGamal_PrivateKey::ElGamal_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
Unexecuted instantiation: Botan::ElGamal_PrivateKey::ElGamal_PrivateKey(Botan::AlgorithmIdentifier const&, std::__1::span<unsigned char const, 18446744073709551615ul>)
73
74
0
std::unique_ptr<Public_Key> ElGamal_PrivateKey::public_key() const {
75
0
   return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(m_public_key));
76
0
}
77
78
0
const BigInt& ElGamal_PrivateKey::get_int_field(std::string_view field) const {
79
0
   return m_private_key->get_int_field(algo_name(), field);
80
0
}
81
82
0
secure_vector<uint8_t> ElGamal_PrivateKey::private_key_bits() const {
83
0
   return m_private_key->DER_encode();
84
0
}
85
86
0
secure_vector<uint8_t> ElGamal_PrivateKey::raw_private_key_bits() const {
87
0
   return m_private_key->raw_private_key_bits();
88
0
}
89
90
0
bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
91
0
   if(!m_private_key->check_key(rng, strong)) {
92
0
      return false;
93
0
   }
94
95
0
#if defined(BOTAN_HAS_OAEP) && defined(BOTAN_HAS_SHA_256)
96
0
   const std::string padding = "OAEP(SHA-256)";
97
#else
98
   const std::string padding = "Raw";
99
#endif
100
101
0
   return KeyPair::encryption_consistency_check(rng, *this, padding);
102
0
}
103
104
namespace {
105
106
/**
107
* ElGamal encryption operation
108
*/
109
class 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
0
            PK_Ops::Encryption_with_Padding(padding), m_key(key) {
113
0
         const size_t powm_window = 4;
114
0
         m_monty_y_p = monty_precompute(m_key->group()._monty_params_p(), m_key->public_key(), powm_window);
115
0
      }
116
117
0
      size_t ciphertext_length(size_t /*ptext_len*/) const override { return 2 * m_key->group().p_bytes(); }
118
119
0
      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
128
std::vector<uint8_t> ElGamal_Encryption_Operation::raw_encrypt(std::span<const uint8_t> ptext,
129
0
                                                               RandomNumberGenerator& rng) {
130
0
   const BigInt m(ptext);
131
132
0
   const auto& group = m_key->group();
133
134
0
   if(m == 0 || m >= group.get_p()) {
135
0
      throw Invalid_Argument("ElGamal encryption: Message out of valid plaintext range");
136
0
   }
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
0
   const size_t k_bits = group.p_bits() - 1;
147
0
   const BigInt k(rng, k_bits, false);
148
149
0
   const BigInt a = group.power_g_p(k, k_bits);
150
0
   const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits).value());
151
152
0
   const size_t p_bytes = group.p_bytes();
153
0
   std::vector<uint8_t> ctext(2 * p_bytes);
154
0
   BufferStuffer stuffer(ctext);
155
0
   a.serialize_to(stuffer.next(p_bytes));
156
0
   b.serialize_to(stuffer.next(p_bytes));
157
0
   return ctext;
158
0
}
159
160
/**
161
* ElGamal decryption operation
162
*/
163
class 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
0
            PK_Ops::Decryption_with_Padding(padding),
169
0
            m_key(key),
170
0
            m_blinder(
171
0
               m_key->group()._reducer_mod_p(),
172
0
               rng,
173
0
               [](const BigInt& k) { return k; },
174
0
               [this](const BigInt& k) { return powermod_x_p(k); }) {}
175
176
0
      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
0
      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
187
0
secure_vector<uint8_t> ElGamal_Decryption_Operation::raw_decrypt(std::span<const uint8_t> ctext) {
188
0
   const auto& group = m_key->group();
189
190
0
   const size_t p_bytes = group.p_bytes();
191
192
0
   if(ctext.size() != 2 * p_bytes) {
193
0
      throw Invalid_Argument("ElGamal decryption: Invalid message");
194
0
   }
195
196
0
   BigInt a(ctext.first(p_bytes));
197
0
   const BigInt b(ctext.last(p_bytes));
198
199
0
   if(!group.verify_public_element(a)) {
200
0
      throw Invalid_Argument("ElGamal decryption: Invalid message");
201
0
   }
202
203
0
   if(b == 0 || b >= group.get_p()) {
204
0
      throw Invalid_Argument("ElGamal decryption: Invalid message");
205
0
   }
206
207
0
   a = m_blinder.blind(a);
208
209
0
   const BigInt r = group.multiply_mod_p(group.inverse_mod_p(powermod_x_p(a)), b);
210
211
0
   return m_blinder.unblind(r).serialize<secure_vector<uint8_t>>(p_bytes);
212
0
}
213
214
}  // namespace
215
216
std::unique_ptr<PK_Ops::Encryption> ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
217
                                                                            std::string_view params,
218
0
                                                                            std::string_view provider) const {
219
0
   if(provider == "base" || provider.empty()) {
220
0
      return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
221
0
   }
222
0
   throw Provider_Not_Found(algo_name(), provider);
223
0
}
224
225
std::unique_ptr<PK_Ops::Decryption> ElGamal_PrivateKey::create_decryption_op(RandomNumberGenerator& rng,
226
                                                                             std::string_view params,
227
0
                                                                             std::string_view provider) const {
228
0
   if(provider == "base" || provider.empty()) {
229
0
      return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
230
0
   }
231
0
   throw Provider_Not_Found(algo_name(), provider);
232
0
}
233
234
}  // namespace Botan