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