Botan 3.3.0
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/numthry.h>
13#include <botan/internal/fmt.h>
14
15namespace Botan {
16
17namespace {
18
19BigInt hash_seq(HashFunction& hash_fn, size_t pad_to, const BigInt& in1, const BigInt& in2) {
20 hash_fn.update(BigInt::encode_1363(in1, pad_to));
21 hash_fn.update(BigInt::encode_1363(in2, pad_to));
22
23 return BigInt::decode(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::decode(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 std::string group_name = "modp/srp/" + std::to_string(N.bits());
53
54 DL_Group group(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 DL_Group group(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.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(BigInt::encode_1363(S, 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 DL_Group group(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 DL_Group group(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 m_group = group;
165
166 const BigInt& g = group.get_g();
167 const BigInt& p = 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() >= 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 = group.mod_p(v * k + group.power_g_p(m_b, b_bits));
180
181 return m_B;
182}
183
185 if(A <= 0 || A >= m_group.get_p()) {
186 throw Decoding_Error("Invalid SRP parameter from client");
187 }
188
189 auto hash_fn = HashFunction::create_or_throw(m_hash_id);
190 if(8 * hash_fn->output_length() >= m_group.p_bits()) {
191 throw Invalid_Argument(fmt("Hash function {} too large for SRP6 with this group", hash_fn->name()));
192 }
193
194 const BigInt u = hash_seq(*hash_fn, m_group.p_bytes(), A, m_B);
195
196 const BigInt vup = m_group.power_b_p(m_v, u, m_group.p_bits());
197 const BigInt S = m_group.power_b_p(m_group.multiply_mod_p(A, vup), m_b, m_group.p_bits());
198
199 return SymmetricKey(BigInt::encode_1363(S, m_group.p_bytes()));
200}
201
202} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
static BigInt decode(const uint8_t buf[], size_t length)
Definition bigint.h:772
size_t bits() const
Definition bigint.cpp:290
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
Definition big_code.cpp:105
BigInt power_g_p(const BigInt &x) const
Definition dl_group.cpp:521
BigInt mod_p(const BigInt &x) const
Definition dl_group.cpp:483
BigInt multiply_mod_p(const BigInt &x, const BigInt &y) const
Definition dl_group.cpp:487
size_t p_bits() const
Definition dl_group.cpp:452
const BigInt & get_p() const
Definition dl_group.cpp:426
size_t p_bytes() const
Definition dl_group.cpp:456
BigInt power_b_p(const BigInt &b, const BigInt &x, size_t max_x_bits) const
Definition dl_group.cpp:533
size_t exponent_bits() const
Definition dl_group.cpp:474
const BigInt & get_g() const
Definition dl_group.cpp:433
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:184
OctetString SymmetricKey
Definition symkey.h:141
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