Botan 3.12.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 const size_t max_aux_bits = std::max<size_t>(a_bits + 1, 2 * 8 * hash_fn->output_length());
121 BOTAN_ASSERT_NOMSG(max_aux_bits >= a_ux.bits());
122
123 const BigInt S = group.power_b_p(B_k_g_x_p, a_ux, max_aux_bits);
124
125 const SymmetricKey Sk(S.serialize<secure_vector<uint8_t>>(p_bytes));
126
127 return std::make_pair(A, Sk);
128}
129
130BigInt srp6_generate_verifier(std::string_view identifier,
131 std::string_view password,
132 const std::vector<uint8_t>& salt,
133 std::string_view group_id,
134 std::string_view hash_id) {
135 auto group = DL_Group::from_name(group_id);
136 return srp6_generate_verifier(identifier, password, salt, group, hash_id);
137}
138
139BigInt srp6_generate_verifier(std::string_view identifier,
140 std::string_view password,
141 const std::vector<uint8_t>& salt,
142 const DL_Group& group,
143 std::string_view hash_id) {
144 auto hash_fn = HashFunction::create_or_throw(hash_id);
145 if(8 * hash_fn->output_length() >= group.p_bits()) {
146 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
147 }
148
149 const BigInt x = compute_x(*hash_fn, identifier, password, salt);
150 return group.power_g_p(x, hash_fn->output_length() * 8);
151}
152
154 std::string_view group_id,
155 std::string_view hash_id,
157 auto group = DL_Group::from_name(group_id);
158 const size_t b_bits = group.exponent_bits();
159 return this->step1(v, group, hash_id, b_bits, rng);
160}
161
163 const BigInt& v, const DL_Group& group, std::string_view hash_id, size_t b_bits, RandomNumberGenerator& rng) {
164 BOTAN_ARG_CHECK(b_bits <= group.p_bits(), "Invalid b_bits");
165
166 BOTAN_STATE_CHECK(!m_group);
167 m_group = std::make_unique<DL_Group>(group);
168
169 const BigInt& g = m_group->get_g();
170 const BigInt& p = m_group->get_p();
171
172 m_v = v;
173 m_b = BigInt(rng, b_bits);
174 m_hash_id = hash_id;
175
176 auto hash_fn = HashFunction::create_or_throw(hash_id);
177 if(8 * hash_fn->output_length() >= m_group->p_bits()) {
178 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
179 }
180
181 const BigInt k = hash_seq(*hash_fn, m_group->p_bytes(), p, g);
182 m_B = m_group->mod_p(v * k + m_group->power_g_p(m_b, b_bits));
183
184 return m_B;
185}
186
188 BOTAN_STATE_CHECK(m_group);
189
190 if(A <= 0 || A >= m_group->get_p()) {
191 throw Decoding_Error("Invalid SRP parameter from client");
192 }
193
194 auto hash_fn = HashFunction::create_or_throw(m_hash_id);
195 if(8 * hash_fn->output_length() >= m_group->p_bits()) {
196 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
197 }
198
199 const BigInt u = hash_seq(*hash_fn, m_group->p_bytes(), A, m_B);
201
202 const BigInt vup = m_group->power_b_p(m_v, u, m_group->p_bits());
203 const BigInt S = m_group->power_b_p(m_group->multiply_mod_p(A, vup), m_b, m_group->p_bits());
204
205 return SymmetricKey(S.serialize<secure_vector<uint8_t>>(m_group->p_bytes()));
206}
207
208} // 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
bool is_zero() const
Definition bigint.h:484
T serialize(size_t len) const
Definition bigint.h:744
BigInt power_g_p(const BigInt &x) const
Definition dl_group.h:261
BigInt mod_p(const BigInt &x) const
Definition dl_group.cpp:576
BigInt multiply_mod_p(const BigInt &x, const BigInt &y) const
Definition dl_group.cpp:580
size_t p_bits() const
Definition dl_group.cpp:545
const BigInt & get_p() const
Definition dl_group.cpp:519
static DL_Group from_name(std::string_view name)
Definition dl_group.cpp:262
size_t p_bytes() const
Definition dl_group.cpp:549
BigInt power_b_p(const BigInt &b, const BigInt &x, size_t max_x_bits) const
Definition dl_group.cpp:626
const BigInt & get_g() const
Definition dl_group.cpp:526
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:153
SymmetricKey step2(const BigInt &A)
Definition srp6.cpp:187
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:130
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