TrinityCore
SRP6.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include "SRP6.h"
19#include "CryptoRandom.h"
20#include <algorithm>
21#include <functional>
22
24{
25using namespace std::string_literals;
26
27BigNumber const GruntSRP6::N = "894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7"s;
28BigNumber const GruntSRP6::g = 7;
29
30BigNumber const BnetSRP6v1Base::N = "86A7F6DEEB306CE519770FE37D556F29944132554DED0BD68205E27F3231FEF5A10108238A3150C59CAF7B0B6478691C13A6ACF5E1B5ADAFD4A943D4A21A142B800E8A55F8BFBAC700EB77A7235EE5A609E350EA9FC19F10D921C2FA832E4461B7125D38D254A0BE873DFC27858ACB3F8B9F258461E4373BC3A6C2A9634324AB"s;
32
33BigNumber const BnetSRP6v2Base::N = "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F9E4AFF73"s;
35
36SRP6::SRP6(BigNumber const& i, Salt const& salt, Verifier const& verifier, BigNumber const& N, BigNumber const& g, BigNumber const& k)
37 : s(salt), I(i), b(CalculatePrivateB(N)), v(verifier), B(CalculatePublicB(N, g, k))
38{
39}
40
42 : s(GetRandomBytes<SALT_LENGTH>()), _used(true)
43{
44}
45
47{
48 ASSERT(!_used, "A single SRP6 object must only ever be used to verify ONCE!");
49 _used = true;
50
51 return DoVerifyClientEvidence(A, clientM1);
52}
53
54bool SRP6::CheckCredentials(std::string const& username, std::string const& password) const
55{
56 return v == CalculateVerifier(username, password, s);
57}
58
60{
62 b.SetRand(N.GetNumBits());
63 b %= N - 1;
64 return b;
65}
66
68{
69 return (g.ModExp(b, N) + (v * k)) % N;
70}
71
72Verifier SRP6::CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt) const
73{
74 // v = g ^ H(s || H(u || ':' || p)) mod N
75 return Getg().ModExp(
76 CalculateX(username, password, salt),
77 GetN()
78 ).ToByteVector();
79}
80
81GruntSRP6::GruntSRP6(std::string const& username, Salt const& salt, Verifier const& verifier)
82 : SRP6(SHA1::GetDigestOf(username), salt, verifier, N, g, 3)
83{
84}
85
87{
89}
90
91BigNumber GruntSRP6::CalculateX(std::string const& username, std::string const& password, Salt const& salt) const
92{
93 return SHA1::GetDigestOf(
94 salt,
95 SHA1::GetDigestOf(username, ":", password)
96 );
97}
98
100{
101 if ((A % N).IsZero())
102 return {};
103
105 EphemeralKey const S = (A * (v.ModExp(u, N))).ModExp(b, N).ToByteArray<EPHEMERAL_KEY_LENGTH>();
106
108
109 // NgHash = H(N) xor H(g)
110 SHA1::Digest const NHash = SHA1::GetDigestOf(N.ToByteArray<32>());
111 SHA1::Digest const gHash = SHA1::GetDigestOf(g.ToByteArray<1>());
112 SHA1::Digest NgHash;
113 std::transform(NHash.begin(), NHash.end(), gHash.begin(), NgHash.begin(), std::bit_xor<>());
114
116 if (ourM == clientM1)
117 return K;
118
119 return {};
120}
121
123{
124 // split S into two buffers
125 std::array<uint8, EPHEMERAL_KEY_LENGTH / 2> buf0, buf1;
126 for (size_t i = 0; i < S.size() / 2; ++i)
127 {
128 buf0[i] = S[2 * i + 0];
129 buf1[i] = S[2 * i + 1];
130 }
131
132 // find position of first nonzero byte
133 size_t p = 0;
134 while (p < S.size() && !S[p]) ++p;
135 if (p & 1) ++p; // skip one extra byte if p is odd
136 p /= 2; // offset into buffers
137
138 // hash each of the halves, starting at the first nonzero byte
139 SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, S.size() / 2 - p);
140 SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, S.size() / 2 - p);
141
142 // stick the two hashes back together
143 SessionKey K;
144 for (size_t i = 0; i < SHA1::DIGEST_LENGTH; ++i)
145 {
146 K[2 * i + 0] = hash0[i];
147 K[2 * i + 1] = hash1[i];
148 }
149 return K;
150}
151
152BnetSRP6Base::BnetSRP6Base(BigNumber const& i, Salt const& salt, Verifier const& verifier, BigNumber const& N, BigNumber const& g, BigNumber const& k)
153 : SRP6(i, salt, verifier, N, g, k)
154{
155}
156
158{
159 std::array evidenceBns{ &A, &clientM1, &K };
160 return DoCalculateEvidence(evidenceBns);
161}
162
164{
165 BigNumber N = GetN();
166 if ((A % N).IsZero())
167 return {};
168
169 BigNumber const u = CalculateU(A);
170 if ((u % N).IsZero())
171 return {};
172
173 BigNumber const S = (A * v.ModExp(u, N)).ModExp(b, N);
174
175 std::array evidenceBns{ &A, &B, &S };
176 BigNumber const ourM = DoCalculateEvidence(evidenceBns);
177 if (ourM != clientM1)
178 return {};
179
180 return S;
181}
182
184{
185 int32 bytes = (bn.GetNumBits() + 8) >> 3;
186 return bn.ToByteVector(bytes, false);
187}
188
189BnetSRP6v1Base::BnetSRP6v1Base(std::string const& username, Salt const& salt, Verifier const& verifier, BigNumber const& k)
190 : BnetSRP6Base(SHA256::GetDigestOf(username), salt, verifier, N, g, k)
191{
192}
193
194BigNumber BnetSRP6v1Base::CalculateX(std::string const& username, std::string const& password, Salt const& salt) const
195{
196 return SHA256::GetDigestOf(
197 salt,
198 SHA256::GetDigestOf(username, ":", password)
199 );
200}
201
202BnetSRP6v2Base::BnetSRP6v2Base(std::string const& username, Salt const& salt, Verifier const& verifier, BigNumber const& k)
203 : BnetSRP6Base(SHA256::GetDigestOf(username), salt, verifier, N, g, k)
204{
205}
206
207BigNumber BnetSRP6v2Base::CalculateX(std::string const& username, std::string const& password, Salt const& salt) const
208{
209 SHA512::Digest xBytes = {};
210 std::string tmp = username + ":" + password;
211 PKCS5_PBKDF2_HMAC(tmp.c_str(), tmp.length(), salt.data(), salt.size(), GetXIterations(), EVP_sha512(), xBytes.size(), xBytes.data());
212 BigNumber x(xBytes, false);
213 if (xBytes[0] & 0x80)
214 {
215 std::array<uint8, 65> fix = {};
216 fix[64] = 1;
217 x -= fix;
218 }
219
220 return x % (N - 1);
221}
222}
uint8_t uint8
Definition: Define.h:144
int32_t int32
Definition: Define.h:138
#define ASSERT
Definition: Errors.h:68
std::optional< T > Optional
Optional helper class to wrap optional values within.
Definition: Optional.h:25
BigNumber ModExp(BigNumber const &bn1, BigNumber const &bn2) const
Definition: BigNumber.cpp:152
std::vector< uint8 > ToByteVector(int32 minSize=0, bool littleEndian=true) const
Definition: BigNumber.cpp:195
std::array< uint8, Size > ToByteArray(bool littleEndian=true) const
Definition: BigNumber.h:128
void SetRand(int32 numbits)
Definition: BigNumber.cpp:70
int32 GetNumBits() const
Definition: BigNumber.cpp:169
static std::vector< uint8 > GetBrokenEvidenceVector(BigNumber const &bn)
Definition: SRP6.cpp:183
BigNumber CalculateServerEvidence(BigNumber const &A, BigNumber const &clientM1, BigNumber const &K) const final
Definition: SRP6.cpp:157
Optional< BigNumber > DoVerifyClientEvidence(BigNumber const &A, BigNumber const &clientM1) final
Definition: SRP6.cpp:163
BnetSRP6Base(BigNumber const &i, Salt const &salt, Verifier const &verifier, BigNumber const &N, BigNumber const &g, BigNumber const &k)
Definition: SRP6.cpp:152
virtual BigNumber CalculateU(BigNumber const &A) const =0
virtual BigNumber DoCalculateEvidence(std::span< BigNumber const * > bns) const =0
static BigNumber const g
Definition: SRP6.h:157
BigNumber CalculateX(std::string const &username, std::string const &password, Salt const &salt) const final
Definition: SRP6.cpp:194
BnetSRP6v1Base(std::string const &username, Salt const &salt, Verifier const &verifier, BigNumber const &k)
Definition: SRP6.cpp:189
static BigNumber const N
Definition: SRP6.h:156
BigNumber CalculateX(std::string const &username, std::string const &password, Salt const &salt) const final
Definition: SRP6.cpp:207
static BigNumber const N
Definition: SRP6.h:175
BnetSRP6v2Base(std::string const &username, Salt const &salt, Verifier const &verifier, BigNumber const &k)
Definition: SRP6.cpp:202
static BigNumber const g
Definition: SRP6.h:176
uint32 GetXIterations() const final
Definition: SRP6.h:185
Optional< BigNumber > DoVerifyClientEvidence(BigNumber const &A, BigNumber const &clientM1) override
Definition: SRP6.cpp:99
static BigNumber const g
Definition: SRP6.h:103
std::array< uint8, EPHEMERAL_KEY_LENGTH > EphemeralKey
Definition: SRP6.h:98
BigNumber CalculateServerEvidence(BigNumber const &A, BigNumber const &clientM1, BigNumber const &K) const override
Definition: SRP6.cpp:86
static SessionKey SHA1Interleave(EphemeralKey const &S)
Definition: SRP6.cpp:122
static BigNumber const N
Definition: SRP6.h:102
BigNumber CalculateX(std::string const &username, std::string const &password, Salt const &salt) const override
Definition: SRP6.cpp:91
static constexpr size_t EPHEMERAL_KEY_LENGTH
Definition: SRP6.h:96
GruntSRP6(std::string const &username, Salt const &salt, Verifier const &verifier)
Definition: SRP6.cpp:81
std::array< uint8, SHA1::DIGEST_LENGTH *2 > SessionKey
Definition: SRP6.h:100
BigNumber const I
Definition: SRP6.h:82
static BigNumber CalculatePrivateB(BigNumber const &N)
Definition: SRP6.cpp:59
Optional< BigNumber > VerifyClientEvidence(BigNumber const &A, BigNumber const &clientM1)
Definition: SRP6.cpp:46
SRP6(BigNumber const &i, Salt const &salt, Verifier const &verifier, BigNumber const &N, BigNumber const &g, BigNumber const &k)
Definition: SRP6.cpp:36
virtual BigNumber const & Getg() const =0
virtual Optional< BigNumber > DoVerifyClientEvidence(BigNumber const &A, BigNumber const &clientM1)=0
virtual BigNumber CalculateX(std::string const &username, std::string const &password, Salt const &salt) const =0
virtual BigNumber const & GetN() const =0
BigNumber const v
Definition: SRP6.h:84
BigNumber CalculatePublicB(BigNumber const &N, BigNumber const &g, BigNumber const &k) const
Definition: SRP6.cpp:67
Verifier CalculateVerifier(std::string const &username, std::string const &password, Salt const &salt) const
Definition: SRP6.cpp:72
bool CheckCredentials(std::string const &username, std::string const &password) const
Definition: SRP6.cpp:54
BigNumber const b
Definition: SRP6.h:83
BigNumber const B
Definition: SRP6.h:87
std::array< uint8, DIGEST_LENGTH > Digest
Definition: CryptoHash.h:47
static constexpr size_t DIGEST_LENGTH
Definition: CryptoHash.h:46
static Digest GetDigestOf(uint8 const *data, size_t len)
Definition: CryptoHash.h:49
std::array< uint8, SALT_LENGTH > Salt
Definition: SRP6.h:33
std::vector< uint8 > Verifier
Definition: SRP6.h:35
static constexpr size_t SALT_LENGTH
Definition: SRP6.h:32
void TC_COMMON_API GetRandomBytes(uint8 *buf, size_t len)