mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-26 23:26:23 +00:00
feat(Core/DB/Authserver): remove sha_pass_hash (#4827)
This commit is contained in:
@@ -5,36 +5,34 @@
|
||||
*/
|
||||
|
||||
#include "ARC4.h"
|
||||
#include <openssl/sha.h>
|
||||
#include "Errors.h"
|
||||
|
||||
ARC4::ARC4(uint32 len) : m_ctx(EVP_CIPHER_CTX_new())
|
||||
acore::Crypto::ARC4::ARC4()
|
||||
: _ctx(EVP_CIPHER_CTX_new())
|
||||
{
|
||||
EVP_CIPHER_CTX_init(m_ctx);
|
||||
EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
|
||||
EVP_CIPHER_CTX_set_key_length(m_ctx, len);
|
||||
EVP_CIPHER_CTX_init(_ctx);
|
||||
int result = EVP_EncryptInit_ex(_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
|
||||
ARC4::ARC4(uint8* seed, uint32 len) : m_ctx(EVP_CIPHER_CTX_new())
|
||||
acore::Crypto::ARC4::~ARC4()
|
||||
{
|
||||
EVP_CIPHER_CTX_init(m_ctx);
|
||||
EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
|
||||
EVP_CIPHER_CTX_set_key_length(m_ctx, len);
|
||||
EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr);
|
||||
EVP_CIPHER_CTX_free(_ctx);
|
||||
}
|
||||
|
||||
ARC4::~ARC4()
|
||||
void acore::Crypto::ARC4::Init(uint8 const* seed, size_t len)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(m_ctx);
|
||||
int result1 = EVP_CIPHER_CTX_set_key_length(_ctx, len);
|
||||
ASSERT(result1 == 1);
|
||||
int result2 = EVP_EncryptInit_ex(_ctx, nullptr, nullptr, seed, nullptr);
|
||||
ASSERT(result2 == 1);
|
||||
}
|
||||
|
||||
void ARC4::Init(uint8* seed)
|
||||
{
|
||||
EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr);
|
||||
}
|
||||
|
||||
void ARC4::UpdateData(int len, uint8* data)
|
||||
void acore::Crypto::ARC4::UpdateData(uint8* data, size_t len)
|
||||
{
|
||||
int outlen = 0;
|
||||
EVP_EncryptUpdate(m_ctx, data, &outlen, data, len);
|
||||
EVP_EncryptFinal_ex(m_ctx, data, &outlen);
|
||||
int result1 = EVP_EncryptUpdate(_ctx, data, &outlen, data, len);
|
||||
ASSERT(result1 == 1);
|
||||
int result2 = EVP_EncryptFinal_ex(_ctx, data, &outlen);
|
||||
ASSERT(result2 == 1);
|
||||
}
|
||||
|
||||
@@ -8,18 +8,28 @@
|
||||
#define _AUTH_SARC4_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
#include <array>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
class ARC4
|
||||
namespace acore::Crypto
|
||||
{
|
||||
public:
|
||||
ARC4(uint32 len);
|
||||
ARC4(uint8* seed, uint32 len);
|
||||
~ARC4();
|
||||
void Init(uint8* seed);
|
||||
void UpdateData(int len, uint8* data);
|
||||
private:
|
||||
EVP_CIPHER_CTX* m_ctx;
|
||||
};
|
||||
class ARC4
|
||||
{
|
||||
public:
|
||||
ARC4();
|
||||
~ARC4();
|
||||
|
||||
void Init(uint8 const* seed, size_t len);
|
||||
template <typename Container>
|
||||
void Init(Container const& c) { Init(std::data(c), std::size(c)); }
|
||||
|
||||
void UpdateData(uint8* data, size_t len);
|
||||
template <typename Container>
|
||||
void UpdateData(Container& c) { UpdateData(std::data(c), std::size(c)); }
|
||||
private:
|
||||
EVP_CIPHER_CTX* _ctx;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
15
src/common/Cryptography/AuthDefines.h
Normal file
15
src/common/Cryptography/AuthDefines.h
Normal file
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_AUTHDEFINES_H
|
||||
#define AZEROTHCORE_AUTHDEFINES_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <array>
|
||||
|
||||
constexpr size_t SESSION_KEY_LENGTH = 40;
|
||||
using SessionKey = std::array<uint8, SESSION_KEY_LENGTH>;
|
||||
|
||||
#endif
|
||||
@@ -5,56 +5,37 @@
|
||||
*/
|
||||
|
||||
#include "AuthCrypt.h"
|
||||
#include "Cryptography/HMACSHA1.h"
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Errors.h"
|
||||
#include "HMAC.h"
|
||||
|
||||
AuthCrypt::AuthCrypt() :
|
||||
_clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH),
|
||||
_initialized(false)
|
||||
{ }
|
||||
|
||||
void AuthCrypt::Init(BigNumber* K)
|
||||
AuthCrypt::AuthCrypt() : _initialized(false)
|
||||
{
|
||||
uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 };
|
||||
HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey);
|
||||
uint8* encryptHash = serverEncryptHmac.ComputeHash(K);
|
||||
}
|
||||
|
||||
uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE };
|
||||
HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey);
|
||||
uint8* decryptHash = clientDecryptHmac.ComputeHash(K);
|
||||
|
||||
//ARC4 _serverDecrypt(encryptHash);
|
||||
_clientDecrypt.Init(decryptHash);
|
||||
_serverEncrypt.Init(encryptHash);
|
||||
//ARC4 _clientEncrypt(decryptHash);
|
||||
void AuthCrypt::Init(SessionKey const& K)
|
||||
{
|
||||
uint8 ServerEncryptionKey[] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 };
|
||||
_serverEncrypt.Init(acore::Crypto::HMAC_SHA1::GetDigestOf(ServerEncryptionKey, K));
|
||||
uint8 ServerDecryptionKey[] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE };
|
||||
_clientDecrypt.Init(acore::Crypto::HMAC_SHA1::GetDigestOf(ServerDecryptionKey, K));
|
||||
|
||||
// Drop first 1024 bytes, as WoW uses ARC4-drop1024.
|
||||
uint8 syncBuf[1024];
|
||||
memset(syncBuf, 0, 1024);
|
||||
|
||||
_serverEncrypt.UpdateData(1024, syncBuf);
|
||||
//_clientEncrypt.UpdateData(1024, syncBuf);
|
||||
|
||||
memset(syncBuf, 0, 1024);
|
||||
|
||||
//_serverDecrypt.UpdateData(1024, syncBuf);
|
||||
_clientDecrypt.UpdateData(1024, syncBuf);
|
||||
std::array<uint8, 1024> syncBuf;
|
||||
_serverEncrypt.UpdateData(syncBuf);
|
||||
_clientDecrypt.UpdateData(syncBuf);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
void AuthCrypt::DecryptRecv(uint8* data, size_t len)
|
||||
{
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
_clientDecrypt.UpdateData(len, data);
|
||||
ASSERT(_initialized);
|
||||
_clientDecrypt.UpdateData(data, len);
|
||||
}
|
||||
|
||||
void AuthCrypt::EncryptSend(uint8* data, size_t len)
|
||||
{
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
_serverEncrypt.UpdateData(len, data);
|
||||
ASSERT(_initialized);
|
||||
_serverEncrypt.UpdateData(data, len);
|
||||
}
|
||||
|
||||
@@ -7,24 +7,24 @@
|
||||
#ifndef _AUTHCRYPT_H
|
||||
#define _AUTHCRYPT_H
|
||||
|
||||
#include "Cryptography/ARC4.h"
|
||||
|
||||
class BigNumber;
|
||||
#include "ARC4.h"
|
||||
#include "AuthDefines.h"
|
||||
#include <array>
|
||||
|
||||
class AuthCrypt
|
||||
{
|
||||
public:
|
||||
AuthCrypt();
|
||||
|
||||
void Init(BigNumber* K);
|
||||
void DecryptRecv(uint8*, size_t);
|
||||
void EncryptSend(uint8*, size_t);
|
||||
void Init(SessionKey const& K);
|
||||
void DecryptRecv(uint8* data, size_t len);
|
||||
void EncryptSend(uint8* data, size_t len);
|
||||
|
||||
bool IsInitialized() const { return _initialized; }
|
||||
|
||||
private:
|
||||
ARC4 _clientDecrypt;
|
||||
ARC4 _serverEncrypt;
|
||||
acore::Crypto::ARC4 _clientDecrypt;
|
||||
acore::Crypto::ARC4 _serverEncrypt;
|
||||
bool _initialized;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -11,16 +11,12 @@
|
||||
|
||||
BigNumber::BigNumber()
|
||||
: _bn(BN_new())
|
||||
{ }
|
||||
{
|
||||
}
|
||||
|
||||
BigNumber::BigNumber(BigNumber const& bn)
|
||||
: _bn(BN_dup(bn._bn))
|
||||
{ }
|
||||
|
||||
BigNumber::BigNumber(uint32 val)
|
||||
: _bn(BN_new())
|
||||
: _bn(BN_dup(bn.BN()))
|
||||
{
|
||||
BN_set_word(_bn, val);
|
||||
}
|
||||
|
||||
BigNumber::~BigNumber()
|
||||
@@ -28,6 +24,13 @@ BigNumber::~BigNumber()
|
||||
BN_free(_bn);
|
||||
}
|
||||
|
||||
void BigNumber::SetDword(int32 val)
|
||||
{
|
||||
SetDword(uint32(abs(val)));
|
||||
if (val < 0)
|
||||
BN_set_negative(_bn, 1);
|
||||
}
|
||||
|
||||
void BigNumber::SetDword(uint32 val)
|
||||
{
|
||||
BN_set_word(_bn, val);
|
||||
@@ -40,16 +43,25 @@ void BigNumber::SetQword(uint64 val)
|
||||
BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF));
|
||||
}
|
||||
|
||||
void BigNumber::SetBinary(uint8 const* bytes, int32 len)
|
||||
void BigNumber::SetBinary(uint8 const* bytes, int32 len, bool littleEndian)
|
||||
{
|
||||
uint8* array = new uint8[len];
|
||||
if (littleEndian)
|
||||
{
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
uint8* array = new uint8[len];
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = bytes[len - 1 - i];
|
||||
for (int i = 0; i < len; i++)
|
||||
array[i] = bytes[len - 1 - i];
|
||||
|
||||
BN_bin2bn(array, len, _bn);
|
||||
BN_bin2bn(array, len, _bn);
|
||||
|
||||
delete[] array;
|
||||
delete[] array;
|
||||
#else
|
||||
BN_lebin2bn(bytes, len, _bn);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
BN_bin2bn(bytes, len, _bn);
|
||||
}
|
||||
|
||||
void BigNumber::SetHexStr(char const* str)
|
||||
@@ -116,7 +128,7 @@ BigNumber BigNumber::operator%=(BigNumber const& bn)
|
||||
return *this;
|
||||
}
|
||||
|
||||
BigNumber BigNumber::Exp(BigNumber const& bn)
|
||||
BigNumber BigNumber::Exp(BigNumber const& bn) const
|
||||
{
|
||||
BigNumber ret;
|
||||
BN_CTX* bnctx;
|
||||
@@ -128,7 +140,7 @@ BigNumber BigNumber::Exp(BigNumber const& bn)
|
||||
return ret;
|
||||
}
|
||||
|
||||
BigNumber BigNumber::ModExp(BigNumber const& bn1, BigNumber const& bn2)
|
||||
BigNumber BigNumber::ModExp(BigNumber const& bn1, BigNumber const& bn2) const
|
||||
{
|
||||
BigNumber ret;
|
||||
BN_CTX* bnctx;
|
||||
@@ -140,7 +152,7 @@ BigNumber BigNumber::ModExp(BigNumber const& bn1, BigNumber const& bn2)
|
||||
return ret;
|
||||
}
|
||||
|
||||
int32 BigNumber::GetNumBytes(void)
|
||||
int32 BigNumber::GetNumBytes() const
|
||||
{
|
||||
return BN_num_bytes(_bn);
|
||||
}
|
||||
@@ -155,25 +167,38 @@ bool BigNumber::isZero() const
|
||||
return BN_is_zero(_bn);
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian)
|
||||
void BigNumber::GetBytes(uint8* buf, size_t bufsize, bool littleEndian) const
|
||||
{
|
||||
int numBytes = GetNumBytes();
|
||||
int length = (minSize >= numBytes) ? minSize : numBytes;
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
int nBytes = GetNumBytes();
|
||||
ASSERT(nBytes >= 0, "Bignum has negative number of bytes (%d).", nBytes);
|
||||
std::size_t numBytes = static_cast<std::size_t>(nBytes);
|
||||
|
||||
uint8* array = new uint8[length];
|
||||
// too large to store
|
||||
ASSERT(numBytes <= bufsize, "Buffer of size %zu is too small to hold bignum with %zu bytes.\n", bufsize, numBytes);
|
||||
|
||||
// If we need more bytes than length of BigNumber set the rest to 0
|
||||
if (length > numBytes)
|
||||
memset((void*)array, 0, length);
|
||||
if (numBytes < bufsize)
|
||||
memset((void*)buf, 0, bufsize);
|
||||
|
||||
BN_bn2bin(_bn, (unsigned char*)array);
|
||||
BN_bn2bin(_bn, buf + (bufsize - numBytes));
|
||||
|
||||
// openssl's BN stores data internally in big endian format, reverse if little endian desired
|
||||
if (littleEndian)
|
||||
std::reverse(array, array + length);
|
||||
std::reverse(buf, buf + bufsize);
|
||||
#else
|
||||
int res = littleEndian ? BN_bn2lebinpad(_bn, buf, bufsize) : BN_bn2binpad(_bn, buf, bufsize);
|
||||
ASSERT(res > 0, "Buffer of size %zu is too small to hold bignum with %d bytes.\n", bufsize, BN_num_bytes(_bn));
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8[]> ret(array);
|
||||
return ret;
|
||||
std::vector<uint8> BigNumber::ToByteVector(int32 minSize, bool littleEndian) const
|
||||
{
|
||||
std::size_t length = std::max(GetNumBytes(), minSize);
|
||||
std::vector<uint8> v;
|
||||
v.resize(length);
|
||||
GetBytes(v.data(), length, littleEndian);
|
||||
return v;
|
||||
}
|
||||
|
||||
char* BigNumber::AsHexStr() const
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct bignum_st;
|
||||
|
||||
@@ -20,48 +21,57 @@ class BigNumber
|
||||
public:
|
||||
BigNumber();
|
||||
BigNumber(BigNumber const& bn);
|
||||
BigNumber(uint32);
|
||||
BigNumber(uint32 v) : BigNumber() { SetDword(v); }
|
||||
BigNumber(int32 v) : BigNumber() { SetDword(v); }
|
||||
BigNumber(std::string const& v) : BigNumber() { SetHexStr(v); }
|
||||
template<size_t Size>
|
||||
BigNumber(std::array<uint8, Size> const& v, bool littleEndian = true) : BigNumber() { SetBinary(v.data(), Size, littleEndian); }
|
||||
|
||||
~BigNumber();
|
||||
|
||||
void SetDword(int32);
|
||||
void SetDword(uint32);
|
||||
void SetQword(uint64);
|
||||
void SetBinary(uint8 const* bytes, int32 len);
|
||||
void SetBinary(uint8 const* bytes, int32 len, bool littleEndian = true);
|
||||
template<typename Container>
|
||||
auto SetBinary(Container const& c, bool littleEndian = true) -> std::enable_if_t<!std::is_pointer_v<std::decay_t<Container>>> { SetBinary(std::data(c), std::size(c), littleEndian); }
|
||||
void SetHexStr(char const* str);
|
||||
void SetHexStr(std::string const& str) { SetHexStr(str.c_str()); }
|
||||
|
||||
void SetRand(int32 numbits);
|
||||
|
||||
BigNumber& operator=(BigNumber const& bn);
|
||||
|
||||
BigNumber operator+=(BigNumber const& bn);
|
||||
BigNumber operator+(BigNumber const& bn)
|
||||
BigNumber operator+(BigNumber const& bn) const
|
||||
{
|
||||
BigNumber t(*this);
|
||||
return t += bn;
|
||||
}
|
||||
|
||||
BigNumber operator-=(BigNumber const& bn);
|
||||
BigNumber operator-(BigNumber const& bn)
|
||||
BigNumber operator-(BigNumber const& bn) const
|
||||
{
|
||||
BigNumber t(*this);
|
||||
return t -= bn;
|
||||
}
|
||||
|
||||
BigNumber operator*=(BigNumber const& bn);
|
||||
BigNumber operator*(BigNumber const& bn)
|
||||
BigNumber operator*(BigNumber const& bn) const
|
||||
{
|
||||
BigNumber t(*this);
|
||||
return t *= bn;
|
||||
}
|
||||
|
||||
BigNumber operator/=(BigNumber const& bn);
|
||||
BigNumber operator/(BigNumber const& bn)
|
||||
BigNumber operator/(BigNumber const& bn) const
|
||||
{
|
||||
BigNumber t(*this);
|
||||
return t /= bn;
|
||||
}
|
||||
|
||||
BigNumber operator%=(BigNumber const& bn);
|
||||
BigNumber operator%(BigNumber const& bn)
|
||||
BigNumber operator%(BigNumber const& bn) const
|
||||
{
|
||||
BigNumber t(*this);
|
||||
return t %= bn;
|
||||
@@ -69,16 +79,26 @@ public:
|
||||
|
||||
[[nodiscard]] bool isZero() const;
|
||||
|
||||
BigNumber ModExp(BigNumber const& bn1, BigNumber const& bn2);
|
||||
BigNumber Exp(BigNumber const&);
|
||||
BigNumber ModExp(BigNumber const& bn1, BigNumber const& bn2) const;
|
||||
BigNumber Exp(BigNumber const&) const;
|
||||
|
||||
int32 GetNumBytes();
|
||||
int32 GetNumBytes() const;
|
||||
|
||||
struct bignum_st* BN() { return _bn; }
|
||||
struct bignum_st const* BN() const { return _bn; }
|
||||
|
||||
uint32 AsDword();
|
||||
|
||||
std::unique_ptr<uint8[]> AsByteArray(int32 minSize = 0, bool littleEndian = true);
|
||||
void GetBytes(uint8* buf, size_t bufsize, bool littleEndian = true) const;
|
||||
std::vector<uint8> ToByteVector(int32 minSize = 0, bool littleEndian = true) const;
|
||||
|
||||
template<std::size_t Size>
|
||||
std::array<uint8, Size> ToByteArray(bool littleEndian = true) const
|
||||
{
|
||||
std::array<uint8, Size> buf;
|
||||
GetBytes(buf.data(), Size, littleEndian);
|
||||
return buf;
|
||||
}
|
||||
|
||||
[[nodiscard]] char* AsHexStr() const;
|
||||
[[nodiscard]] char* AsDecStr() const;
|
||||
|
||||
20
src/common/Cryptography/CryptoConstants.h
Normal file
20
src/common/Cryptography/CryptoConstants.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_CRYPTO_CONSTANTS_H
|
||||
#define AZEROTHCORE_CRYPTO_CONSTANTS_H
|
||||
|
||||
#include "Define.h"
|
||||
|
||||
namespace acore::Crypto
|
||||
{
|
||||
struct Constants
|
||||
{
|
||||
static constexpr size_t SHA1_DIGEST_LENGTH_BYTES = 20;
|
||||
static constexpr size_t SHA256_DIGEST_LENGTH_BYTES = 32;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
99
src/common/Cryptography/CryptoGenerics.h
Normal file
99
src/common/Cryptography/CryptoGenerics.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_CRYPTO_GENERICS_HPP
|
||||
#define AZEROTHCORE_CRYPTO_GENERICS_HPP
|
||||
|
||||
#include "BigNumber.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
|
||||
namespace acore::Impl
|
||||
{
|
||||
struct CryptoGenericsImpl
|
||||
{
|
||||
template <typename Cipher>
|
||||
static typename Cipher::IV GenerateRandomIV()
|
||||
{
|
||||
typename Cipher::IV iv;
|
||||
acore::Crypto::GetRandomBytes(iv);
|
||||
return iv;
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
static void AppendToBack(std::vector<uint8>& data, Container const& tail)
|
||||
{
|
||||
data.insert(data.end(), std::begin(tail), std::end(tail));
|
||||
}
|
||||
|
||||
template <typename Container>
|
||||
static void SplitFromBack(std::vector<uint8>& data, Container& tail)
|
||||
{
|
||||
ASSERT(data.size() >= std::size(tail));
|
||||
for (size_t i = 1, N = std::size(tail); i <= N; ++i)
|
||||
{
|
||||
tail[N - i] = data.back();
|
||||
data.pop_back();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace acore::Crypto
|
||||
{
|
||||
template <typename Cipher>
|
||||
void AEEncryptWithRandomIV(std::vector<uint8>& data, typename Cipher::Key const& key)
|
||||
{
|
||||
using IV = typename Cipher::IV;
|
||||
using Tag = typename Cipher::Tag;
|
||||
// select random IV
|
||||
IV iv = acore::Impl::CryptoGenericsImpl::GenerateRandomIV<Cipher>();
|
||||
Tag tag;
|
||||
|
||||
// encrypt data
|
||||
Cipher cipher(true);
|
||||
cipher.Init(key);
|
||||
bool success = cipher.Process(iv, data.data(), data.size(), tag);
|
||||
ASSERT(success);
|
||||
|
||||
// append trailing IV and tag
|
||||
acore::Impl::CryptoGenericsImpl::AppendToBack(data, iv);
|
||||
acore::Impl::CryptoGenericsImpl::AppendToBack(data, tag);
|
||||
}
|
||||
|
||||
template <typename Cipher>
|
||||
void AEEncryptWithRandomIV(std::vector<uint8>& data, BigNumber const& key)
|
||||
{
|
||||
AEEncryptWithRandomIV<Cipher>(data, key.ToByteArray<Cipher::KEY_SIZE_BYTES>());
|
||||
}
|
||||
|
||||
template <typename Cipher>
|
||||
bool AEDecrypt(std::vector<uint8>& data, typename Cipher::Key const& key)
|
||||
{
|
||||
using IV = typename Cipher::IV;
|
||||
using Tag = typename Cipher::Tag;
|
||||
// extract trailing IV and tag
|
||||
IV iv;
|
||||
Tag tag;
|
||||
acore::Impl::CryptoGenericsImpl::SplitFromBack(data, tag);
|
||||
acore::Impl::CryptoGenericsImpl::SplitFromBack(data, iv);
|
||||
|
||||
// decrypt data
|
||||
Cipher cipher(false);
|
||||
cipher.Init(key);
|
||||
return cipher.Process(iv, data.data(), data.size(), tag);
|
||||
}
|
||||
|
||||
template <typename Cipher>
|
||||
bool AEDecrypt(std::vector<uint8>& data, BigNumber const& key)
|
||||
{
|
||||
return AEDecrypt<Cipher>(data, key.ToByteArray<Cipher::KEY_SIZE_BYTES>());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
107
src/common/Cryptography/CryptoHash.h
Normal file
107
src/common/Cryptography/CryptoHash.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_CRYPTOHASH_H
|
||||
#define AZEROTHCORE_CRYPTOHASH_H
|
||||
|
||||
#include "CryptoConstants.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
namespace acore::Impl
|
||||
{
|
||||
struct GenericHashImpl
|
||||
{
|
||||
typedef EVP_MD const* (*HashCreator)();
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
static EVP_MD_CTX* MakeCTX() { return EVP_MD_CTX_create(); }
|
||||
static void DestroyCTX(EVP_MD_CTX* ctx) { EVP_MD_CTX_destroy(ctx); }
|
||||
#else
|
||||
static EVP_MD_CTX* MakeCTX() { return EVP_MD_CTX_new(); }
|
||||
static void DestroyCTX(EVP_MD_CTX* ctx) { EVP_MD_CTX_free(ctx); }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <GenericHashImpl::HashCreator HashCreator, size_t DigestLength>
|
||||
class GenericHash
|
||||
{
|
||||
public:
|
||||
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
||||
|
||||
static Digest GetDigestOf(uint8 const* data, size_t len)
|
||||
{
|
||||
GenericHash hash;
|
||||
hash.UpdateData(data, len);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static auto GetDigestOf(Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
|
||||
{
|
||||
GenericHash hash;
|
||||
(hash.UpdateData(std::forward<Ts>(pack)), ...);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
GenericHash() : _ctx(GenericHashImpl::MakeCTX())
|
||||
{
|
||||
int result = EVP_DigestInit_ex(_ctx, HashCreator(), nullptr);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
|
||||
~GenericHash()
|
||||
{
|
||||
if (!_ctx)
|
||||
return;
|
||||
GenericHashImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
void UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
int result = EVP_DigestUpdate(_ctx, data, len);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
template <typename Container>
|
||||
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
uint32 length;
|
||||
int result = EVP_DigestFinal_ex(_ctx, _digest.data(), &length);
|
||||
ASSERT(result == 1);
|
||||
ASSERT(length == DIGEST_LENGTH);
|
||||
GenericHashImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
Digest const& GetDigest() const { return _digest; }
|
||||
|
||||
private:
|
||||
EVP_MD_CTX* _ctx;
|
||||
Digest _digest = { };
|
||||
};
|
||||
}
|
||||
|
||||
namespace acore::Crypto
|
||||
{
|
||||
using SHA1 = acore::Impl::GenericHash<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
|
||||
using SHA256 = acore::Impl::GenericHash<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
|
||||
}
|
||||
|
||||
#endif
|
||||
14
src/common/Cryptography/CryptoRandom.cpp
Normal file
14
src/common/Cryptography/CryptoRandom.cpp
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#include "CryptoRandom.h"
|
||||
#include "Errors.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
void acore::Crypto::GetRandomBytes(uint8* buf, size_t len)
|
||||
{
|
||||
int result = RAND_bytes(buf, len);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
31
src/common/Cryptography/CryptoRandom.h
Normal file
31
src/common/Cryptography/CryptoRandom.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_CRYPTORANDOM_H
|
||||
#define AZEROTHCORE_CRYPTORANDOM_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <array>
|
||||
|
||||
namespace acore::Crypto
|
||||
{
|
||||
void GetRandomBytes(uint8* buf, size_t len);
|
||||
|
||||
template <typename Container>
|
||||
void GetRandomBytes(Container& c)
|
||||
{
|
||||
GetRandomBytes(std::data(c), std::size(c));
|
||||
}
|
||||
|
||||
template <size_t S>
|
||||
std::array<uint8, S> GetRandomBytes()
|
||||
{
|
||||
std::array<uint8, S> arr;
|
||||
GetRandomBytes(arr);
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
118
src/common/Cryptography/HMAC.h
Normal file
118
src/common/Cryptography/HMAC.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_HMAC_H
|
||||
#define AZEROTHCORE_HMAC_H
|
||||
|
||||
#include "CryptoConstants.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
namespace acore::Impl
|
||||
{
|
||||
struct HMACImpl
|
||||
{
|
||||
typedef EVP_MD const* (*HashCreator)();
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
static HMAC_CTX* MakeCTX()
|
||||
{
|
||||
HMAC_CTX* ctx = new HMAC_CTX();
|
||||
HMAC_CTX_init(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void DestroyCTX(HMAC_CTX* ctx)
|
||||
{
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
delete ctx;
|
||||
}
|
||||
#else
|
||||
static HMAC_CTX* MakeCTX() { return HMAC_CTX_new(); }
|
||||
static void DestroyCTX(HMAC_CTX* ctx) { HMAC_CTX_free(ctx); }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <HMACImpl::HashCreator HashCreator, size_t DigestLength>
|
||||
class GenericHMAC
|
||||
{
|
||||
public:
|
||||
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
||||
|
||||
template <typename Container>
|
||||
static Digest GetDigestOf(Container const& seed, uint8 const* data, size_t len)
|
||||
{
|
||||
GenericHMAC hash(seed);
|
||||
hash.UpdateData(data, len);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
template <typename Container, typename... Ts>
|
||||
static auto GetDigestOf(Container const& seed, Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
|
||||
{
|
||||
GenericHMAC hash(seed);
|
||||
(hash.UpdateData(std::forward<Ts>(pack)), ...);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
GenericHMAC(uint8 const* seed, size_t len) : _ctx(HMACImpl::MakeCTX())
|
||||
{
|
||||
int result = HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
template <typename Container>
|
||||
GenericHMAC(Container const& container) : GenericHMAC(std::data(container), std::size(container)) {}
|
||||
|
||||
~GenericHMAC()
|
||||
{
|
||||
if (!_ctx)
|
||||
return;
|
||||
HMACImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
void UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
int result = HMAC_Update(_ctx, data, len);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
template <typename Container>
|
||||
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
uint32 length = 0;
|
||||
int result = HMAC_Final(_ctx, _digest.data(), &length);
|
||||
ASSERT(result == 1);
|
||||
ASSERT(length == DIGEST_LENGTH);
|
||||
HMACImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
Digest const& GetDigest() const { return _digest; }
|
||||
private:
|
||||
HMAC_CTX* _ctx;
|
||||
Digest _digest = { };
|
||||
};
|
||||
}
|
||||
|
||||
namespace acore::Crypto
|
||||
{
|
||||
using HMAC_SHA1 = acore::Impl::GenericHMAC<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
|
||||
using HMAC_SHA256 = acore::Impl::GenericHMAC<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
|
||||
}
|
||||
#endif
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "HMACSHA1.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Errors.h"
|
||||
#include <cstring>
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
HMAC_CTX* HMAC_CTX_new()
|
||||
{
|
||||
HMAC_CTX* ctx = new HMAC_CTX();
|
||||
HMAC_CTX_init(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void HMAC_CTX_free(HMAC_CTX* ctx)
|
||||
{
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
delete ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
HmacHash::HmacHash(uint32 len, uint8* seed)
|
||||
{
|
||||
m_ctx = HMAC_CTX_new();
|
||||
HMAC_Init_ex(m_ctx, seed, len, EVP_sha1(), nullptr);
|
||||
memset(m_digest, 0, sizeof(m_digest));
|
||||
}
|
||||
|
||||
HmacHash::~HmacHash()
|
||||
{
|
||||
HMAC_CTX_free(m_ctx);
|
||||
}
|
||||
|
||||
void HmacHash::UpdateData(std::string const& str)
|
||||
{
|
||||
HMAC_Update(m_ctx, reinterpret_cast<uint8 const*>(str.c_str()), str.length());
|
||||
}
|
||||
|
||||
void HmacHash::UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
HMAC_Update(m_ctx, data, len);
|
||||
}
|
||||
|
||||
void HmacHash::Finalize()
|
||||
{
|
||||
uint32 length = 0;
|
||||
HMAC_Final(m_ctx, m_digest, &length);
|
||||
ASSERT(length == SHA_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
uint8* HmacHash::ComputeHash(BigNumber* bn)
|
||||
{
|
||||
HMAC_Update(m_ctx, bn->AsByteArray().get(), bn->GetNumBytes());
|
||||
Finalize();
|
||||
return m_digest;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _AUTH_HMAC_H
|
||||
#define _AUTH_HMAC_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
#define SEED_KEY_SIZE 16
|
||||
|
||||
class HmacHash
|
||||
{
|
||||
public:
|
||||
HmacHash(uint32 len, uint8* seed);
|
||||
~HmacHash();
|
||||
void UpdateData(std::string const& str);
|
||||
void UpdateData(uint8 const* data, size_t len);
|
||||
void Finalize();
|
||||
uint8* ComputeHash(BigNumber* bn);
|
||||
uint8* GetDigest() { return m_digest; }
|
||||
int GetLength() const { return SHA_DIGEST_LENGTH; }
|
||||
private:
|
||||
HMAC_CTX* m_ctx;
|
||||
uint8 m_digest[SHA_DIGEST_LENGTH];
|
||||
};
|
||||
#endif
|
||||
@@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "SHA1.h"
|
||||
#include "BigNumber.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
SHA1Hash::SHA1Hash()
|
||||
{
|
||||
SHA1_Init(&mC);
|
||||
memset(mDigest, 0, SHA_DIGEST_LENGTH * sizeof(uint8));
|
||||
}
|
||||
|
||||
SHA1Hash::~SHA1Hash()
|
||||
{
|
||||
SHA1_Init(&mC);
|
||||
}
|
||||
|
||||
void SHA1Hash::UpdateData(const uint8* dta, int len)
|
||||
{
|
||||
SHA1_Update(&mC, dta, len);
|
||||
}
|
||||
|
||||
void SHA1Hash::UpdateData(const std::string& str)
|
||||
{
|
||||
UpdateData((uint8 const*)str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void SHA1Hash::UpdateBigNumbers(BigNumber* bn0, ...)
|
||||
{
|
||||
va_list v;
|
||||
BigNumber* bn;
|
||||
|
||||
va_start(v, bn0);
|
||||
bn = bn0;
|
||||
while (bn)
|
||||
{
|
||||
UpdateData(bn->AsByteArray().get(), bn->GetNumBytes());
|
||||
bn = va_arg(v, BigNumber*);
|
||||
}
|
||||
va_end(v);
|
||||
}
|
||||
|
||||
void SHA1Hash::Initialize()
|
||||
{
|
||||
SHA1_Init(&mC);
|
||||
}
|
||||
|
||||
void SHA1Hash::Finalize(void)
|
||||
{
|
||||
SHA1_Final(mDigest, &mC);
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#ifndef _AUTH_SHA1_H
|
||||
#define _AUTH_SHA1_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
class SHA1Hash
|
||||
{
|
||||
public:
|
||||
SHA1Hash();
|
||||
~SHA1Hash();
|
||||
|
||||
void UpdateBigNumbers(BigNumber* bn0, ...);
|
||||
|
||||
void UpdateData(const uint8* dta, int len);
|
||||
void UpdateData(const std::string& str);
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
uint8* GetDigest() { return mDigest; };
|
||||
[[nodiscard]] int GetLength() const { return SHA_DIGEST_LENGTH; };
|
||||
|
||||
private:
|
||||
SHA_CTX mC;
|
||||
uint8 mDigest[SHA_DIGEST_LENGTH];
|
||||
};
|
||||
#endif
|
||||
97
src/common/Cryptography/SRP6.cpp
Normal file
97
src/common/Cryptography/SRP6.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#include "SRP6.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "Util.h"
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
using SHA1 = acore::Crypto::SHA1;
|
||||
using SRP6 = acore::Crypto::SRP6;
|
||||
|
||||
/*static*/ std::array<uint8, 1> const SRP6::g = { 7 };
|
||||
/*static*/ std::array<uint8, 32> const SRP6::N = HexStrToByteArray<32>("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", true);
|
||||
/*static*/ BigNumber const SRP6::_g(SRP6::g);
|
||||
/*static*/ BigNumber const SRP6::_N(N);
|
||||
|
||||
/*static*/ std::pair<SRP6::Salt, SRP6::Verifier> SRP6::MakeRegistrationData(std::string const& username, std::string const& password)
|
||||
{
|
||||
std::pair<SRP6::Salt, SRP6::Verifier> res;
|
||||
Crypto::GetRandomBytes(res.first); // random salt
|
||||
res.second = CalculateVerifier(username, password, res.first);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*static*/ SRP6::Verifier SRP6::CalculateVerifier(std::string const& username, std::string const& password, SRP6::Salt const& salt)
|
||||
{
|
||||
// v = g ^ H(s || H(u || ':' || p)) mod N
|
||||
return _g.ModExp(
|
||||
SHA1::GetDigestOf(
|
||||
salt,
|
||||
SHA1::GetDigestOf(username, ":", password)
|
||||
)
|
||||
,_N).ToByteArray<32>();
|
||||
}
|
||||
|
||||
/*static*/ SessionKey SRP6::SHA1Interleave(SRP6::EphemeralKey const& S)
|
||||
{
|
||||
// split S into two buffers
|
||||
std::array<uint8, EPHEMERAL_KEY_LENGTH/2> buf0, buf1;
|
||||
for (size_t i = 0; i < EPHEMERAL_KEY_LENGTH/2; ++i)
|
||||
{
|
||||
buf0[i] = S[2 * i + 0];
|
||||
buf1[i] = S[2 * i + 1];
|
||||
}
|
||||
|
||||
// find position of first nonzero byte
|
||||
size_t p = 0;
|
||||
while (p < EPHEMERAL_KEY_LENGTH && !S[p]) ++p;
|
||||
if (p & 1) ++p; // skip one extra byte if p is odd
|
||||
p /= 2; // offset into buffers
|
||||
|
||||
// hash each of the halves, starting at the first nonzero byte
|
||||
SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
|
||||
SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
|
||||
|
||||
// stick the two hashes back together
|
||||
SessionKey K;
|
||||
for (size_t i = 0; i < SHA1::DIGEST_LENGTH; ++i)
|
||||
{
|
||||
K[2 * i + 0] = hash0[i];
|
||||
K[2 * i + 1] = hash1[i];
|
||||
}
|
||||
return K;
|
||||
}
|
||||
|
||||
SRP6::SRP6(std::string const& username, Salt const& salt, Verifier const& verifier)
|
||||
: _I(SHA1::GetDigestOf(username)), _b(Crypto::GetRandomBytes<32>()), _v(verifier), s(salt), B(_B(_b, _v)) {}
|
||||
|
||||
std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM)
|
||||
{
|
||||
ASSERT(!_used);
|
||||
_used = true;
|
||||
|
||||
BigNumber const _A(A);
|
||||
if ((_A % _N).isZero())
|
||||
return std::nullopt;
|
||||
|
||||
BigNumber const u(SHA1::GetDigestOf(A, B));
|
||||
EphemeralKey const S = (_A * (_v.ModExp(u, _N))).ModExp(_b, N).ToByteArray<32>();
|
||||
|
||||
SessionKey K = SHA1Interleave(S);
|
||||
|
||||
// NgHash = H(N) xor H(g)
|
||||
SHA1::Digest const NHash = SHA1::GetDigestOf(N);
|
||||
SHA1::Digest const gHash = SHA1::GetDigestOf(g);
|
||||
SHA1::Digest NgHash;
|
||||
std::transform(NHash.begin(), NHash.end(), gHash.begin(), NgHash.begin(), std::bit_xor<>());
|
||||
|
||||
SHA1::Digest const ourM = SHA1::GetDigestOf(NgHash, _I, s, A, B, K);
|
||||
if (ourM == clientM)
|
||||
return K;
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
71
src/common/Cryptography/SRP6.h
Normal file
71
src/common/Cryptography/SRP6.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#ifndef AZEROTHCORE_SRP6_H
|
||||
#define AZEROTHCORE_SRP6_H
|
||||
|
||||
#include "AuthDefines.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Define.h"
|
||||
#include "Common.h"
|
||||
#include "CryptoHash.h"
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
namespace acore::Crypto
|
||||
{
|
||||
class SRP6
|
||||
{
|
||||
public:
|
||||
static constexpr size_t SALT_LENGTH = 32;
|
||||
using Salt = std::array<uint8, SALT_LENGTH>;
|
||||
static constexpr size_t VERIFIER_LENGTH = 32;
|
||||
using Verifier = std::array<uint8, VERIFIER_LENGTH>;
|
||||
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
|
||||
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
|
||||
|
||||
static std::array<uint8, 1> const g;
|
||||
static std::array<uint8, 32> const N;
|
||||
|
||||
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
|
||||
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password);
|
||||
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
|
||||
static bool CheckLogin(std::string const& username, std::string const& password, Salt const& salt, Verifier const& verifier)
|
||||
{
|
||||
return (verifier == CalculateVerifier(username, password, salt));
|
||||
}
|
||||
|
||||
static SHA1::Digest GetSessionVerifier(EphemeralKey const& A, SHA1::Digest const& clientM, SessionKey const& K)
|
||||
{
|
||||
return SHA1::GetDigestOf(A, clientM, K);
|
||||
}
|
||||
|
||||
SRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
|
||||
std::optional<SessionKey> VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM);
|
||||
|
||||
private:
|
||||
bool _used = false; // a single instance can only be used to verify once
|
||||
|
||||
static Verifier CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt);
|
||||
static SessionKey SHA1Interleave(EphemeralKey const& S);
|
||||
|
||||
/* global algorithm parameters */
|
||||
static BigNumber const _g; // a [g]enerator for the ring of integers mod N, algorithm parameter
|
||||
static BigNumber const _N; // the modulus, an algorithm parameter; all operations are mod this
|
||||
|
||||
static EphemeralKey _B(BigNumber const& b, BigNumber const& v) { return ((_g.ModExp(b,_N) + (v * 3)) % N).ToByteArray<EPHEMERAL_KEY_LENGTH>(); }
|
||||
|
||||
/* per-instantiation parameters, set on construction */
|
||||
SHA1::Digest const _I; // H(I) - the username, all uppercase
|
||||
BigNumber const _b; // b - randomly chosen by the server, 19 bytes, never given out
|
||||
BigNumber const _v; // v - the user's password verifier, derived from s + H(USERNAME || ":" || PASSWORD)
|
||||
|
||||
public:
|
||||
Salt const s; // s - the user's password salt, random, used to calculate v on registration
|
||||
EphemeralKey const B; // B = 3v + g^b
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
50
src/common/Cryptography/SessionKeyGenerator.h
Normal file
50
src/common/Cryptography/SessionKeyGenerator.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
|
||||
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "CryptoHash.h"
|
||||
|
||||
#ifndef AZEROTHCORE_SESSIONKEYGENERATOR_HPP
|
||||
#define AZEROTHCORE_SESSIONKEYGENERATOR_HPP
|
||||
|
||||
template <typename Hash>
|
||||
class SessionKeyGenerator
|
||||
{
|
||||
public:
|
||||
template <typename C>
|
||||
SessionKeyGenerator(C const& buf) :
|
||||
o0it(o0.begin())
|
||||
{
|
||||
uint8 const* data = std::data(buf);
|
||||
size_t const len = std::size(buf);
|
||||
size_t const halflen = (len / 2);
|
||||
|
||||
o1 = Hash::GetDigestOf(data, halflen);
|
||||
o2 = Hash::GetDigestOf(data + halflen, len - halflen);
|
||||
o0 = Hash::GetDigestOf(o1, o0, o2);
|
||||
}
|
||||
|
||||
void Generate(uint8* buf, uint32 sz)
|
||||
{
|
||||
for (uint32 i = 0; i < sz; ++i)
|
||||
{
|
||||
if (o0it == o0.end())
|
||||
{
|
||||
o0 = Hash::GetDigestOf(o1, o0, o2);
|
||||
o0it = o0.begin();
|
||||
}
|
||||
|
||||
buf[i] = *(o0it++);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typename Hash::Digest o0 = { };
|
||||
typename Hash::Digest o1 = { };
|
||||
typename Hash::Digest o2 = { };
|
||||
typename Hash::Digest::const_iterator o0it;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
|
||||
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
|
||||
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
|
||||
*/
|
||||
|
||||
#include "SHA1.h"
|
||||
|
||||
#ifndef _WARDEN_KEY_GENERATION_H
|
||||
#define _WARDEN_KEY_GENERATION_H
|
||||
|
||||
class SHA1Randx
|
||||
{
|
||||
public:
|
||||
SHA1Randx(uint8* buff, uint32 size)
|
||||
{
|
||||
uint32 taken = size / 2;
|
||||
|
||||
sh.Initialize();
|
||||
sh.UpdateData(buff, taken);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o1, sh.GetDigest(), 20);
|
||||
|
||||
sh.Initialize();
|
||||
sh.UpdateData(buff + taken, size - taken);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o2, sh.GetDigest(), 20);
|
||||
|
||||
memset(o0, 0x00, 20);
|
||||
|
||||
FillUp();
|
||||
}
|
||||
|
||||
void Generate(uint8* buf, uint32 sz)
|
||||
{
|
||||
for (uint32 i = 0; i < sz; ++i)
|
||||
{
|
||||
if (taken == 20)
|
||||
FillUp();
|
||||
|
||||
buf[i] = o0[taken];
|
||||
taken++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void FillUp()
|
||||
{
|
||||
sh.Initialize();
|
||||
sh.UpdateData(o1, 20);
|
||||
sh.UpdateData(o0, 20);
|
||||
sh.UpdateData(o2, 20);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o0, sh.GetDigest(), 20);
|
||||
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
SHA1Hash sh;
|
||||
uint32 taken;
|
||||
uint8 o0[20], o1[20], o2[20];
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user