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

randombit / botan / 13262741994

11 Feb 2025 12:19PM UTC coverage: 91.656% (-0.003%) from 91.659%
13262741994

Pull #4647

github

web-flow
Merge 0b8e56724 into f372b5a9e
Pull Request #4647: Avoid using mem_ops.h or assert.h in public headers

94864 of 103500 relevant lines covered (91.66%)

11330304.66 hits per line

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

92.63
/src/lib/misc/srp6/srp6.cpp
1
/*
2
* SRP-6a (RFC 5054 compatatible)
3
* (C) 2011,2012,2019,2020 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7

8
#include <botan/srp6.h>
9

10
#include <botan/assert.h>
11
#include <botan/dl_group.h>
12
#include <botan/hash.h>
13
#include <botan/internal/fmt.h>
14

15
namespace Botan {
16

17
namespace {
18

19
BigInt hash_seq(HashFunction& hash_fn, size_t p_bytes, const BigInt& in1, const BigInt& in2) {
296✔
20
   hash_fn.update(in1.serialize(p_bytes));
296✔
21
   hash_fn.update(in2.serialize(p_bytes));
296✔
22

23
   return BigInt::from_bytes(hash_fn.final());
592✔
24
}
25

26
BigInt compute_x(HashFunction& hash_fn,
148✔
27
                 std::string_view identifier,
28
                 std::string_view password,
29
                 const std::vector<uint8_t>& salt) {
30
   hash_fn.update(identifier);
148✔
31
   hash_fn.update(":");
148✔
32
   hash_fn.update(password);
148✔
33

34
   secure_vector<uint8_t> inner_h = hash_fn.final();
148✔
35

36
   hash_fn.update(salt);
148✔
37
   hash_fn.update(inner_h);
148✔
38

39
   secure_vector<uint8_t> outer_h = hash_fn.final();
148✔
40

41
   return BigInt::from_bytes(outer_h);
148✔
42
}
296✔
43

44
}  // namespace
45

46
std::string srp6_group_identifier(const BigInt& N, const BigInt& g) {
50✔
47
   /*
48
   This function assumes that only one 'standard' SRP parameter set has
49
   been defined for a particular bitsize. As of this writing that is the case.
50
   */
51
   try {
50✔
52
      const std::string group_name = "modp/srp/" + std::to_string(N.bits());
100✔
53

54
      auto group = DL_Group::from_name(group_name);
50✔
55

56
      if(group.get_p() == N && group.get_g() == g) {
50✔
57
         return group_name;
100✔
58
      }
59
   } catch(...) {}
50✔
60

61
   // If we didn't return, the group was unknown or did not match
62
   throw Invalid_Argument("Invalid or unknown SRP group parameters");
×
63
}
64

65
std::pair<BigInt, SymmetricKey> srp6_client_agree(std::string_view identifier,
24✔
66
                                                  std::string_view password,
67
                                                  std::string_view group_id,
68
                                                  std::string_view hash_id,
69
                                                  const std::vector<uint8_t>& salt,
70
                                                  const BigInt& B,
71
                                                  RandomNumberGenerator& rng) {
72
   auto group = DL_Group::from_name(group_id);
24✔
73
   const size_t a_bits = group.exponent_bits();
24✔
74

75
   return srp6_client_agree(identifier, password, group, hash_id, salt, B, a_bits, rng);
24✔
76
}
24✔
77

78
std::pair<BigInt, SymmetricKey> srp6_client_agree(std::string_view identifier,
74✔
79
                                                  std::string_view password,
80
                                                  const DL_Group& group,
81
                                                  std::string_view hash_id,
82
                                                  const std::vector<uint8_t>& salt,
83
                                                  const BigInt& B,
84
                                                  const size_t a_bits,
85
                                                  RandomNumberGenerator& rng) {
86
   BOTAN_ARG_CHECK(a_bits <= group.p_bits(), "Invalid a_bits");
74✔
87

88
   const BigInt& g = group.get_g();
74✔
89
   const BigInt& p = group.get_p();
74✔
90

91
   const size_t p_bytes = group.p_bytes();
74✔
92

93
   if(B <= 0 || B >= p) {
148✔
94
      throw Decoding_Error("Invalid SRP parameter from server");
×
95
   }
96

97
   auto hash_fn = HashFunction::create_or_throw(hash_id);
74✔
98
   if(8 * hash_fn->output_length() >= group.p_bits()) {
74✔
99
      throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
×
100
   }
101

102
   const BigInt k = hash_seq(*hash_fn, p_bytes, p, g);
74✔
103

104
   const BigInt a(rng, a_bits);
74✔
105

106
   const BigInt A = group.power_g_p(a, a_bits);
74✔
107

108
   const BigInt u = hash_seq(*hash_fn, p_bytes, A, B);
74✔
109

110
   const BigInt x = compute_x(*hash_fn, identifier, password, salt);
74✔
111

112
   const BigInt g_x_p = group.power_g_p(x, hash_fn->output_length() * 8);
74✔
113

114
   const BigInt B_k_g_x_p = group.mod_p(B - group.multiply_mod_p(k, g_x_p));
74✔
115

116
   const BigInt a_ux = a + u * x;
74✔
117

118
   const size_t max_aux_bits = std::max<size_t>(a_bits + 1, 2 * 8 * hash_fn->output_length());
74✔
119
   BOTAN_ASSERT_NOMSG(max_aux_bits >= a_ux.bits());
74✔
120

121
   const BigInt S = group.power_b_p(B_k_g_x_p, a_ux, max_aux_bits);
74✔
122

123
   const SymmetricKey Sk(S.serialize<secure_vector<uint8_t>>(p_bytes));
74✔
124

125
   return std::make_pair(A, Sk);
74✔
126
}
148✔
127

