Botan 3.13.0
Crypto and TLS for C&
srp6.cpp
Go to the documentation of this file.
1/*
2* SRP-6a (RFC 5054 compatible)
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/exceptn.h>
13#include <botan/hash.h>
14#include <botan/internal/fmt.h>
15
16namespace Botan {
17
18namespace {
19
20BigInt hash_seq(HashFunction& hash_fn, size_t p_bytes, const BigInt& in1, const BigInt& in2) {
21 hash_fn.update(in1.serialize(p_bytes));
22 hash_fn.update(in2.serialize(p_bytes));
23
24 return BigInt::from_bytes(hash_fn.final());
25}
26
27BigInt compute_x(HashFunction& hash_fn,
28 std::string_view identifier,
29 std::string_view password,
30 const std::vector<uint8_t>& salt) {
31 hash_fn.update(identifier);
32 hash_fn.update(":");
33 hash_fn.update(password);
34
35 secure_vector<uint8_t> inner_h = hash_fn.final();
36
37 hash_fn.update(salt);
38 hash_fn.update(inner_h);
39
40 secure_vector<uint8_t> outer_h = hash_fn.final();
41
42 return BigInt::from_bytes(outer_h);
43}
44
45} // namespace
46
47std::string srp6_group_identifier(const BigInt& N, const BigInt& g) {
48 /*
49 This function assumes that only one 'standard' SRP parameter set has
50 been defined for a particular bitsize. As of this writing that is the case.
51 */
52 try {
53 const std::string group_name = "modp/srp/" + std::to_string(N.bits());
54
55 auto group = DL_Group::from_name(group_name);
56
57 if(group.get_p() == N && group.get_g() == g) {
58 return group_name;
59 }
60 } catch(...) {}
61
62 // If we didn't return, the group was unknown or did not match
63 throw Invalid_Argument("Invalid or unknown SRP group parameters");
64}
65
66std::pair<BigInt, SymmetricKey> srp6_client_agree(std::string_view identifier,
67 std::string_view password,
68 std::string_view group_id,
69 std::string_view hash_id,
70 const std::vector<uint8_t>& salt,
71 const BigInt& B,
73 auto group = DL_Group::from_name(group_id);
74 const size_t a_bits = group.exponent_bits();
75
76 return srp6_client_agree(identifier, password, group, hash_id, salt, B, a_bits, rng);
77}
78
79std::pair<BigInt, SymmetricKey> srp6_client_agree(std::string_view identifier,
80 std::string_view password,
81 const DL_Group& group,
82 std::string_view hash_id,
83 const std::vector<uint8_t>& salt,
84 const BigInt& B,
85 const size_t a_bits,
87 BOTAN_ARG_CHECK(a_bits <= group.p_bits(), "Invalid a_bits");
88
89 const BigInt& g = group.get_g();
90 const BigInt& p = group.get_p();
91
92 const size_t p_bytes = group.p_bytes();
93
94 if(B <= 0 || B >= p) {
95 throw Decoding_Error("Invalid SRP parameter from server");
96 }
97
98 auto hash_fn = HashFunction::create_or_throw(hash_id);
99 if(8 * hash_fn->output_length() >= group.p_bits()) {
100 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
101 }
102
103 const BigInt k = hash_seq(*hash_fn, p_bytes, p, g);
104
105 const BigInt a(rng, a_bits);
106
107 const BigInt A = group.power_g_p(a, a_bits);
108
109 const BigInt u = hash_seq(*hash_fn, p_bytes, A, B);
111
112 const BigInt x = compute_x(*hash_fn, identifier, password, salt);
113
114 const BigInt g_x_p = group.power_g_p(x, hash_fn->output_length() * 8);
115
116 const BigInt B_k_g_x_p = group.mod_p(B + group.mod_p(p - group.multiply_mod_p(k, g_x_p)));
117
118 const BigInt a_ux = a + u * x;
119
120 // a < 2^a_bits and u*x < 2^(2H) where H is the hash output bits, so
121 // a + u*x < 2^(max(a_bits, 2H) + 1).
122 const size_t max_aux_bits = std::max<size_t>(a_bits, 2 * 8 * hash_fn->output_length()) + 1;
123 BOTAN_ASSERT_NOMSG(max_aux_bits >= a_ux.bits());
124
125 const BigInt S = group.power_b_p(B_k_g_x_p, a_ux, max_aux_bits);
126
127 const SymmetricKey Sk(S.serialize<secure_vector<uint8_t>>(p_bytes));
128
129 return std::make_pair(A, Sk);
130}
131
132BigInt srp6_generate_verifier(std::string_view identifier,
133 std::string_view password,
134 const std::vector<uint8_t>& salt,
135 std::string_view group_id,
136 std::string_view hash_id) {
137 auto group = DL_Group::from_name(group_id);
138 return srp6_generate_verifier(identifier, password, salt, group, hash_id);
139}
140
141BigInt srp6_generate_verifier(std::string_view identifier,
142 std::string_view password,
143 const std::vector<uint8_t>& salt,
144 const DL_Group& group,
145 std::string_view hash_id) {
146 auto hash_fn = HashFunction::create_or_throw(hash_id);
147 if(8 * hash_fn->output_length() >= group.p_bits()) {
148 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
149 }
150
151 const BigInt x = compute_x(*hash_fn, identifier, password, salt);
152 return group.power_g_p(x, hash_fn->output_length() * 8);
153}
154
156 std::string_view group_id,
157 std::string_view hash_id,
159 auto group = DL_Group::from_name(group_id);
160 const size_t b_bits = group.exponent_bits();
161 return this->step1(v, group, hash_id, b_bits, rng);
162}
163
165 const BigInt& v, const DL_Group& group, std::string_view hash_id, size_t b_bits, RandomNumberGenerator& rng) {
166 if(v.signum() <= 0 || v >= group.get_p()) {
167 throw Invalid_Argument("SRP6_Server_Session: invalid verifier");
168 }
169
170 BOTAN_ARG_CHECK(b_bits >= 160 && b_bits <= group.p_bits(), "Invalid b_bits");
171
172 BOTAN_STATE_CHECK(!m_group);
173 m_group = std::make_unique<DL_Group>(group);
174 m_b_bits = b_bits;
175
176 const BigInt& g = m_group->get_g();
177 const BigInt& p = m_group->get_p();
178
179 m_v = v;
180 m_b = BigInt(rng, m_b_bits);
181 m_hash_id = hash_id;
182
183 auto hash_fn = HashFunction::create_or_throw(hash_id);
184 if(8 * hash_fn->output_length() >= m_group->p_bits()) {
185 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
186 }
187
188 const BigInt k = hash_seq(*hash_fn, m_group->p_bytes(), p, g);
189 m_B = m_group->mod_p(v * k + m_group->power_g_p(m_b, b_bits));
190
191 return m_B;
192}
193
195 BOTAN_STATE_CHECK(m_group);
196
197 if(A <= 0 || A >= m_group->get_p()) {
198 throw Decoding_Error("Invalid SRP parameter from client");
199 }
200
201 auto hash_fn = HashFunction::create_or_throw(m_hash_id);
202 if(8 * hash_fn->output_length() >= m_group->p_bits()) {
203 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
204 }
205
206 const BigInt u = hash_seq(*hash_fn, m_group->p_bytes(), A, m_B);
208
209 // The maximum length of u is fixed based on the chosen hash function
210 const size_t u_bits = hash_fn->output_length() * 8;
211 const BigInt vup = m_group->power_b_p(m_v, u, u_bits);
212
213 // The size of b is chosen by either a formula or the application; either way it is public
214 const BigInt S = m_group->power_b_p(m_group->multiply_mod_p(A, vup), m_b, m_b_bits);
215
216 return SymmetricKey(S.serialize<secure_vector<uint8_t>>(m_group->p_bytes()));
217}
218
219} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
int signum() const
Definition bigint.h:493
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:83
size_t bits() const
Definition bigint.cpp:307
bool is_zero() const
Definition bigint.h:510
T serialize(size_t len) const
Definition bigint.h:790
BigInt power_g_p(const BigInt &x) const
Definition dl_group.h:261
BigInt mod_p(const BigInt &x) const
Definition dl_group.cpp:580
BigInt multiply_mod_p(const BigInt &x, const BigInt &y) const
Definition dl_group.cpp:584
size_t p_bits() const
Definition dl_group.cpp:549
const BigInt & get_p() const
Definition dl_group.cpp:523
static DL_Group from_name(std::string_view name)
Definition dl_group.cpp:266
size_t p_bytes() const
Definition dl_group.cpp:553
BigInt power_b_p(const BigInt &b, const BigInt &x, size_t max_x_bits) const
Definition dl_group.cpp:632
const BigInt & get_g() const
Definition dl_group.cpp:530
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
Definition hash.cpp:308
BigInt step1(const BigInt &v, std::string_view group_id, std::string_view hash_id, RandomNumberGenerator &rng)
Definition srp6.cpp:155
SymmetricKey step2(const BigInt &A)
Definition srp6.cpp:194
OctetString SymmetricKey
Definition symkey.h:153
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
std::pair< BigInt, SymmetricKey > srp6_client_agree(std::string_view identifier, std::string_view password, std::string_view group_id, std::string_view hash_id, const std::vector< uint8_t > &salt, const BigInt &B, RandomNumberGenerator &rng)
Definition srp6.cpp:66
BigInt srp6_generate_verifier(std::string_view identifier, std::string_view password, const std::vector< uint8_t > &salt, std::string_view group_id, std::string_view hash_id)
Definition srp6.cpp:132
std::string srp6_group_identifier(const BigInt &N, const BigInt &g)
Definition srp6.cpp:47
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:128