Botan 3.11.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);
110
111 const BigInt x = compute_x(*hash_fn, identifier, password, salt);
112
113 const BigInt g_x_p = group.power_g_p(x, hash_fn->output_length() * 8);
114
115 const BigInt B_k_g_x_p = group.mod_p(B + group.mod_p(p - group.multiply_mod_p(k, g_x_p)));
116
117 const BigInt a_ux = a + u * x;
118
119 const size_t max_aux_bits = std::max<size_t>(a_bits + 1, 2 * 8 * hash_fn->output_length());
120 BOTAN_ASSERT_NOMSG(max_aux_bits >= a_ux.bits());
121
122 const BigInt S = group.power_b_p(B_k_g_x_p, a_ux, max_aux_bits);
123
124 const SymmetricKey Sk(S.serialize<secure_vector<uint8_t>>(p_bytes));
125
126 return std::make_pair(A, Sk);
127}
128
129BigInt srp6_generate_verifier(std::string_view identifier,
130 std::string_view password,
131 const std::vector<uint8_t>& salt,
132 std::string_view group_id,
133 std::string_view hash_id) {
134 auto group = DL_Group::from_name(group_id);
135 return srp6_generate_verifier(identifier, password, salt, group, hash_id);
136}
137
138BigInt srp6_generate_verifier(std::string_view identifier,
139 std::string_view password,
140 const std::vector<uint8_t>& salt,
141 const DL_Group& group,
142 std::string_view hash_id) {
143 auto hash_fn = HashFunction::create_or_throw(hash_id);
144 if(8 * hash_fn->output_length() >= group.p_bits()) {
145 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
146 }
147
148 const BigInt x = compute_x(*hash_fn, identifier, password, salt);
149 return group.power_g_p(x, hash_fn->output_length() * 8);
150}
151
153 std::string_view group_id,
154 std::string_view hash_id,
156 auto group = DL_Group::from_name(group_id);
157 const size_t b_bits = group.exponent_bits();
158 return this->step1(v, group, hash_id, b_bits, rng);
159}
160
162 const BigInt& v, const DL_Group& group, std::string_view hash_id, size_t b_bits, RandomNumberGenerator& rng) {
163 BOTAN_ARG_CHECK(b_bits <= group.p_bits(), "Invalid b_bits");
164
165 BOTAN_STATE_CHECK(!m_group);
166 m_group = std::make_unique<DL_Group>(group);
167
168 const BigInt& g = m_group->get_g();
169 const BigInt& p = m_group->get_p();
170
171 m_v = v;
172 m_b = BigInt(rng, b_bits);
173 m_hash_id = hash_id;
174
175 auto hash_fn = HashFunction::create_or_throw(hash_id);
176 if(8 * hash_fn->output_length() >= m_group->p_bits()) {
177 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
178 }
179
180 const BigInt k = hash_seq(*hash_fn, m_group->p_bytes(), p, g);
181 m_B = m_group->mod_p(v * k + m_group->power_g_p(m_b, b_bits));
182
183 return m_B;
184}
185
187 BOTAN_STATE_CHECK(m_group);
188
189 if(A <= 0 || A >= m_group->get_p()) {
190 throw Decoding_Error("Invalid SRP parameter from client");
191 }
192
193 auto hash_fn = HashFunction::create_or_throw(m_hash_id);
194 if(8 * hash_fn->output_length() >= m_group->p_bits()) {
195 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
196 }
197
198 const BigInt u = hash_seq(*hash_fn, m_group->p_bytes(), A, m_B);
199
200 const BigInt vup = m_group->power_b_p(m_v, u, m_group->p_bits());
201 const BigInt S = m_group->power_b_p(m_group->multiply_mod_p(A, vup), m_b, m_group->p_bits());
202
203 return SymmetricKey(S.serialize<secure_vector<uint8_t>>(m_group->p_bytes()));
204}
205
206} // 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
static BigInt from_bytes(std::span< const uint8_t > bytes)
Definition bigint.cpp:83
size_t bits() const
Definition bigint.cpp:307
T serialize(size_t len) const
Definition bigint.h:727
BigInt power_g_p(const BigInt &x) const
Definition dl_group.h:263
BigInt mod_p(const BigInt &x) const
Definition dl_group.cpp:531
BigInt multiply_mod_p(const BigInt &x, const BigInt &y) const
Definition dl_group.cpp:535
size_t p_bits() const
Definition dl_group.cpp:500
const BigInt & get_p() const
Definition dl_group.cpp:474
static DL_Group from_name(std::string_view name)
Definition dl_group.cpp:217
size_t p_bytes() const
Definition dl_group.cpp:504
BigInt power_b_p(const BigInt &b, const BigInt &x, size_t max_x_bits) const
Definition dl_group.cpp:581
const BigInt & get_g() const
Definition dl_group.cpp:481
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:152
SymmetricKey step2(const BigInt &A)
Definition srp6.cpp:186
OctetString SymmetricKey
Definition symkey.h:140
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:129
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:68