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

randombit / botan / 5976513284

25 Aug 2023 02:08PM UTC coverage: 91.731% (+0.02%) from 91.707%
5976513284

Pull #3680

github

web-flow
Merge dacba68bf into 88fbc4081
Pull Request #3680: Kuznyechik block cipher

78785 of 85887 relevant lines covered (91.73%)

8425808.74 hits per line

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

90.11
/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 {
4✔
27
   return m_public_key->estimated_strength();
4✔
28
}
29

30
size_t ElGamal_PublicKey::key_length() const {
×
31
   return m_public_key->p_bits();
×
32
}
33

34
AlgorithmIdentifier ElGamal_PublicKey::algorithm_identifier() const {
44✔
35
   return AlgorithmIdentifier(object_identifier(), m_public_key->group().DER_encode(DL_Group_Format::ANSI_X9_42));
88✔
36
}
37

38
std::vector<uint8_t> ElGamal_PublicKey::public_key_bits() const {
17✔
39
   return m_public_key->DER_encode();
17✔
40
}
41

42
const BigInt& ElGamal_PublicKey::get_int_field(std::string_view field) const {
6✔
43
   return m_public_key->get_int_field(algo_name(), field);
6✔
44
}
45

46
bool ElGamal_PublicKey::check_key(RandomNumberGenerator& rng, bool strong) const {
5✔
47
   return m_public_key->check_key(rng, strong);
5✔
48
}
49

50
ElGamal_PrivateKey::ElGamal_PrivateKey(RandomNumberGenerator& rng, const DL_Group& group) {
8✔
51
   m_private_key = std::make_shared<DL_PrivateKey>(group, rng);
8✔
52
   m_public_key = m_private_key->public_key();
8✔
53
}
8✔
54

55
ElGamal_PrivateKey::ElGamal_PrivateKey(const DL_Group& group, const BigInt& x) {
25✔
56
   m_private_key = std::make_shared<DL_PrivateKey>(group, x);
25✔
57
   m_public_key = m_private_key->public_key();
25✔
58
}
25✔
59

60
ElGamal_PrivateKey::ElGamal_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) {
14✔
61
   m_private_key = std::make_shared<DL_PrivateKey>(alg_id, key_bits, DL_Group_Format::ANSI_X9_42);
14✔
62
   m_public_key = m_private_key->public_key();
14✔
63
}
14✔
64

65
std::unique_ptr<Public_Key> ElGamal_PrivateKey::public_key() const {
3✔
66
   return std::unique_ptr<Public_Key>(new ElGamal_PublicKey(m_public_key));
3✔
67
}
68

69
const BigInt& ElGamal_PrivateKey::get_int_field(std::string_view field) const {
2✔
70
   return m_private_key->get_int_field(algo_name(), field);
2✔
71
}
72

73
secure_vector<uint8_t> ElGamal_PrivateKey::private_key_bits() const {
31✔
74
   return m_private_key->DER_encode();
31✔
75
}
76

77
secure_vector<uint8_t> ElGamal_PrivateKey::raw_private_key_bits() const {
×
78
   return m_private_key->raw_private_key_bits();
×
79
}
80

81
bool ElGamal_PrivateKey::check_key(RandomNumberGenerator& rng, bool strong) const {
3✔
82
   if(!m_private_key->check_key(rng, strong)) {
3✔
83
      return false;
84
   }
85

86
   return KeyPair::encryption_consistency_check(rng, *this, "OAEP(SHA-256)");
3✔
87
}
88

