1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
|
/*
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TRINITY_SRP6_H
#define TRINITY_SRP6_H
#include "BigNumber.h"
#include "CryptoHash.h"
#include "Define.h"
#include "Optional.h"
#include <array>
#include <span>
namespace Trinity::Crypto
{
namespace SRP
{
static constexpr size_t SALT_LENGTH = 32;
using Salt = std::array<uint8, SALT_LENGTH>;
using Verifier = std::vector<uint8>;
class TC_COMMON_API SRP6
{
protected:
struct ForRegistrationTag { };
public:
explicit SRP6(BigNumber const& i, Salt const& salt, Verifier const& verifier, BigNumber const& N, BigNumber const& g, BigNumber const& k);
explicit SRP6(ForRegistrationTag);
SRP6(SRP6 const&) = delete;
SRP6(SRP6&&) = delete;
SRP6& operator=(SRP6 const&) = delete;
SRP6& operator=(SRP6&&) = delete;
virtual ~SRP6() = default;
virtual BigNumber const& GetN() const = 0;
virtual BigNumber const& Getg() const = 0;
Optional<BigNumber> VerifyClientEvidence(BigNumber const& A, BigNumber const& clientM1);
virtual BigNumber CalculateServerEvidence(BigNumber const& A, BigNumber const& clientM1, BigNumber const& K) const = 0;
template<typename Impl>
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password)
{
Impl impl(ForRegistrationTag{});
return { impl.s, impl.CalculateVerifier(username, password, impl.s) };
}
bool CheckCredentials(std::string const& username, std::string const& password) const;
Salt const s; // s - the user's password salt, random, used to calculate v on registration
protected:
static BigNumber CalculatePrivateB(BigNumber const& N);
BigNumber CalculatePublicB(BigNumber const& N, BigNumber const& g, BigNumber const& k) const;
virtual BigNumber CalculateX(std::string const& username, std::string const& password, Salt const& salt) const = 0;
Verifier CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt) const;
virtual Optional<BigNumber> DoVerifyClientEvidence(BigNumber const& A, BigNumber const& clientM1) = 0;
BigNumber const I; // H(I) - the username, all uppercase
BigNumber const b; // b - randomly chosen by the server, same length as N, never given out
BigNumber const v; // v - the user's password verifier, derived from s + H(USERNAME || ":" || PASSWORD)
public:
BigNumber const B; // B = k*v + g^b
private:
bool _used = false; // a single instance can only be used to verify once
};
class TC_COMMON_API GruntSRP6 final : public SRP6
{
public:
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
using SessionKey = std::array<uint8, SHA1::DIGEST_LENGTH * 2>;
static BigNumber const N; // the modulus, an algorithm parameter; all operations are mod this
static BigNumber const g; // a [g]enerator for the ring of integers mod N, algorithm parameter
explicit GruntSRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
explicit GruntSRP6(ForRegistrationTag t) : SRP6(t) { }
BigNumber const& GetN() const override { return N; }
BigNumber const& Getg() const override { return g; }
BigNumber CalculateServerEvidence(BigNumber const& A, BigNumber const& clientM1, BigNumber const& K) const override;
protected:
BigNumber CalculateX(std::string const& username, std::string const& password, Salt const& salt) const override;
Optional<BigNumber> DoVerifyClientEvidence(BigNumber const& A, BigNumber const& clientM1) override;
static SessionKey SHA1Interleave(EphemeralKey const& S);
};
class TC_COMMON_API BnetSRP6Base : public SRP6
{
public:
explicit BnetSRP6Base(BigNumber const& i, Salt const& salt, Verifier const& verifier, BigNumber const& N, BigNumber const& g, BigNumber const& k);
explicit BnetSRP6Base(ForRegistrationTag t) : SRP6(t) { }
BigNumber CalculateServerEvidence(BigNumber const& A, BigNumber const& clientM1, BigNumber const& K) const final;
virtual uint8 GetVersion() const = 0;
virtual uint32 GetXIterations() const = 0;
protected:
Optional<BigNumber> DoVerifyClientEvidence(BigNumber const& A, BigNumber const& clientM1) final;
virtual BigNumber CalculateU(BigNumber const& A) const = 0;
virtual BigNumber DoCalculateEvidence(std::span<BigNumber const*> bns) const = 0;
template<typename CryptoHash>
BigNumber DoCalculateEvidence(std::span<BigNumber const*> bns) const
{
CryptoHash hash;
for (BigNumber const* bn : bns)
hash.UpdateData(GetBrokenEvidenceVector(*bn));
hash.Finalize();
return BigNumber(hash.GetDigest(), false);
}
static std::vector<uint8> GetBrokenEvidenceVector(BigNumber const& bn);
};
class TC_COMMON_API BnetSRP6v1Base : public BnetSRP6Base
{
public:
static BigNumber const N; // the modulus, an algorithm parameter; all operations are mod this
static BigNumber const g; // a [g]enerator for the ring of integers mod N, algorithm parameter
explicit BnetSRP6v1Base(std::string const& username, Salt const& salt, Verifier const& verifier, BigNumber const& k);
explicit BnetSRP6v1Base(ForRegistrationTag t) : BnetSRP6Base(t) { }
BigNumber const& GetN() const final { return N; }
BigNumber const& Getg() const final { return g; }
uint8 GetVersion() const final { return 1; }
uint32 GetXIterations() const final { return 1; }
protected:
BigNumber CalculateX(std::string const& username, std::string const& password, Salt const& salt) const final;
};
class TC_COMMON_API BnetSRP6v2Base : public BnetSRP6Base
{
public:
static BigNumber const N; // the modulus, an algorithm parameter; all operations are mod this
static BigNumber const g; // a [g]enerator for the ring of integers mod N, algorithm parameter
explicit BnetSRP6v2Base(std::string const& username, Salt const& salt, Verifier const& verifier, BigNumber const& k);
explicit BnetSRP6v2Base(ForRegistrationTag t) : BnetSRP6Base(t) { }
BigNumber const& GetN() const final { return N; }
BigNumber const& Getg() const final { return g; }
uint8 GetVersion() const final { return 2; }
uint32 GetXIterations() const final { return 15000; }
protected:
BigNumber CalculateX(std::string const& username, std::string const& password, Salt const& salt) const final;
};
template<typename CryptoHash>
class BnetSRP6v1 final : public BnetSRP6v1Base
{
public:
BnetSRP6v1(std::string const& username, Salt const& salt, Verifier const& verifier)
: BnetSRP6v1Base(username, salt, verifier, BigNumber(CryptoHash::GetDigestOf(N.ToByteArray<128>(false), g.ToByteArray<128>(false)), false))
{
}
explicit BnetSRP6v1(ForRegistrationTag t) : BnetSRP6v1Base(t) { }
protected:
BigNumber CalculateU(BigNumber const& A) const override
{
return BigNumber(CryptoHash::GetDigestOf(A.ToByteArray<128>(false), B.ToByteArray<128>(false)), false);
}
BigNumber DoCalculateEvidence(std::span<BigNumber const*> bns) const override
{
return BnetSRP6Base::DoCalculateEvidence<CryptoHash>(bns);
}
};
template<typename CryptoHash>
class BnetSRP6v2 final : public BnetSRP6v2Base
{
public:
BnetSRP6v2(std::string const& username, Salt const& salt, Verifier const& verifier)
: BnetSRP6v2Base(username, salt, verifier, BigNumber(CryptoHash::GetDigestOf(N.ToByteArray<256>(false), g.ToByteArray<256>(false)), false))
{
}
explicit BnetSRP6v2(ForRegistrationTag t) : BnetSRP6v2Base(t) { }
protected:
BigNumber CalculateU(BigNumber const& A) const override
{
return BigNumber(CryptoHash::GetDigestOf(A.ToByteArray<256>(false), B.ToByteArray<256>(false)), false);
}
BigNumber DoCalculateEvidence(std::span<BigNumber const*> bns) const override
{
return BnetSRP6Base::DoCalculateEvidence<CryptoHash>(bns);
}
};
}
using SRP::SRP6;
}
#endif
|