• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

randombit / botan / 5133001362

31 May 2023 01:21PM UTC coverage: 92.021% (+0.009%) from 92.012%
5133001362

Pull #3549

github

web-flow
Merge 959f0cf91 into 1cbeffafb
Pull Request #3549: SPHINCS+

76874 of 83540 relevant lines covered (92.02%)

12243477.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.8
/src/lib/pubkey/elgamal/elgamal.cpp
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

16
namespace Botan {
17

18
ElGamal_PublicKey::ElGamal_PublicKey(const DL_Group& group, const BigInt& y) {
2✔
19
   m_public_key = std::make_shared<DL_PublicKey>(group, y);
2✔
20
}
2✔
21

22
ElGamal_PublicKey::ElGamal_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
4✔
23
   m_public_key = std::make_shared<DL_PublicKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
4✔
24
}
4✔
25

26
size_t ElGamal_PublicKey::estimated_strength() const { return m_public_key->estimated_strength(); }
4✔
27

28
size_t ElGamal_PublicKey::key_length() const { return m_public_key->p_bits(); }
×
29

30
AlgorithmIdentifier ElGamal_PublicKey::algorithm_identifier() const {
44✔
31
   return AlgorithmIdentifier(object_identifier(), m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
88✔
32
}
33

34
std::vector<uint8_t> ElGamal_PublicKey::public_key_bits() const { return m_public_key->DER_encode(); }
17✔
35

36
const BigInt& ElGamal_PublicKey::get_int_field(std::string_view field) const {
6✔
37
   return m_public_key->get_int_field(algo_name(), field);
6✔
38
}
39

40
bool ElGamal_PublicKey::check_key(RandomNumberGenerator& rng, bool strong) const {
5✔
41
   return m_public_key->check_key(rng, strong);
5✔
42
}
43

44
ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group) {
8✔
45
   m_private_key = std::make_shared<DL_PrivateKey>(group, rng);
8✔
46
   m_public_key = m_private_key->public_key();
8✔
47
}
8✔
48

49
ElGamal_PrivateKey::ElGamal_PrivateKey(const DL_Group& group, const BigInt& x) {
25✔
50
   m_private_key = std::make_shared<DL_PrivateKey>(group, x);
25✔
51
   m_public_key = m_private_key->public_key();
25✔
52
}
25✔
53

54
ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
14✔
55
   m_private_key = std::make_shared<DL_PrivateKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
14✔
56
   m_public_key = m_private_key->public_key();
14✔
57
}
14✔
58

59
std::unique_ptr<Public_Key> ElGamal_PrivateKey::public_key() const {
3✔
60
   return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(m_public_key));
6✔
61
}
62

63
const BigInt& ElGamal_PrivateKey::get_int_field(std::string_view field) const {
2✔
64
   return m_private_key->get_int_field(algo_name(), field);
2✔
65
}
66

67
secure_vector<uint8_t> ElGamal_PrivateKey::private_key_bits() const { return m_private_key->DER_encode(); }
31✔
68

69
secure_vector<uint8_t> ElGamal_PrivateKey::raw_private_key_bits() const {
×
70
   return m_private_key->raw_private_key_bits();
×
71
}
72

73
bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
3✔
74
   if(!m_private_key->check_key(rng, strong)) {
3✔
75
      return false;
76
   }
77

78
   return KeyPair::encryption_consistency_check(rng, *this, "OAEP(SHA-256)");
3✔
79
}
80

