TrinityCore
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 "Util.h"
21#include <algorithm>
22#include <functional>
23
26
27/*static*/ std::array<uint8, 1> const SRP6::g = { 7 };
28/*static*/ std::array<uint8, 32> const SRP6::N = HexStrToByteArray<32>("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", true);
29/*static*/ BigNumber const SRP6::_g(SRP6::g);
30/*static*/ BigNumber const SRP6::_N(N);
31
32/*static*/ std::pair<SRP6::Salt, SRP6::Verifier> SRP6::MakeRegistrationData(std::string const& username, std::string const& password)
33{
34 std::pair<SRP6::Salt, SRP6::Verifier> res;
35 Crypto::GetRandomBytes(res.first); // random salt
36 res.second = CalculateVerifier(username, password, res.first);
37 return res;
38}
39
40/*static*/ SRP6::Verifier SRP6::CalculateVerifier(std::string const& username, std::string const& password, SRP6::Salt const& salt)
41{
42 // v = g ^ H(s || H(u || ':' || p)) mod N
43 return _g.ModExp(
45 salt,
46 SHA1::GetDigestOf(username, ":", password)
47 )
48 ,_N).ToByteArray<32>();
49}
50
52{
53 // split S into two buffers
54 std::array<uint8, EPHEMERAL_KEY_LENGTH/2> buf0, buf1;
55 for (size_t i = 0; i < EPHEMERAL_KEY_LENGTH/2; ++i)
56 {
57 buf0[i] = S[2 * i + 0];
58 buf1[i] = S[2 * i + 1];
59 }
60
61 // find position of first nonzero byte
62 size_t p = 0;
63 while (p < EPHEMERAL_KEY_LENGTH && !S[p]) ++p;
64 if (p & 1) ++p; // skip one extra byte if p is odd
65 p /= 2; // offset into buffers
66
67 // hash each of the halves, starting at the first nonzero byte
68 SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
69 SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
70
71 // stick the two hashes back together
72 SessionKey K;
73 for (size_t i = 0; i < SHA1::DIGEST_LENGTH; ++i)
74 {
75 K[2 * i + 0] = hash0[i];
76 K[2 * i + 1] = hash1[i];
77 }
78 return K;
79}
80
81SRP6::SRP6(std::string const& username, Salt const& salt, Verifier const& verifier)
82 : _I(SHA1::GetDigestOf(username)), _b(Crypto::GetRandomBytes<32>()), _v(verifier), s(salt), B(_B(_b, _v)) {}
83
84std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM)
85{
86 ASSERT(!_used, "A single SRP6 object must only ever be used to verify ONCE!");
87 _used = true;
88
89 BigNumber const _A(A);
90 if ((_A % _N).IsZero())
91 return std::nullopt;
92
93 BigNumber const u(SHA1::GetDigestOf(A, B));
94 EphemeralKey const S = (_A * (_v.ModExp(u, _N))).ModExp(_b, N).ToByteArray<32>();
95
97
98 // NgHash = H(N) xor H(g)
99 SHA1::Digest const NHash = SHA1::GetDigestOf(N);
100 SHA1::Digest const gHash = SHA1::GetDigestOf(g);
101 SHA1::Digest NgHash;
102 std::transform(NHash.begin(), NHash.end(), gHash.begin(), NgHash.begin(), std::bit_xor<>());
103
104 SHA1::Digest const ourM = SHA1::GetDigestOf(NgHash, _I, s, A, B, K);
105 if (ourM == clientM)
106 return K;
107 else
108 return std::nullopt;
109}
std::array< uint8, SESSION_KEY_LENGTH > SessionKey
Definition: AuthDefines.h:25
uint8_t uint8
Definition: Define.h:135
#define ASSERT
Definition: Errors.h:68
Trinity::Crypto::SRP6 SRP6
Definition: SRP6.cpp:25
BigNumber ModExp(BigNumber const &bn1, BigNumber const &bn2) const
Definition: BigNumber.cpp:153
std::array< uint8, Size > ToByteArray(bool littleEndian=true) const
Definition: BigNumber.h:126
static Verifier CalculateVerifier(std::string const &username, std::string const &password, Salt const &salt)
Definition: SRP6.cpp:40
std::optional< SessionKey > VerifyChallengeResponse(EphemeralKey const &A, SHA1::Digest const &clientM)
Definition: SRP6.cpp:84
EphemeralKey const B
Definition: SRP6.h:79
BigNumber const _b
Definition: SRP6.h:74
static SessionKey SHA1Interleave(EphemeralKey const &S)
Definition: SRP6.cpp:51
static std::array< uint8, 32 > const N
Definition: SRP6.h:42
Salt const s
Definition: SRP6.h:78
static BigNumber const _N
Definition: SRP6.h:68
std::array< uint8, SALT_LENGTH > Salt
Definition: SRP6.h:35
std::array< uint8, EPHEMERAL_KEY_LENGTH > EphemeralKey
Definition: SRP6.h:39
SRP6(std::string const &username, Salt const &salt, Verifier const &verifier)
Definition: SRP6.cpp:81
static std::pair< Salt, Verifier > MakeRegistrationData(std::string const &username, std::string const &password)
Definition: SRP6.cpp:32
BigNumber const _v
Definition: SRP6.h:75
static std::array< uint8, 1 > const g
Definition: SRP6.h:41
std::array< uint8, VERIFIER_LENGTH > Verifier
Definition: SRP6.h:37
static constexpr size_t EPHEMERAL_KEY_LENGTH
Definition: SRP6.h:38
static BigNumber const _g
Definition: SRP6.h:67
SHA1::Digest const _I
Definition: SRP6.h:73
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
Trinity::Impl::GenericHash< EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES > SHA1
Definition: CryptoHash.h:141
void TC_COMMON_API GetRandomBytes(uint8 *buf, size_t len)