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