128
BigInt srp6_generate_verifier(std::string_view identifier,
74✔
129
                              std::string_view password,
130
                              const std::vector<uint8_t>& salt,
131
                              std::string_view group_id,
132
                              std::string_view hash_id) {
133
   auto group = DL_Group::from_name(group_id);
74✔
134
   return srp6_generate_verifier(identifier, password, salt, group, hash_id);
74✔
135
}
74✔
136

137
BigInt srp6_generate_verifier(std::string_view identifier,
74✔
138
                              std::string_view password,
139
                              const std::vector<uint8_t>& salt,
140
                              const DL_Group& group,
141
                              std::string_view hash_id) {
142
   auto hash_fn = HashFunction::create_or_throw(hash_id);
74✔
143
   if(8 * hash_fn->output_length() >= group.p_bits()) {
74✔
144
      throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
×
145
   }
146

147
   const BigInt x = compute_x(*hash_fn, identifier, password, salt);
74✔
148
   return group.power_g_p(x, hash_fn->output_length() * 8);
74✔
149
}
148✔
150

151
BigInt SRP6_Server_Session::step1(const BigInt& v,
24✔
152
                                  std::string_view group_id,
153
                                  std::string_view hash_id,
154
                                  RandomNumberGenerator& rng) {
155
   auto group = DL_Group::from_name(group_id);
24✔
156
   const size_t b_bits = group.exponent_bits();
24✔
157
   return this->step1(v, group, hash_id, b_bits, rng);
24✔
158
}
24✔
159

160
BigInt SRP6_Server_Session::step1(
74✔
161
   const BigInt& v, const DL_Group& group, std::string_view hash_id, size_t b_bits, RandomNumberGenerator& rng) {
162
   BOTAN_ARG_CHECK(b_bits <= group.p_bits(), "Invalid b_bits");
74✔
163

164
   BOTAN_STATE_CHECK(!m_group);
74✔
165
   m_group = std::make_unique<DL_Group>(group);
74✔
166

167
   const BigInt& g = m_group->get_g();
74✔
168
   const BigInt& p = m_group->get_p();
74✔
169

170
   m_v = v;
74✔
171
   m_b = BigInt(rng, b_bits);
74✔
172
   m_hash_id = hash_id;
74✔
173

174
   auto hash_fn = HashFunction::create_or_throw(hash_id);
74✔
175
   if(8 * hash_fn->output_length() >= m_group->p_bits()) {
74✔
176
      throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
×
177
   }
178

179
   const BigInt k = hash_seq(*hash_fn, m_group->p_bytes(), p, g);
74✔
180
   m_B = m_group->mod_p(v * k + m_group->power_g_p(m_b, b_bits));
74✔
181

182
   return m_B;
74✔
183
}
148✔
184

185
SymmetricKey SRP6_Server_Session::step2(const BigInt& A) {
74✔
186
   BOTAN_STATE_CHECK(m_group);
74✔
187

188
   if(A <= 0 || A >= m_group->get_p()) {
74✔
189
      throw Decoding_Error("Invalid SRP parameter from client");
×
190
   }
191

192
   auto hash_fn = HashFunction::create_or_throw(m_hash_id);
74✔
193
   if(8 * hash_fn->output_length() >= m_group->p_bits()) {
74✔
194
      throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
×
195
   }
196

197
   const BigInt u = hash_seq(*hash_fn, m_group->p_bytes(), A, m_B);
74✔
198

199
   const BigInt vup = m_group->power_b_p(m_v, u, m_group->p_bits());
74✔
200
   const BigInt S = m_group->power_b_p(m_group->multiply_mod_p(A, vup), m_b, m_group->p_bits());
74✔
201

202
   return SymmetricKey(S.serialize<secure_vector<uint8_t>>(m_group->p_bytes()));
74✔
203
}
148✔
204

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

© 2026 Coveralls, Inc