89
namespace {
90

91
/**
92
* ElGamal encryption operation
93
*/
94
class ElGamal_Encryption_Operation final : public PK_Ops::Encryption_with_EME {
×
95
   public:
96
      ElGamal_Encryption_Operation(const std::shared_ptr<const DL_PublicKey>& key, std::string_view eme) :
15✔
97
            PK_Ops::Encryption_with_EME(eme), m_key(key) {
15✔
98
         const size_t powm_window = 4;
15✔
99
         m_monty_y_p = monty_precompute(m_key->group().monty_params_p(), m_key->public_key(), powm_window);
15✔
100
      }
15✔
101

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

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

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

108
   private:
109
      std::shared_ptr<const DL_PublicKey> m_key;
110
      std::shared_ptr<const Montgomery_Exponentation_State> m_monty_y_p;
111
};
112

113
secure_vector<uint8_t> ElGamal_Encryption_Operation::raw_encrypt(const uint8_t msg[],
15✔
114
                                                                 size_t msg_len,
115
                                                                 RandomNumberGenerator& rng) {
116
   BigInt m(msg, msg_len);
15✔
117

118
   const auto& group = m_key->group();
15✔
119

120
   if(m >= group.get_p()) {
15✔
121
      throw Invalid_Argument("ElGamal encryption: Input is too large");
×
122
   }
123

124
   /*
125
   Some weird PGP implementations generate keys using bad parameters
126
   which result in easily breakable encryption if short exponents are
127
   used during encryption. To avoid this problem, always use full size
128
   exponents.
129

130
   See https://eprint.iacr.org/2021/923
131
   */
132
   const size_t k_bits = group.p_bits() - 1;
15✔
133
   const BigInt k(rng, k_bits, false);
15✔
134

135
   const BigInt a = group.power_g_p(k, k_bits);
15✔
136
   const BigInt b = group.multiply_mod_p(m, monty_execute(*m_monty_y_p, k, k_bits));
15✔
137

138
   return BigInt::encode_fixed_length_int_pair(a, b, group.p_bytes());
15✔
139
}
60✔
140

141
/**
142
* ElGamal decryption operation
143
*/
144
class ElGamal_Decryption_Operation final : public PK_Ops::Decryption_with_EME {
×
145
   public:
146
      ElGamal_Decryption_Operation(const std::shared_ptr<const DL_PrivateKey>& key,
32✔
147
                                   std::string_view eme,
148
                                   RandomNumberGenerator& rng) :
32✔
149
            PK_Ops::Decryption_with_EME(eme),
150
            m_key(key),
32✔
151
            m_blinder(
64✔
152
               m_key->group().get_p(),
32✔
153
               rng,
154
               [](const BigInt& k) { return k; },
32✔
155
               [this](const BigInt& k) { return powermod_x_p(k); }) {}
64✔
156

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

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

161
   private:
162
      BigInt powermod_x_p(const BigInt& v) const { return m_key->group().power_b_p(v, m_key->private_key()); }
32✔
163

164
      std::shared_ptr<const DL_PrivateKey> m_key;
165
      Blinder m_blinder;
166
};
167

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

171
   const size_t p_bytes = group.p_bytes();
492✔
172

173
   if(msg_len != 2 * p_bytes) {
492✔
174
      throw Invalid_Argument("ElGamal decryption: Invalid message");
×
175
   }
176

177
   BigInt a(msg, p_bytes);
492✔
178
   const BigInt b(msg + p_bytes, p_bytes);
492✔
179

180
   if(a >= group.get_p() || b >= group.get_p()) {
492✔
181
      throw Invalid_Argument("ElGamal decryption: Invalid message");
×
182
   }
183

184
   a = m_blinder.blind(a);
492✔
185

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

188
   return BigInt::encode_1363(m_blinder.unblind(r), p_bytes);
984✔
189
}
1,476✔
190

191
}  // namespace
192

193
std::unique_ptr<PK_Ops::Encryption> ElGamal_PublicKey::create_encryption_op(RandomNumberGenerator& /*rng*/,
33✔
194
                                                                            std::string_view params,
195
                                                                            std::string_view provider) const {
196
   if(provider == "base" || provider.empty()) {
39✔
197
      return std::make_unique<ElGamal_Encryption_Operation>(this->m_public_key, params);
15✔
198
   }
199
   throw Provider_Not_Found(algo_name(), provider);
36✔
200
}
201

202
std::unique_ptr<PK_Ops::Decryption> ElGamal_PrivateKey::create_decryption_op(RandomNumberGenerator& rng,
101✔
203
                                                                             std::string_view params,
204
                                                                             std::string_view provider) const {
205
   if(provider == "base" || provider.empty()) {
124✔
206
      return std::make_unique<ElGamal_Decryption_Operation>(this->m_private_key, params, rng);
32✔
207
   }
208
   throw Provider_Not_Found(algo_name(), provider);
138✔
209
}
210

211
}  // 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