81
namespace {
82

83
/**
84
* ElGamal encryption operation
85
*/
86
class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME {
×
87
   public:
88
      ElGamal_Encryption_Operation(const std::shared_ptr<const DL_PublicKey>& key, std::string_view eme) :
15✔
89
            PK_Ops::Encryption_with_EME(eme), m_key(key) {
15✔
90
         const size_t powm_window = 4;
15✔
91
         m_monty_y_p = monty_precompute(m_key->group().monty_params_p(), m_key->public_key(), powm_window);
15✔
92
      }
15✔
93

94
      size_t ciphertext_length(size_t /*ptext_len*/) const override { return 2 * m_key->group().p_bytes(); }
8✔
95

96
      size_t max_ptext_input_bits() const override { return m_key->group().p_bits() - 1; }
31✔
97

98
      secure_vector<uint8_t> raw_encrypt(const uint8_t msg[], size_t msg_len, RandomNumberGenerator& rng) override;
99

100
   private:
101
      std::shared_ptr<const DL_PublicKey> m_key;
102
      std::shared_ptr<const Montgomery_Exponentation_State> m_monty_y_p;
103
};
104

105
secure_vector<uint8_t> ElGamal_Encryption_Operation::raw_encrypt(const uint8_t msg[],
15✔
106
                                                                 size_t msg_len,
107
                                                                 RandomNumberGenerator& rng) {
108
   BigInt m(msg, msg_len);
15✔
109

110
   const auto& group = m_key->group();
15✔
111

112
   if(m >= group.get_p()) {
15✔
113
      throw Invalid_Argument("ElGamal encryption: Input is too large");
×
114
   }
115

116
   /*
117
   Some weird PGP implementations generate keys using bad parameters
118
   which result in easily breakable encryption if short exponents are
119
   used during encryption. To avoid this problem, always use full size
120
   exponents.
121

122
   See https://eprint.iacr.org/2021/923
123
   */
124
   const size_t k_bits = group.p_bits() - 1;
15✔
125
   const BigInt k(rng, k_bits, false);
15✔
126

127
   const BigInt a = group.power_g_p(k, k_bits);
15✔
128
   const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits));
15✔
129

130
   return BigInt::encode_fixed_length_int_pair(a, b, group.p_bytes());
15✔
131
}
60✔
132

133
/**
134
* ElGamal decryption operation
135
*/
136
class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME {
×
137
   public:
138
      ElGamal_Decryption_Operation(const std::shared_ptr<const DL_PrivateKey>& key,
32✔
139
                                   std::string_view eme,
140
                                   RandomNumberGenerator& rng) :
32✔
141
            PK_Ops::Decryption_with_EME(eme),
142
            m_key(key),
64✔
143
            m_blinder(
64✔
144
               m_key->group().get_p(),
32✔
145
               rng,
146
               [](const BigInt& k) { return k; },
32✔
147
               [this](const BigInt& k) { return powermod_x_p(k); }) {}
64✔
148

149
      size_t plaintext_length(size_t /*ctext_len*/) const override { return m_key->group().p_bytes(); }
8✔
150

151
      secure_vector<uint8_t> raw_decrypt(const uint8_t msg[], size_t msg_len) override;
152

153
   private:
154
      BigInt powermod_x_p(const BigInt& v) const { return m_key->group().power_b_p(v, m_key->private_key()); }
32✔
155

156
      std::shared_ptr<const DL_PrivateKey> m_key;
157
      Blinder m_blinder;
158
};
159

160
secure_vector<uint8_t> ElGamal_Decryption_Operation::raw_decrypt(const uint8_t msg[], size_t msg_len) {
492✔
161
   const auto& group = m_key->group();
492✔
162

163
   const size_t p_bytes = group.p_bytes();
492✔
164

165
   if(msg_len != 2 * p_bytes) {
492✔
166
      throw Invalid_Argument("ElGamal decryption: Invalid message");
×
167
   }
168

169
   BigInt a(msg, p_bytes);
492✔
170
   const BigInt b(msg + p_bytes, p_bytes);
492✔
171

172
   if(a >= group.get_p() || b >= group.get_p()) {
492✔
173
      throw Invalid_Argument("ElGamal decryption: Invalid message");
×
174
   }
175

176
   a = m_blinder.blind(a);
492✔
177

178
   const BigInt r = group.multiply_mod_p(group.inverse_mod_p(powermod_x_p(a)), b);
984✔
179

180
   return BigInt::encode_1363(m_blinder.unblind(r), p_bytes);
984✔
181
}
1,476✔
182

183
}  // namespace
184

185
std::unique_ptr<PK_Ops::Encryption> ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
33✔
186
                                                                            std::string_view params,
187
                                                                            std::string_view provider) const {
188
   if(provider == "base" || provider.empty()) {
39✔
189
      return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
15✔
190
   }
191
   throw Provider_Not_Found(algo_name(), provider);
36✔
192
}
193

194
std::unique_ptr<PK_Ops::Decryption> ElGamal_PrivateKey::create_decryption_op(RandomNumberGenerator& rng,
101✔
195
                                                                             std::string_view params,
196
                                                                             std::string_view provider) const {
197
   if(provider == "base" || provider.empty()) {
124✔
198
      return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
32✔
199
   }
200
   throw Provider_Not_Found(algo_name(), provider);
138✔
201
}
202

203
}  // namespace Botan
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc