Coverage Report

Created: 2020-09-16 07:52

/src/botan/src/lib/misc/srp6/srp6.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* SRP-6a (RFC 5054 compatatible)
3
* (C) 2011,2012,2019 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/srp6.h>
9
#include <botan/hash.h>
10
#include <botan/dl_group.h>
11
#include <botan/numthry.h>
12
13
namespace Botan {
14
15
namespace {
16
17
BigInt hash_seq(const std::string& hash_id,
18
                size_t pad_to,
19
                const BigInt& in1,
20
                const BigInt& in2)
21
0
   {
22
0
   std::unique_ptr<HashFunction> hash_fn(HashFunction::create_or_throw(hash_id));
23
0
24
0
   hash_fn->update(BigInt::encode_1363(in1, pad_to));
25
0
   hash_fn->update(BigInt::encode_1363(in2, pad_to));
26
0
27
0
   return BigInt::decode(hash_fn->final());
28
0
   }
29
30
BigInt compute_x(const std::string& hash_id,
31
                 const std::string& identifier,
32
                 const std::string& password,
33
                 const std::vector<uint8_t>& salt)
34
0
   {
35
0
   std::unique_ptr<HashFunction> hash_fn(HashFunction::create_or_throw(hash_id));
36
0
37
0
   hash_fn->update(identifier);
38
0
   hash_fn->update(":");
39
0
   hash_fn->update(password);
40
0
41
0
   secure_vector<uint8_t> inner_h = hash_fn->final();
42
0
43
0
   hash_fn->update(salt);
44
0
   hash_fn->update(inner_h);
45
0
46
0
   secure_vector<uint8_t> outer_h = hash_fn->final();
47
0
48
0
   return BigInt::decode(outer_h);
49
0
   }
50
51
}
52
53
std::string srp6_group_identifier(const BigInt& N, const BigInt& g)
54
0
   {
55
   /*
56
   This function assumes that only one 'standard' SRP parameter set has
57
   been defined for a particular bitsize. As of this writing that is the case.
58
   */
59
0
   try
60
0
      {
61
0
      const std::string group_name = "modp/srp/" + std::to_string(N.bits());
62
0
63
0
      DL_Group group(group_name);
64
0
65
0
      if(group.get_p() == N && group.get_g() == g)
66
0
         return group_name;
67
0
      }
68
0
   catch(...)
69
0
      {
70
0
      }
71
0
72
   // If we didn't return, the group was unknown or did not match
73
0
   throw Invalid_Argument("Invalid or unknown SRP group parameters");
74
0
   }
75
76
std::pair<BigInt, SymmetricKey>
77
srp6_client_agree(const std::string& identifier,
78
                  const std::string& password,
79
                  const std::string& group_id,
80
                  const std::string& hash_id,
81
                  const std::vector<uint8_t>& salt,
82
                  const BigInt& B,
83
                  RandomNumberGenerator& rng)
84
0
   {
85
0
   DL_Group group(group_id);
86
0
   const size_t a_bits = group.exponent_bits();
87
0
88
0
   return srp6_client_agree(identifier, password, group, hash_id, salt, B, a_bits, rng);
89
0
   }
90
91
std::pair<BigInt, SymmetricKey>
92
srp6_client_agree(const std::string& identifier,
93
                  const std::string& password,
94
                  const DL_Group& group,
95
                  const std::string& hash_id,
96
                  const std::vector<uint8_t>& salt,
97
                  const BigInt& B,
98
                  const size_t a_bits,
99
                  RandomNumberGenerator& rng)
100
0
   {
101
0
   const BigInt& g = group.get_g();
102
0
   const BigInt& p = group.get_p();
103
0
104
0
   const size_t p_bytes = group.p_bytes();
105
0
106
0
   if(B <= 0 || B >= p)
107
0
      throw Decoding_Error("Invalid SRP parameter from server");
108
0
109
0
   const BigInt k = hash_seq(hash_id, p_bytes, p, g);
110
0
111
0
   const BigInt a(rng, a_bits);
112
0
113
0
   const BigInt A = group.power_g_p(a, a_bits);
114
0
115
0
   const BigInt u = hash_seq(hash_id, p_bytes, A, B);
116
0
117
0
   const BigInt x = compute_x(hash_id, identifier, password, salt);
118
0
119
0
   const BigInt S = power_mod(group.mod_p(B - (k * power_mod(g, x, p))),
120
0
                              group.mod_p(a + (u * x)), p);
121
0
122
0
   const SymmetricKey Sk(BigInt::encode_1363(S, p_bytes));
123
0
124
0
   return std::make_pair(A, Sk);
125
0
   }
126
127
BigInt generate_srp6_verifier(const std::string& identifier,
128
                              const std::string& password,
129
                              const std::vector<uint8_t>& salt,
130
                              const std::string& group_id,
131
                              const std::string& hash_id)
132
0
   {
133
0
   DL_Group group(group_id);
134
0
   return generate_srp6_verifier(identifier, password, salt, group, hash_id);
135
0
   }
136
137
BigInt generate_srp6_verifier(const std::string& identifier,
138
                              const std::string& password,
139
                              const std::vector<uint8_t>& salt,
140
                              const DL_Group& group,
141
                              const std::string& hash_id)
142
0
   {
143
0
   const BigInt x = compute_x(hash_id, identifier, password, salt);
144
   // FIXME: x should be size of hash fn so avoid computing x.bits() here
145
0
   return group.power_g_p(x, x.bits());
146
0
   }
147
148
BigInt SRP6_Server_Session::step1(const BigInt& v,
149
                                  const std::string& group_id,
150
                                  const std::string& hash_id,
151
                                  RandomNumberGenerator& rng)
152
0
   {
153
0
   DL_Group group(group_id);
154
0
   const size_t b_bits = group.exponent_bits();
155
0
156
0
   return this->step1(v, group, hash_id, b_bits, rng);
157
0
   }
158
159
BigInt SRP6_Server_Session::step1(const BigInt& v,
160
                                  const DL_Group& group,
161
                                  const std::string& hash_id,
162
                                  size_t b_bits,
163
                                  RandomNumberGenerator& rng)
164
0
   {
165
0
   const BigInt& g = group.get_g();
166
0
   const BigInt& p = group.get_p();
167
0
168
0
   m_p_bytes = p.bytes();
169
0
   m_v = v;
170
0
   m_b = BigInt(rng, b_bits);
171
0
   m_p = p;
172
0
   m_hash_id = hash_id;
173
0
174
0
   const BigInt k = hash_seq(hash_id, m_p_bytes, p, g);
175
0
176
0
   m_B = group.mod_p(v*k + group.power_g_p(m_b, b_bits));
177
0
178
0
   return m_B;
179
0
   }
180
181
SymmetricKey SRP6_Server_Session::step2(const BigInt& A)
182
0
   {
183
0
   if(A <= 0 || A >= m_p)
184
0
      throw Decoding_Error("Invalid SRP parameter from client");
185
0
186
0
   const BigInt u = hash_seq(m_hash_id, m_p_bytes, A, m_B);
187
0
188
0
   const BigInt S = power_mod(A * power_mod(m_v, u, m_p), m_b, m_p);
189
0
190
0
   return BigInt::encode_1363(S, m_p_bytes);
191
0
   }
192
193
}