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