diff options
Diffstat (limited to 'src')
42 files changed, 730 insertions, 723 deletions
diff --git a/src/common/Cryptography/AES.cpp b/src/common/Cryptography/AES.cpp index 55f5f9aa55f..7d4ccc7c46f 100644 --- a/src/common/Cryptography/AES.cpp +++ b/src/common/Cryptography/AES.cpp @@ -37,7 +37,7 @@ void Trinity::Crypto::AES::Init(Key const& key) ASSERT(status); } -bool Trinity::Crypto::AES::Process(IV const& iv, uint8* data, std::size_t length, Tag& tag) +bool Trinity::Crypto::AES::Process(IV const& iv, uint8* data, size_t length, Tag& tag) { ASSERT(length <= std::numeric_limits<int>::max()); int len = static_cast<int>(length); diff --git a/src/common/Cryptography/AES.h b/src/common/Cryptography/AES.h index d0ff2114b02..ca997030077 100644 --- a/src/common/Cryptography/AES.h +++ b/src/common/Cryptography/AES.h @@ -22,33 +22,30 @@ #include <array> #include <openssl/evp.h> -namespace Trinity +namespace Trinity::Crypto { -namespace Crypto -{ -class TC_COMMON_API AES -{ -public: - static constexpr std::size_t IV_SIZE_BYTES = 12; - static constexpr std::size_t KEY_SIZE_BYTES = 16; - static constexpr std::size_t TAG_SIZE_BYTES = 12; + class TC_COMMON_API AES + { + public: + static constexpr size_t IV_SIZE_BYTES = 12; + static constexpr size_t KEY_SIZE_BYTES = 16; + static constexpr size_t TAG_SIZE_BYTES = 12; - using IV = std::array<uint8, IV_SIZE_BYTES>; - using Key = std::array<uint8, KEY_SIZE_BYTES>; - using Tag = uint8[TAG_SIZE_BYTES]; + using IV = std::array<uint8, IV_SIZE_BYTES>; + using Key = std::array<uint8, KEY_SIZE_BYTES>; + using Tag = uint8[TAG_SIZE_BYTES]; - AES(bool encrypting); - ~AES(); + AES(bool encrypting); + ~AES(); - void Init(Key const& key); + void Init(Key const& key); - bool Process(IV const& iv, uint8* data, std::size_t length, Tag& tag); + bool Process(IV const& iv, uint8* data, size_t length, Tag& tag); -private: - EVP_CIPHER_CTX* _ctx; - bool _encrypting; -}; -} + private: + EVP_CIPHER_CTX* _ctx; + bool _encrypting; + }; } #endif // Trinity_AES_h__ diff --git a/src/common/Cryptography/ARC4.cpp b/src/common/Cryptography/ARC4.cpp index fe32fec8ef4..161303e2c15 100644 --- a/src/common/Cryptography/ARC4.cpp +++ b/src/common/Cryptography/ARC4.cpp @@ -16,35 +16,33 @@ */ #include "ARC4.h" +#include "Errors.h" -ARC4::ARC4(uint32 len) : m_ctx(EVP_CIPHER_CTX_new()) +Trinity::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()) +Trinity::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 Trinity::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 Trinity::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); } diff --git a/src/common/Cryptography/ARC4.h b/src/common/Cryptography/ARC4.h index e0b0d2d39b6..5ce2db5aa3b 100644 --- a/src/common/Cryptography/ARC4.h +++ b/src/common/Cryptography/ARC4.h @@ -19,18 +19,27 @@ #define _AUTH_SARC4_H #include "Define.h" +#include <array> #include <openssl/evp.h> -class TC_COMMON_API ARC4 +namespace Trinity::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 TC_COMMON_API 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 diff --git a/src/common/Cryptography/Argon2.cpp b/src/common/Cryptography/Argon2.cpp index c3a2f07310b..225d92c3994 100644 --- a/src/common/Cryptography/Argon2.cpp +++ b/src/common/Cryptography/Argon2.cpp @@ -21,12 +21,13 @@ /*static*/ Optional<std::string> Trinity::Crypto::Argon2::Hash(std::string const& password, BigNumber const& salt, uint32 nIterations, uint32 kibMemoryCost) { char buf[ENCODED_HASH_LEN]; + std::vector<uint8> saltBytes = salt.ToByteVector(); int status = argon2id_hash_encoded( nIterations, kibMemoryCost, PARALLELISM, password.c_str(), password.length(), - salt.AsByteArray().get(), salt.GetNumBytes(), + saltBytes.data(), saltBytes.size(), HASH_LEN, buf, ENCODED_HASH_LEN ); diff --git a/src/common/Cryptography/Argon2.h b/src/common/Cryptography/Argon2.h index 06f1c6398aa..2c1d44d10d7 100644 --- a/src/common/Cryptography/Argon2.h +++ b/src/common/Cryptography/Argon2.h @@ -23,22 +23,19 @@ #include "Optional.h" #include <string> -namespace Trinity +namespace Trinity::Crypto { -namespace Crypto -{ -struct TC_COMMON_API Argon2 -{ - static constexpr uint32 HASH_LEN = 16; // 128 bits, in bytes - static constexpr uint32 ENCODED_HASH_LEN = 100; // in chars - static constexpr uint32 DEFAULT_ITERATIONS = 10; // determined by dice roll, guaranteed to be secure (not really) - static constexpr uint32 DEFAULT_MEMORY_COST = (1u << 17); // 2^17 kibibytes is 2^7 mebibytes is ~100MB - static constexpr uint32 PARALLELISM = 1; // we don't support threaded hashing + struct TC_COMMON_API Argon2 + { + static constexpr uint32 HASH_LEN = 16; // 128 bits, in bytes + static constexpr uint32 ENCODED_HASH_LEN = 100; // in chars + static constexpr uint32 DEFAULT_ITERATIONS = 10; // determined by dice roll, guaranteed to be secure (not really) + static constexpr uint32 DEFAULT_MEMORY_COST = (1u << 17); // 2^17 kibibytes is 2^7 mebibytes is ~100MB + static constexpr uint32 PARALLELISM = 1; // we don't support threaded hashing - static Optional<std::string> Hash(std::string const& password, BigNumber const& salt, uint32 nIterations = DEFAULT_ITERATIONS, uint32 kibMemoryCost = DEFAULT_MEMORY_COST); - static bool Verify(std::string const& password, std::string const& hash); -}; -} + static Optional<std::string> Hash(std::string const& password, BigNumber const& salt, uint32 nIterations = DEFAULT_ITERATIONS, uint32 kibMemoryCost = DEFAULT_MEMORY_COST); + static bool Verify(std::string const& password, std::string const& hash); + }; } #endif diff --git a/src/common/Cryptography/Authentication/AuthCrypt.cpp b/src/common/Cryptography/Authentication/AuthCrypt.cpp index c4ff701f5d1..9d50fb026c3 100644 --- a/src/common/Cryptography/Authentication/AuthCrypt.cpp +++ b/src/common/Cryptography/Authentication/AuthCrypt.cpp @@ -16,58 +16,39 @@ */ #include "AuthCrypt.h" -#include "Cryptography/HMACSHA1.h" -#include "Cryptography/BigNumber.h" +#include "BigNumber.h" +#include "Errors.h" +#include "HMAC.h" #include <cstring> AuthCrypt::AuthCrypt() : - _clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH), _initialized(false) { } -void AuthCrypt::Init(BigNumber* K) +void AuthCrypt::Init(std::array<uint8, 40> const& K) { - 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); + uint8 ServerEncryptionKey[] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 }; + _serverEncrypt.Init(Trinity::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(Trinity::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); } diff --git a/src/common/Cryptography/Authentication/AuthCrypt.h b/src/common/Cryptography/Authentication/AuthCrypt.h index c6d4066350c..cb1a217297a 100644 --- a/src/common/Cryptography/Authentication/AuthCrypt.h +++ b/src/common/Cryptography/Authentication/AuthCrypt.h @@ -18,24 +18,23 @@ #ifndef _AUTHCRYPT_H #define _AUTHCRYPT_H -#include "Cryptography/ARC4.h" - -class BigNumber; +#include "ARC4.h" +#include <array> class TC_COMMON_API AuthCrypt { public: AuthCrypt(); - void Init(BigNumber* K); - void DecryptRecv(uint8 *, size_t); - void EncryptSend(uint8 *, size_t); + void Init(std::array<uint8, 40> 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; + Trinity::Crypto::ARC4 _clientDecrypt; + Trinity::Crypto::ARC4 _serverEncrypt; bool _initialized; }; #endif diff --git a/src/common/Cryptography/BigNumber.cpp b/src/common/Cryptography/BigNumber.cpp index 036d6594045..7bbe43fff50 100644 --- a/src/common/Cryptography/BigNumber.cpp +++ b/src/common/Cryptography/BigNumber.cpp @@ -30,12 +30,6 @@ BigNumber::BigNumber(BigNumber const& bn) : _bn(BN_dup(bn._bn)) { } -BigNumber::BigNumber(uint32 val) - : _bn(BN_new()) -{ - BN_set_word(_bn, val); -} - BigNumber::~BigNumber() { BN_free(_bn); @@ -185,15 +179,14 @@ bool BigNumber::IsNegative() const return BN_is_negative(_bn); } -bool BigNumber::AsByteArray(uint8* buf, std::size_t bufsize, bool littleEndian) const +void BigNumber::GetBytes(uint8* buf, std::size_t bufsize, bool littleEndian) const { int nBytes = GetNumBytes(); - ASSERT(!(nBytes < 0)); + ASSERT(nBytes >= 0, "Bignum has negative number of bytes (%d).", nBytes); std::size_t numBytes = static_cast<std::size_t>(nBytes); // too large to store - if (bufsize < numBytes) - return false; + 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 (numBytes < bufsize) @@ -204,18 +197,15 @@ bool BigNumber::AsByteArray(uint8* buf, std::size_t bufsize, bool littleEndian) // openssl's BN stores data internally in big endian format, reverse if little endian desired if (littleEndian) std::reverse(buf, buf + bufsize); - - return true; } -std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian) const +std::vector<uint8> BigNumber::ToByteVector(int32 minSize, bool littleEndian) const { std::size_t length = std::max(GetNumBytes(), minSize); - uint8* array = new uint8[length]; - bool success = AsByteArray(array, length, littleEndian); - ASSERT(success); - - return std::unique_ptr<uint8[]>(array); + std::vector<uint8> v; + v.resize(length); + GetBytes(v.data(), length, littleEndian); + return v; } std::string BigNumber::AsHexStr() const diff --git a/src/common/Cryptography/BigNumber.h b/src/common/Cryptography/BigNumber.h index 9efe66714c5..ef9281b4652 100644 --- a/src/common/Cryptography/BigNumber.h +++ b/src/common/Cryptography/BigNumber.h @@ -22,6 +22,7 @@ #include <array> #include <memory> #include <string> +#include <vector> struct bignum_st; @@ -30,13 +31,20 @@ class TC_COMMON_API BigNumber public: BigNumber(); BigNumber(BigNumber const& bn); - BigNumber(uint32); + BigNumber(uint32 v) : BigNumber() { SetDword(v); } + BigNumber(std::string const& v) : BigNumber() { SetHexStr(v); } + template <size_t Size> + BigNumber(std::array<uint8, Size> const& v) : BigNumber() { SetBinary(v.data(), Size); } + ~BigNumber(); void SetDword(uint32); void SetQword(uint64); void SetBinary(uint8 const* bytes, int32 len); + template <typename Container> + void SetBinary(Container const& c) { SetBinary(std::data(c), std::size(c)); } bool SetHexStr(char const* str); + bool SetHexStr(std::string const& str) { return SetHexStr(str.c_str()); } void SetRand(int32 numbits); @@ -103,12 +111,14 @@ class TC_COMMON_API BigNumber uint32 AsDword() const; - bool AsByteArray(uint8* buf, std::size_t bufsize, bool littleEndian = true) const; - std::unique_ptr<uint8[]> AsByteArray(int32 minSize = 0, bool littleEndian = true) const; - template <std::size_t N> std::array<uint8, N> AsByteArray(bool littleEndian = true) const + 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, N> buf; - AsByteArray(buf.data(), N, littleEndian); + std::array<uint8, Size> buf; + GetBytes(buf.data(), Size, littleEndian); return buf; } diff --git a/src/common/Cryptography/HMACSHA1.h b/src/common/Cryptography/CryptoConstants.h index b04d0a394d4..7e698a685e4 100644 --- a/src/common/Cryptography/HMACSHA1.h +++ b/src/common/Cryptography/CryptoConstants.h @@ -15,31 +15,18 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _AUTH_HMAC_H -#define _AUTH_HMAC_H +#ifndef TRINITY_CRYPTO_CONSTANTS_H +#define TRINITY_CRYPTO_CONSTANTS_H #include "Define.h" -#include <string> -#include <openssl/hmac.h> -#include <openssl/sha.h> -class BigNumber; - -#define SEED_KEY_SIZE 16 - -class TC_COMMON_API HmacHash +namespace Trinity::Crypto { - 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]; -}; + struct Constants + { + static constexpr size_t SHA1_DIGEST_LENGTH_BYTES = 20; + static constexpr size_t SHA256_DIGEST_LENGTH_BYTES = 32; + }; +} + #endif diff --git a/src/common/Cryptography/CryptoGenerics.h b/src/common/Cryptography/CryptoGenerics.h index 935033ae22f..75ad443b32a 100644 --- a/src/common/Cryptography/CryptoGenerics.h +++ b/src/common/Cryptography/CryptoGenerics.h @@ -19,96 +19,92 @@ #define TRINITY_CRYPTO_GENERICS_HPP #include "BigNumber.h" +#include "CryptoRandom.h" #include "Define.h" #include "Errors.h" #include <iterator> #include <vector> -#include <openssl/rand.h> -namespace Trinity +namespace Trinity::Impl { - namespace Impl + struct CryptoGenericsImpl { - struct CryptoGenericsImpl + template <typename Cipher> + static typename Cipher::IV GenerateRandomIV() { - template <typename Cipher> - static typename Cipher::IV GenerateRandomIV() - { - typename Cipher::IV iv; - int status = RAND_bytes(std::data(iv), std::size(iv)); - ASSERT(status); - return iv; - } + typename Cipher::IV iv; + Trinity::Crypto::GetRandomBytes(iv); + return iv; + } - template <typename C> - static void AppendToBack(std::vector<uint8>& data, C const& tail) - { - data.insert(data.end(), std::begin(tail), std::end(tail)); - } + 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 C> - static void SplitFromBack(std::vector<uint8>& data, C& 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) { - 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(); - } + tail[N - i] = data.back(); + data.pop_back(); } - }; - } + } + }; +} - namespace Crypto +namespace Trinity::Crypto +{ + template <typename Cipher> + void AEEncryptWithRandomIV(std::vector<uint8>& data, typename Cipher::Key const& key) { - 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 = Trinity::Impl::CryptoGenericsImpl::GenerateRandomIV<Cipher>(); - Tag tag; + using IV = typename Cipher::IV; + using Tag = typename Cipher::Tag; + // select random IV + IV iv = Trinity::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); + // 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 - Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, iv); - Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, tag); - } + // append trailing IV and tag + Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, iv); + Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, tag); + } - template <typename Cipher> - void AEEncryptWithRandomIV(std::vector<uint8>& data, BigNumber const& key) - { - AEEncryptWithRandomIV<Cipher>(data, key.AsByteArray<Cipher::KEY_SIZE_BYTES>()); - } + 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; - Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, tag); - Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, iv); + 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; + Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, tag); + Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, iv); - // decrypt data - Cipher cipher(false); - cipher.Init(key); - return cipher.Process(iv, data.data(), data.size(), tag); - } + // 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.AsByteArray<Cipher::KEY_SIZE_BYTES>()); - } + template <typename Cipher> + bool AEDecrypt(std::vector<uint8>& data, BigNumber const& key) + { + return AEDecrypt<Cipher>(data, key.ToByteArray<Cipher::KEY_SIZE_BYTES>()); } } diff --git a/src/common/Cryptography/CryptoHash.h b/src/common/Cryptography/CryptoHash.h new file mode 100644 index 00000000000..8c9825ce2d8 --- /dev/null +++ b/src/common/Cryptography/CryptoHash.h @@ -0,0 +1,119 @@ +/* + * 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_CRYPTOHASH_H +#define TRINITY_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 Trinity::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 Trinity::Crypto +{ + using SHA1 = Trinity::Impl::GenericHash<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>; + using SHA256 = Trinity::Impl::GenericHash<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>; +} + +#endif diff --git a/src/common/Cryptography/CryptoRandom.cpp b/src/common/Cryptography/CryptoRandom.cpp new file mode 100644 index 00000000000..971c2ce7f7c --- /dev/null +++ b/src/common/Cryptography/CryptoRandom.cpp @@ -0,0 +1,26 @@ +/* + * 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/>. + */ + +#include "CryptoRandom.h" +#include "Errors.h" +#include <openssl/rand.h> + +void Trinity::Crypto::GetRandomBytes(uint8* buf, size_t len) +{ + int result = RAND_bytes(buf, len); + ASSERT(result == 1, "Not enough randomness in OpenSSL's entropy pool. What in the world are you running on?"); +} diff --git a/src/common/Cryptography/SHA1.h b/src/common/Cryptography/CryptoRandom.h index bea63304426..f5ede4e992e 100644 --- a/src/common/Cryptography/SHA1.h +++ b/src/common/Cryptography/CryptoRandom.h @@ -15,38 +15,29 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _AUTH_SHA1_H -#define _AUTH_SHA1_H +#ifndef TRINITY_CRYPTORANDOM_H +#define TRINITY_CRYPTORANDOM_H #include "Define.h" -#include <string> -#include <openssl/sha.h> +#include <array> -class BigNumber; - -class TC_COMMON_API SHA1Hash +namespace Trinity::Crypto { - 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(void) { return mDigest; } - int GetLength(void) const { return SHA_DIGEST_LENGTH; } - - private: - SHA_CTX mC; - uint8 mDigest[SHA_DIGEST_LENGTH]; -}; - -/// Returns the SHA1 hash of the given content as hex string. -TC_COMMON_API std::string CalculateSHA1Hash(std::string const& content); + void TC_COMMON_API 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 diff --git a/src/common/Cryptography/HMAC.h b/src/common/Cryptography/HMAC.h new file mode 100644 index 00000000000..18a236ebccd --- /dev/null +++ b/src/common/Cryptography/HMAC.h @@ -0,0 +1,130 @@ +/* + * 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_HMAC_H +#define TRINITY_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 Trinity::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 Trinity::Crypto +{ + using HMAC_SHA1 = Trinity::Impl::GenericHMAC<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>; + using HMAC_SHA256 = Trinity::Impl::GenericHMAC<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>; +} +#endif diff --git a/src/common/Cryptography/HMACSHA1.cpp b/src/common/Cryptography/HMACSHA1.cpp deleted file mode 100644 index 1a8526a9c00..00000000000 --- a/src/common/Cryptography/HMACSHA1.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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/>. - */ - -#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; -} diff --git a/src/common/Cryptography/SHA1.cpp b/src/common/Cryptography/SHA1.cpp deleted file mode 100644 index 15140d82a43..00000000000 --- a/src/common/Cryptography/SHA1.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * 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/>. - */ - -#include "SHA1.h" -#include "BigNumber.h" -#include "Util.h" -#include <cstring> -#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); -} - -std::string CalculateSHA1Hash(std::string const& content) -{ - unsigned char digest[SHA_DIGEST_LENGTH]; - SHA1((unsigned char*)content.c_str(), content.length(), (unsigned char*)&digest); - - return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH); -} diff --git a/src/common/Cryptography/SessionKeyGenerator.h b/src/common/Cryptography/SessionKeyGenerator.h new file mode 100644 index 00000000000..af787358981 --- /dev/null +++ b/src/common/Cryptography/SessionKeyGenerator.h @@ -0,0 +1,60 @@ +/* + * 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/>. + */ + +#include <cstring> +#include "CryptoHash.h" + +#ifndef TRINITY_SESSIONKEYGENERATOR_HPP +#define TRINITY_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, o1, o2; + typename Hash::Digest::const_iterator o0it; + }; + +#endif diff --git a/src/common/Cryptography/TOTP.h b/src/common/Cryptography/TOTP.h index 02e5b9adffc..0aba8ff867e 100644 --- a/src/common/Cryptography/TOTP.h +++ b/src/common/Cryptography/TOTP.h @@ -22,19 +22,16 @@ #include <ctime> #include <vector> -namespace Trinity +namespace Trinity::Crypto { -namespace Crypto -{ -struct TC_COMMON_API TOTP -{ - static constexpr std::size_t RECOMMENDED_SECRET_LENGTH = 20; - using Secret = std::vector<uint8>; + struct TC_COMMON_API TOTP + { + static constexpr size_t RECOMMENDED_SECRET_LENGTH = 20; + using Secret = std::vector<uint8>; - static uint32 GenerateToken(Secret const& key, time_t timestamp); - static bool ValidateToken(Secret const& key, uint32 token); -}; -} + static uint32 GenerateToken(Secret const& key, time_t timestamp); + static bool ValidateToken(Secret const& key, uint32 token); + }; } #endif diff --git a/src/common/Cryptography/WardenKeyGeneration.h b/src/common/Cryptography/WardenKeyGeneration.h deleted file mode 100644 index 6f507dd58c7..00000000000 --- a/src/common/Cryptography/WardenKeyGeneration.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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/>. - */ - -#include "SHA1.h" - -#include <cstring> - -#ifndef _WARDEN_KEY_GENERATION_H -#define _WARDEN_KEY_GENERATION_H - -class SHA1Randx -{ -public: - SHA1Randx(uint8* buff, uint32 size) - { - uint32 halfSize = size / 2; - - sh.Initialize(); - sh.UpdateData(buff, halfSize); - sh.Finalize(); - - memcpy(o1, sh.GetDigest(), 20); - - sh.Initialize(); - sh.UpdateData(buff + halfSize, size - halfSize); - 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 diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index 62629c80d43..7e4b9130e82 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -611,7 +611,7 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String) return WStrToUtf8(wstr, utf8String); } -std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */) +std::string ByteArrayToHexStr(uint8 const* bytes, size_t arrayLen, bool reverse /* = false */) { int32 init = 0; int32 end = arrayLen; diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index 94c1271ceca..b22295e95a8 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -304,7 +304,9 @@ TC_COMMON_API bool IsIPAddress(char const* ipaddress); TC_COMMON_API uint32 CreatePIDFile(std::string const& filename); TC_COMMON_API uint32 GetPID(); -TC_COMMON_API std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); +TC_COMMON_API std::string ByteArrayToHexStr(uint8 const* bytes, size_t length, bool reverse = false); +template <typename Container> +std::string ByteArrayToHexStr(Container const& c, bool reverse = false) { return ByteArrayToHexStr(std::data(c), std::size(c), reverse); } TC_COMMON_API void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false); TC_COMMON_API bool StringToBool(std::string const& str); diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index 748d2145a23..c1f4703ea47 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -20,13 +20,14 @@ #include "AuthCodes.h" #include "Config.h" #include "CryptoGenerics.h" +#include "CryptoRandom.h" #include "DatabaseEnv.h" #include "Errors.h" +#include "CryptoHash.h" #include "IPLocation.h" #include "Log.h" #include "RealmList.h" #include "SecretMgr.h" -#include "SHA1.h" #include "TOTP.h" #include "Util.h" #include <boost/lexical_cast.hpp> @@ -74,8 +75,7 @@ typedef struct AUTH_LOGON_PROOF_C { uint8 cmd; uint8 A[32]; - uint8 M1[20]; - uint8 crc_hash[20]; + Trinity::Crypto::SHA1::Digest M1, crc_hash; uint8 number_of_keys; uint8 securityFlags; } sAuthLogonProof_C; @@ -85,7 +85,7 @@ typedef struct AUTH_LOGON_PROOF_S { uint8 cmd; uint8 error; - uint8 M2[20]; + Trinity::Crypto::SHA1::Digest M2; uint32 AccountFlags; uint32 SurveyId; uint16 LoginFlags; @@ -96,7 +96,7 @@ typedef struct AUTH_LOGON_PROOF_S_OLD { uint8 cmd; uint8 error; - uint8 M2[20]; + Trinity::Crypto::SHA1::Digest M2; uint32 unk2; } sAuthLogonProof_S_Old; static_assert(sizeof(sAuthLogonProof_S_Old) == (1 + 1 + 20 + 4)); @@ -105,8 +105,7 @@ typedef struct AUTH_RECONNECT_PROOF_C { uint8 cmd; uint8 R1[16]; - uint8 R2[20]; - uint8 R3[20]; + Trinity::Crypto::SHA1::Digest R2, R3; uint8 number_of_keys; } sAuthReconnectProof_C; static_assert(sizeof(sAuthReconnectProof_C) == (1 + 16 + 20 + 20 + 1)); @@ -115,10 +114,10 @@ static_assert(sizeof(sAuthReconnectProof_C) == (1 + 16 + 20 + 20 + 1)); std::array<uint8, 16> VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B, 0x21, 0x57, 0xFC, 0x37, 0x3F, 0xB3, 0x69, 0xCD, 0xD2, 0xF1 } }; -enum class BufferSizes : uint32 +struct BufferSizes { - SRP_6_V = 0x20, - SRP_6_S = 0x20, + static constexpr size_t SRP_6_V = 0x20; + static constexpr size_t SRP_6_S = 0x20; }; #define MAX_ACCEPTED_CHALLENGE_SIZE (sizeof(AUTH_LOGON_CHALLENGE_C) + 16) @@ -436,12 +435,12 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result) pkt << uint8(WOW_SUCCESS); // B may be calculated < 32B so we force minimal length to 32B - pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes + pkt.append(B.ToByteArray<32>()); // 32 bytes pkt << uint8(1); - pkt.append(g.AsByteArray(1).get(), 1); + pkt.append(g.ToByteArray<1>()); pkt << uint8(32); - pkt.append(N.AsByteArray(32).get(), 32); - pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes + pkt.append(N.ToByteArray<32>()); + pkt.append(s.ToByteArray<BufferSizes::SRP_6_S>()); // 32 bytes pkt.append(VersionChallenge.data(), VersionChallenge.size()); pkt << uint8(securityFlags); // security flags (0x0...0x04) @@ -500,72 +499,42 @@ bool AuthSession::HandleLogonProof() if ((A % N).IsZero()) return false; - SHA1Hash sha; - sha.UpdateBigNumbers(&A, &B, nullptr); - sha.Finalize(); - BigNumber u; - u.SetBinary(sha.GetDigest(), 20); + BigNumber u(Trinity::Crypto::SHA1::GetDigestOf(A.ToByteArray<32>(), B.ToByteArray<32>())); BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N); - uint8 t[32]; - uint8 t1[16]; - uint8 vK[40]; - memcpy(t, S.AsByteArray(32).get(), 32); - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2]; - - sha.Initialize(); - sha.UpdateData(t1, 16); + std::array<uint8, 32> t = S.ToByteArray<32>(); + std::array<uint8, 16> buf; + Trinity::Crypto::SHA1::Digest part; + std::array<uint8, 40> sessionKey; + + for (size_t i = 0; i < 16; ++i) + buf[i] = t[i * 2]; + part = Trinity::Crypto::SHA1::GetDigestOf(buf); + for (size_t i = 0; i < Trinity::Crypto::SHA1::DIGEST_LENGTH; ++i) + sessionKey[i * 2] = part[i]; + + for (size_t i = 0; i < 16; ++i) + buf[i] = t[i * 2 + 1]; + part = Trinity::Crypto::SHA1::GetDigestOf(buf); + for (size_t i = 0; i < Trinity::Crypto::SHA1::DIGEST_LENGTH; ++i) + sessionKey[i * 2 + 1] = part[i]; + + Trinity::Crypto::SHA1::Digest hash = Trinity::Crypto::SHA1::GetDigestOf(N.ToByteArray<32>()); + Trinity::Crypto::SHA1::Digest hash2 = Trinity::Crypto::SHA1::GetDigestOf(g.ToByteArray<1>()); + std::transform(hash.begin(), hash.end(), hash2.begin(), hash.begin(), std::bit_xor<>()); // hash = H(N) xor H(g) + + Trinity::Crypto::SHA1 sha; + sha.UpdateData(hash); + sha.UpdateData(Trinity::Crypto::SHA1::GetDigestOf(_accountInfo.Login)); + sha.UpdateData(s.ToByteArray<BufferSizes::SRP_6_S>()); + sha.UpdateData(A.ToByteArray<32>()); + sha.UpdateData(B.ToByteArray<32>()); + sha.UpdateData(sessionKey); sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2] = sha.GetDigest()[i]; - - for (int i = 0; i < 16; ++i) - t1[i] = t[i * 2 + 1]; - - sha.Initialize(); - sha.UpdateData(t1, 16); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - vK[i * 2 + 1] = sha.GetDigest()[i]; - - K.SetBinary(vK, 40); - - uint8 hash[20]; - - sha.Initialize(); - sha.UpdateBigNumbers(&N, nullptr); - sha.Finalize(); - memcpy(hash, sha.GetDigest(), 20); - sha.Initialize(); - sha.UpdateBigNumbers(&g, nullptr); - sha.Finalize(); - - for (int i = 0; i < 20; ++i) - hash[i] ^= sha.GetDigest()[i]; - - BigNumber t3; - t3.SetBinary(hash, 20); - - sha.Initialize(); - sha.UpdateData(_accountInfo.Login); - sha.Finalize(); - uint8 t4[SHA_DIGEST_LENGTH]; - memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH); - - sha.Initialize(); - sha.UpdateBigNumbers(&t3, nullptr); - sha.UpdateData(t4, SHA_DIGEST_LENGTH); - sha.UpdateBigNumbers(&s, &A, &B, &K, nullptr); - sha.Finalize(); - BigNumber M; - M.SetBinary(sha.GetDigest(), sha.GetLength()); + Trinity::Crypto::SHA1::Digest M = sha.GetDigest(); // Check if SRP6 results match (password is correct), else send an error - if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20)) + if (M == logonProof->M1) { // Check auth token bool tokenSuccess = false; @@ -607,8 +576,8 @@ bool AuthSession::HandleLogonProof() // Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // No SQL injection (escaped user name) and IP address as received by socket - LoginDatabasePreparedStatement*stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); - stmt->setString(0, K.AsHexStr()); + LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); + stmt->setString(0, ByteArrayToHexStr(sessionKey)); stmt->setString(1, GetRemoteIpAddress().to_string()); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); @@ -616,15 +585,13 @@ bool AuthSession::HandleLogonProof() LoginDatabase.DirectExecute(stmt); // Finish SRP6 and send the final result to the client - sha.Initialize(); - sha.UpdateBigNumbers(&A, &M, &K, nullptr); - sha.Finalize(); + Trinity::Crypto::SHA1::Digest M2 = Trinity::Crypto::SHA1::GetDigestOf(A.ToByteArray<32>(), M, sessionKey); ByteBuffer packet; if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients { sAuthLogonProof_S proof; - memcpy(proof.M2, sha.GetDigest(), 20); + proof.M2 = M2; proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.AccountFlags = 0x00800000; // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) @@ -637,7 +604,7 @@ bool AuthSession::HandleLogonProof() else { sAuthLogonProof_S_Old proof; - memcpy(proof.M2, sha.GetDigest(), 20); + proof.M2 = M2; proof.cmd = AUTH_LOGON_PROOF; proof.error = 0; proof.unk2 = 0x00; @@ -760,12 +727,12 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result) Field* fields = result->Fetch(); _accountInfo.LoadResult(fields); - K.SetHexStr(fields[9].GetCString()); - _reconnectProof.SetRand(16 * 8); + HexStrToByteArray(fields[9].GetCString(), sessionKey.data()); + Trinity::Crypto::GetRandomBytes(_reconnectProof); _status = STATUS_RECONNECT_PROOF; pkt << uint8(WOW_SUCCESS); - pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random + pkt.append(_reconnectProof); pkt.append(VersionChallenge.data(), VersionChallenge.size()); SendPacket(pkt); @@ -778,19 +745,20 @@ bool AuthSession::HandleReconnectProof() sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer()); - if (_accountInfo.Login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) + if (_accountInfo.Login.empty()) return false; BigNumber t1; t1.SetBinary(reconnectProof->R1, 16); - SHA1Hash sha; - sha.Initialize(); + Trinity::Crypto::SHA1 sha; sha.UpdateData(_accountInfo.Login); - sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, nullptr); + sha.UpdateData(t1.ToByteArray<16>()); + sha.UpdateData(_reconnectProof); + sha.UpdateData(sessionKey); sha.Finalize(); - if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH)) + if (sha.GetDigest() == reconnectProof->R2) { if (!VerifyVersion(reconnectProof->R1, sizeof(reconnectProof->R1), reconnectProof->R3, true)) { @@ -939,17 +907,14 @@ void AuthSession::SetVSFields(const std::string& rI) I.SetHexStr(rI.c_str()); // In case of leading zeros in the rI hash, restore them - uint8 mDigest[SHA_DIGEST_LENGTH]; - memcpy(mDigest, I.AsByteArray(SHA_DIGEST_LENGTH).get(), SHA_DIGEST_LENGTH); - - std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH); + std::array<uint8, Trinity::Crypto::SHA1::DIGEST_LENGTH> mDigest = I.ToByteArray<Trinity::Crypto::SHA1::DIGEST_LENGTH>(false); - SHA1Hash sha; - sha.UpdateData(s.AsByteArray(uint32(BufferSizes::SRP_6_S)).get(), (uint32(BufferSizes::SRP_6_S))); - sha.UpdateData(mDigest, SHA_DIGEST_LENGTH); + Trinity::Crypto::SHA1 sha; + sha.UpdateData(s.ToByteArray<BufferSizes::SRP_6_S>()); + sha.UpdateData(mDigest); sha.Finalize(); BigNumber x; - x.SetBinary(sha.GetDigest(), sha.GetLength()); + x.SetBinary(sha.GetDigest()); v = g.ModExp(x, N); // No SQL injection (username escaped) @@ -960,13 +925,13 @@ void AuthSession::SetVSFields(const std::string& rI) LoginDatabase.Execute(stmt); } -bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect) +bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, Trinity::Crypto::SHA1::Digest const& versionProof, bool isReconnect) { if (!sConfigMgr->GetBoolDefault("StrictVersionCheck", false)) return true; - std::array<uint8, 20> zeros = { {} }; - std::array<uint8, 20> const* versionHash = nullptr; + Trinity::Crypto::SHA1::Digest zeros; + Trinity::Crypto::SHA1::Digest const* versionHash = nullptr; if (!isReconnect) { RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(_build); @@ -981,16 +946,16 @@ bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, uint8 const* vers if (!versionHash) return false; - if (!memcmp(versionHash->data(), zeros.data(), zeros.size())) + if (zeros == *versionHash) return true; // not filled serverside } else versionHash = &zeros; - SHA1Hash version; + Trinity::Crypto::SHA1 version; version.UpdateData(a, aLength); - version.UpdateData(versionHash->data(), versionHash->size()); + version.UpdateData(*versionHash); version.Finalize(); - return memcmp(versionProof, version.GetDigest(), version.GetLength()) == 0; + return (versionProof == version.GetDigest()); } diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 86bbb4a6f9a..44454f6138b 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -22,6 +22,7 @@ #include "BigNumber.h" #include "ByteBuffer.h" #include "Common.h" +#include "CryptoHash.h" #include "Optional.h" #include "Socket.h" #include "QueryResult.h" @@ -89,12 +90,12 @@ private: void SetVSFields(const std::string& rI); - bool VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect); + bool VerifyVersion(uint8 const* a, int32 aLength, Trinity::Crypto::SHA1::Digest const& versionProof, bool isReconnect); BigNumber N, s, g, v; BigNumber b, B; - BigNumber K; - BigNumber _reconnectProof; + std::array<uint8, 40> sessionKey; + std::array<uint8, 16> _reconnectProof; AuthStatus _status; AccountInfo _accountInfo; diff --git a/src/server/database/Updater/UpdateFetcher.cpp b/src/server/database/Updater/UpdateFetcher.cpp index d8f6cafacbc..76dabf37e66 100644 --- a/src/server/database/Updater/UpdateFetcher.cpp +++ b/src/server/database/Updater/UpdateFetcher.cpp @@ -19,10 +19,10 @@ #include "Common.h" #include "DBUpdater.h" #include "Field.h" +#include "CryptoHash.h" #include "Log.h" #include "QueryResult.h" #include "Util.h" -#include "SHA1.h" #include <boost/filesystem/operations.hpp> #include <fstream> #include <sstream> @@ -222,7 +222,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks, } // Calculate a Sha1 hash based on query content. - std::string const hash = CalculateSHA1Hash(ReadSQLUpdate(availableQuery.first)); + std::string const hash = ByteArrayToHexStr(Trinity::Crypto::SHA1::GetDigestOf(ReadSQLUpdate(availableQuery.first))); UpdateMode mode = MODE_APPLY; diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp index cc620e241f4..4b370181dee 100644 --- a/src/server/game/Accounts/AccountMgr.cpp +++ b/src/server/game/Accounts/AccountMgr.cpp @@ -18,12 +18,12 @@ #include "AccountMgr.h" #include "Config.h" #include "DatabaseEnv.h" +#include "CryptoHash.h" #include "Log.h" #include "ObjectAccessor.h" #include "Player.h" #include "Realm.h" #include "ScriptMgr.h" -#include "SHA1.h" #include "Util.h" #include "World.h" #include "WorldSession.h" @@ -379,14 +379,7 @@ uint32 AccountMgr::GetCharactersCount(uint32 accountId) std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password) { - SHA1Hash sha; - sha.Initialize(); - sha.UpdateData(name); - sha.UpdateData(":"); - sha.UpdateData(password); - sha.Finalize(); - - return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength()); + return ByteArrayToHexStr(Trinity::Crypto::SHA1::GetDigestOf(name, ":", password)); } bool AccountMgr::IsBannedAccount(std::string const& name) diff --git a/src/server/game/Scripting/ScriptReloadMgr.cpp b/src/server/game/Scripting/ScriptReloadMgr.cpp index f6619fa7ea9..580642dde66 100644 --- a/src/server/game/Scripting/ScriptReloadMgr.cpp +++ b/src/server/game/Scripting/ScriptReloadMgr.cpp @@ -40,13 +40,14 @@ ScriptReloadMgr* ScriptReloadMgr::instance() #include "BuiltInConfig.h" #include "Config.h" #include "GitRevision.h" +#include "CryptoHash.h" #include "Log.h" #include "MPSCQueue.h" #include "Regex.h" #include "ScriptMgr.h" -#include "SHA1.h" #include "StartProcess.h" #include "Timer.h" +#include "Util.h" #include "World.h" #include <boost/algorithm/string/replace.hpp> #include <boost/filesystem.hpp> @@ -756,7 +757,7 @@ private: auto path = fs::temp_directory_path(); path /= Trinity::StringFormat("tc_script_cache_%s_%s", GitRevision::GetBranch(), - CalculateSHA1Hash(sConfigMgr->GetFilename()).c_str()); + ByteArrayToHexStr(Trinity::Crypto::SHA1::GetDigestOf(sConfigMgr->GetFilename())).c_str()); return path; } diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 6c3cf1b43ff..abbf28c8bae 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -1209,7 +1209,7 @@ TransactionCallback& WorldSession::AddTransactionCallback(TransactionCallback&& return _transactionCallbacks.AddCallback(std::move(callback)); } -void WorldSession::InitWarden(BigNumber* k, std::string const& os) +void WorldSession::InitWarden(std::array<uint8, 40> const& k, std::string const& os) { if (os == "Win") { diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index e72ade20183..9d7cbc2cde7 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -34,7 +34,6 @@ #include <unordered_map> #include <boost/circular_buffer.hpp> -class BigNumber; class Creature; class GameObject; class InstanceSave; @@ -423,7 +422,7 @@ class TC_GAME_API WorldSession void SetPlayer(Player* player); uint8 Expansion() const { return m_expansion; } - void InitWarden(BigNumber* k, std::string const& os); + void InitWarden(std::array<uint8, 40> const& k, std::string const& os); /// Session in auth.queue currently void SetInQueue(bool state) { m_inQueue = state; } diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 05b5c8bb9b0..6dac06165c8 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -19,6 +19,8 @@ #include "BigNumber.h" #include "DatabaseEnv.h" #include "GameTime.h" +#include "CryptoHash.h" +#include "CryptoRandom.h" #include "IPLocation.h" #include "Opcodes.h" #include "PacketLog.h" @@ -26,7 +28,6 @@ #include "RBAC.h" #include "Realm.h" #include "ScriptMgr.h" -#include "SHA1.h" #include "World.h" #include "WorldSession.h" #include <memory> @@ -34,8 +35,9 @@ using boost::asio::ip::tcp; WorldSocket::WorldSocket(tcp::socket&& socket) - : Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096) + : Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096) { + Trinity::Crypto::GetRandomBytes(_authSeed); _headerBuffer.Resize(sizeof(ClientPktHeader)); } @@ -126,15 +128,9 @@ void WorldSocket::HandleSendAuthSession() { WorldPacket packet(SMSG_AUTH_CHALLENGE, 37); packet << uint32(1); // 1...31 - packet << uint32(_authSeed); + packet.append(_authSeed); - BigNumber seed1; - seed1.SetRand(16 * 8); - packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds - - BigNumber seed2; - seed2.SetRand(16 * 8); - packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds + packet.append(Trinity::Crypto::GetRandomBytes<32>()); // new encryption seeds SendPacketAndLogOpcode(packet); } @@ -212,7 +208,8 @@ bool WorldSocket::ReadHeaderHandler() { ASSERT(_headerBuffer.GetActiveSize() == sizeof(ClientPktHeader)); - _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader)); + if (_authCrypt.IsInitialized()) + _authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader)); ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer()); EndianConvertReverse(header->size); @@ -236,11 +233,11 @@ struct AuthSession uint32 LoginServerType = 0; uint32 RealmID = 0; uint32 Build = 0; - uint32 LocalChallenge = 0; + std::array<uint8, 4> LocalChallenge; uint32 LoginServerID = 0; uint32 RegionID = 0; uint64 DosResponse = 0; - uint8 Digest[SHA_DIGEST_LENGTH] = {}; + Trinity::Crypto::SHA1::Digest Digest; std::string Account; ByteBuffer AddonInfo; }; @@ -248,7 +245,7 @@ struct AuthSession struct AccountInfo { uint32 Id; - BigNumber SessionKey; + std::array<uint8, 40> SessionKey; std::string LastIP; bool IsLockedToIP; std::string LockCountry; @@ -273,7 +270,7 @@ struct AccountInfo // LEFT JOIN account r ON a.id = r.recruiter // WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1 Id = fields[0].GetUInt32(); - SessionKey.SetHexStr(fields[1].GetCString()); + HexStrToByteArray(fields[1].GetCString(), SessionKey.data()); LastIP = fields[2].GetString(); IsLockedToIP = fields[3].GetBool(); LockCountry = fields[4].GetString(); @@ -428,12 +425,12 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) recvPacket >> authSession->LoginServerID; recvPacket >> authSession->Account; recvPacket >> authSession->LoginServerType; - recvPacket >> authSession->LocalChallenge; + recvPacket.read(authSession->LocalChallenge); recvPacket >> authSession->RegionID; recvPacket >> authSession->BattlegroupID; recvPacket >> authSession->RealmID; // realmId from auth_database.realmlist table recvPacket >> authSession->DosResponse; - recvPacket.read(authSession->Digest, 20); + recvPacket.read(authSession->Digest); authSession->AddonInfo.resize(recvPacket.size() - recvPacket.rpos()); recvPacket.read(authSession->AddonInfo.contents(), authSession->AddonInfo.size()); // .contents will throw if empty, thats what we want @@ -470,7 +467,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes // This also allows to check for possible "hack" attempts on account // even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it - _authCrypt.Init(&account.SessionKey); + _authCrypt.Init(account.SessionKey); // First reject the connection if packet contains invalid data or realm state doesn't allow logging in if (sWorld->IsClosed()) @@ -501,17 +498,17 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes } // Check that Key and account name are the same on client and server - uint32 t = 0; + uint8 t[4] = { 0x00,0x00,0x00,0x00 }; - SHA1Hash sha; + Trinity::Crypto::SHA1 sha; sha.UpdateData(authSession->Account); - sha.UpdateData((uint8*)&t, 4); - sha.UpdateData((uint8*)&authSession->LocalChallenge, 4); - sha.UpdateData((uint8*)&_authSeed, 4); - sha.UpdateBigNumbers(&account.SessionKey, nullptr); + sha.UpdateData(t); + sha.UpdateData(authSession->LocalChallenge); + sha.UpdateData(_authSeed); + sha.UpdateData(account.SessionKey); sha.Finalize(); - if (memcmp(sha.GetDigest(), authSession->Digest, SHA_DIGEST_LENGTH) != 0) + if (sha.GetDigest() != authSession->Digest) { SendAuthResponseError(AUTH_FAILED); TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", account.Id, authSession->Account.c_str(), address.c_str()); @@ -601,7 +598,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes // Initialize Warden system only if it is enabled by config if (wardenActive) - _worldSession->InitWarden(&account.SessionKey, account.OS); + _worldSession->InitWarden(account.SessionKey, account.OS); _queryProcessor.AddCallback(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1))); AsyncRead(); diff --git a/src/server/game/Server/WorldSocket.h b/src/server/game/Server/WorldSocket.h index 4920280acb6..77511f774e3 100644 --- a/src/server/game/Server/WorldSocket.h +++ b/src/server/game/Server/WorldSocket.h @@ -112,7 +112,7 @@ private: bool HandlePing(WorldPacket& recvPacket); - uint32 _authSeed; + std::array<uint8, 4> _authSeed; AuthCrypt _authCrypt; TimePoint _LastPingTime; diff --git a/src/server/game/Warden/Warden.cpp b/src/server/game/Warden/Warden.cpp index 9f887cfedae..7fc532fd961 100644 --- a/src/server/game/Warden/Warden.cpp +++ b/src/server/game/Warden/Warden.cpp @@ -29,7 +29,7 @@ #include <openssl/sha.h> -Warden::Warden() : _session(nullptr), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), +Warden::Warden() : _session(nullptr), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0), _dataSent(false), _previousTimestamp(0), _module(nullptr), _initialized(false) { memset(_inputKey, 0, sizeof(_inputKey)); @@ -130,12 +130,12 @@ void Warden::Update() void Warden::DecryptData(uint8* buffer, uint32 length) { - _inputCrypto.UpdateData(length, buffer); + _inputCrypto.UpdateData(buffer, length); } void Warden::EncryptData(uint8* buffer, uint32 length) { - _outputCrypto.UpdateData(length, buffer); + _outputCrypto.UpdateData(buffer, length); } bool Warden::IsValidCheckSum(uint32 checksum, uint8 const* data, const uint16 length) diff --git a/src/server/game/Warden/Warden.h b/src/server/game/Warden/Warden.h index 24d6cf9bc34..3d9543a7412 100644 --- a/src/server/game/Warden/Warden.h +++ b/src/server/game/Warden/Warden.h @@ -18,11 +18,10 @@ #ifndef _WARDEN_BASE_H #define _WARDEN_BASE_H -#include <map> -#include "Cryptography/ARC4.h" -#include "Cryptography/BigNumber.h" +#include "ARC4.h" #include "ByteBuffer.h" #include "WardenCheckMgr.h" +#include <array> enum WardenOpcodes { @@ -100,7 +99,7 @@ class TC_GAME_API Warden Warden(); virtual ~Warden(); - virtual void Init(WorldSession* session, BigNumber* k) = 0; + virtual void Init(WorldSession* session, std::array<uint8, 40> const& K) = 0; virtual ClientWardenModule* GetModuleForClient() = 0; virtual void InitializeModule() = 0; virtual void RequestHash() = 0; @@ -125,8 +124,8 @@ class TC_GAME_API Warden uint8 _inputKey[16]; uint8 _outputKey[16]; uint8 _seed[16]; - ARC4 _inputCrypto; - ARC4 _outputCrypto; + Trinity::Crypto::ARC4 _inputCrypto; + Trinity::Crypto::ARC4 _outputCrypto; uint32 _checkTimer; // Timer for sending check requests uint32 _clientResponseTimer; // Timer for client response delay bool _dataSent; diff --git a/src/server/game/Warden/WardenCheckMgr.cpp b/src/server/game/Warden/WardenCheckMgr.cpp index aa8ca22f079..49ed703d1ca 100644 --- a/src/server/game/Warden/WardenCheckMgr.cpp +++ b/src/server/game/Warden/WardenCheckMgr.cpp @@ -85,19 +85,7 @@ void WardenCheckMgr::LoadWardenChecks() wardenCheck->Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION)); if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK) - { wardenCheck->Data.SetHexStr(data.c_str()); - int len = data.size() / 2; - - if (wardenCheck->Data.GetNumBytes() < len) - { - uint8 temp[24]; - memset(temp, 0, len); - memcpy(temp, wardenCheck->Data.AsByteArray().get(), wardenCheck->Data.GetNumBytes()); - std::reverse(temp, temp + len); - wardenCheck->Data.SetBinary((uint8*)temp, len); - } - } if (checkType == MEM_CHECK || checkType == MODULE_CHECK) MemChecksIdPool.push_back(id); @@ -120,16 +108,6 @@ void WardenCheckMgr::LoadWardenChecks() { WardenCheckResult* wr = new WardenCheckResult(); wr->Result.SetHexStr(checkResult.c_str()); - int len = checkResult.size() / 2; - if (wr->Result.GetNumBytes() < len) - { - uint8 *temp = new uint8[len]; - memset(temp, 0, len); - memcpy(temp, wr->Result.AsByteArray().get(), wr->Result.GetNumBytes()); - std::reverse(temp, temp + len); - wr->Result.SetBinary((uint8*)temp, len); - delete [] temp; - } CheckResultStore[id] = wr; } diff --git a/src/server/game/Warden/WardenMac.cpp b/src/server/game/Warden/WardenMac.cpp index 847a3cf69a0..e8a5b45cd76 100644 --- a/src/server/game/Warden/WardenMac.cpp +++ b/src/server/game/Warden/WardenMac.cpp @@ -15,18 +15,18 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Cryptography/WardenKeyGeneration.h" +#include "WardenMac.h" +#include "ByteBuffer.h" #include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" +#include "GameTime.h" #include "Log.h" #include "Opcodes.h" -#include "ByteBuffer.h" -#include "GameTime.h" #include "Player.h" +#include "SessionKeyGenerator.h" #include "Util.h" -#include "WardenMac.h" #include "WardenModuleMac.h" +#include "WorldPacket.h" +#include "WorldSession.h" #include <openssl/md5.h> @@ -34,11 +34,11 @@ WardenMac::WardenMac() : Warden() { } WardenMac::~WardenMac() { } -void WardenMac::Init(WorldSession* pClient, BigNumber* K) +void WardenMac::Init(WorldSession* pClient, std::array<uint8, 40> const& K) { _session = pClient; // Generate Warden Key - SHA1Randx WK(K->AsByteArray().get(), K->GetNumBytes()); + SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K); WK.Generate(_inputKey, 16); WK.Generate(_outputKey, 16); /* @@ -154,14 +154,14 @@ void WardenMac::HandleHashResult(ByteBuffer &buff) buff.rpos(buff.wpos()); - SHA1Hash sha1; + Trinity::Crypto::SHA1 sha1; sha1.UpdateData((uint8*)keyIn, 16); sha1.Finalize(); //const uint8 validHash[20] = { 0x56, 0x8C, 0x05, 0x4C, 0x78, 0x1A, 0x97, 0x2A, 0x60, 0x37, 0xA2, 0x29, 0x0C, 0x22, 0xB5, 0x25, 0x71, 0xA0, 0x6F, 0x4E }; // Verify key - if (memcmp(buff.contents() + 1, sha1.GetDigest(), 20) != 0) + if (memcmp(buff.contents() + 1, sha1.GetDigest().data(), 20) != 0) { TC_LOG_WARN("warden", "%s failed hash reply. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str()); return; @@ -235,16 +235,16 @@ void WardenMac::HandleData(ByteBuffer &buff) std::string str = "Test string!"; - SHA1Hash sha1; + Trinity::Crypto::SHA1 sha1; sha1.UpdateData(str); uint32 magic = 0xFEEDFACE; // unsure sha1.UpdateData((uint8*)&magic, 4); sha1.Finalize(); - uint8 sha1Hash[20]; - buff.read(sha1Hash, 20); + std::array<uint8, Trinity::Crypto::SHA1::DIGEST_LENGTH> sha1Hash; + buff.read(sha1Hash.data(), sha1Hash.size()); - if (memcmp(sha1Hash, sha1.GetDigest(), 20) != 0) + if (sha1Hash != sha1.GetDigest()) { TC_LOG_DEBUG("warden", "Handle data failed: SHA1 hash is wrong!"); //found = true; diff --git a/src/server/game/Warden/WardenMac.h b/src/server/game/Warden/WardenMac.h index 81ab864cf02..c186e546f9e 100644 --- a/src/server/game/Warden/WardenMac.h +++ b/src/server/game/Warden/WardenMac.h @@ -18,9 +18,7 @@ #ifndef _WARDEN_MAC_H #define _WARDEN_MAC_H -#include "Cryptography/ARC4.h" -#include <map> -#include "Cryptography/BigNumber.h" +#include "ARC4.h" #include "ByteBuffer.h" #include "Warden.h" @@ -33,7 +31,7 @@ class TC_GAME_API WardenMac : public Warden WardenMac(); ~WardenMac(); - void Init(WorldSession* session, BigNumber* k) override; + void Init(WorldSession* session, std::array<uint8, 40> const& k) override; ClientWardenModule* GetModuleForClient() override; void InitializeModule() override; void RequestHash() override; diff --git a/src/server/game/Warden/WardenWin.cpp b/src/server/game/Warden/WardenWin.cpp index f973bfad79c..f423ab2486e 100644 --- a/src/server/game/Warden/WardenWin.cpp +++ b/src/server/game/Warden/WardenWin.cpp @@ -15,34 +15,35 @@ * with this program. If not, see <http://www.gnu.org/licenses/>. */ -#include "Cryptography/HMACSHA1.h" -#include "Cryptography/WardenKeyGeneration.h" +#include "WardenWin.h" #include "Common.h" -#include "WorldPacket.h" -#include "WorldSession.h" -#include "Log.h" -#include "Opcodes.h" #include "ByteBuffer.h" -#include "Database/DatabaseEnv.h" +#include "CryptoRandom.h" +#include "DatabaseEnv.h" #include "GameTime.h" -#include "World.h" +#include "HMAC.h" +#include "Log.h" +#include "Opcodes.h" #include "Player.h" +#include "Random.h" +#include "SessionKeyGenerator.h" #include "Util.h" -#include "WardenWin.h" #include "WardenModuleWin.h" #include "WardenCheckMgr.h" -#include "Random.h" +#include "World.h" +#include "WorldPacket.h" +#include "WorldSession.h" #include <openssl/md5.h> WardenWin::WardenWin() : Warden(), _serverTicks(0) {} WardenWin::~WardenWin() { } -void WardenWin::Init(WorldSession* session, BigNumber* k) +void WardenWin::Init(WorldSession* session, std::array<uint8, 40> const& K) { _session = session; // Generate Warden Key - SHA1Randx WK(k->AsByteArray().get(), k->GetNumBytes()); + SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K); WK.Generate(_inputKey, 16); WK.Generate(_outputKey, 16); @@ -262,7 +263,8 @@ void WardenWin::RequestData() case PAGE_CHECK_A: case PAGE_CHECK_B: { - buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes()); + std::vector<uint8> data = wd->Data.ToByteVector(0, false); + buff.append(data.data(), data.size()); buff << uint32(wd->Address); buff << uint8(wd->Length); break; @@ -275,18 +277,16 @@ void WardenWin::RequestData() } case DRIVER_CHECK: { - buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes()); + std::vector<uint8> data = wd->Data.ToByteVector(0, false); + buff.append(data.data(), data.size()); buff << uint8(index++); break; } case MODULE_CHECK: { - uint32 seed = rand32(); - buff << uint32(seed); - HmacHash hmac(4, (uint8*)&seed); - hmac.UpdateData(wd->Str); - hmac.Finalize(); - buff.append(hmac.GetDigest(), hmac.GetLength()); + std::array<uint8, 4> seed = Trinity::Crypto::GetRandomBytes<4>(); + buff.append(seed); + buff.append(Trinity::Crypto::HMAC_SHA1::GetDigestOf(seed, wd->Str)); break; } /*case PROC_CHECK: @@ -391,7 +391,8 @@ void WardenWin::HandleData(ByteBuffer &buff) continue; } - if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false).get(), rd->Length) != 0) + std::vector<uint8> result = rs->Result.ToByteVector(); + if (memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0) { TC_LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId %u account Id %u", *itr, _session->GetAccountId()); checkFailed = *itr; @@ -470,7 +471,7 @@ void WardenWin::HandleData(ByteBuffer &buff) continue; } - if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false).get(), 20) != 0) // SHA1 + if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), 20) != 0) // SHA1 { TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId()); checkFailed = *itr; diff --git a/src/server/game/Warden/WardenWin.h b/src/server/game/Warden/WardenWin.h index c45d73572be..77f66f621a3 100644 --- a/src/server/game/Warden/WardenWin.h +++ b/src/server/game/Warden/WardenWin.h @@ -18,11 +18,11 @@ #ifndef _WARDEN_WIN_H #define _WARDEN_WIN_H -#include <map> #include "Cryptography/ARC4.h" #include "Cryptography/BigNumber.h" #include "ByteBuffer.h" #include "Warden.h" +#include <list> #pragma pack(push, 1) @@ -67,7 +67,7 @@ class TC_GAME_API WardenWin : public Warden WardenWin(); ~WardenWin(); - void Init(WorldSession* session, BigNumber* K) override; + void Init(WorldSession* session, std::array<uint8, 40> const& K) override; ClientWardenModule* GetModuleForClient() override; void InitializeModule() override; void RequestHash() override; diff --git a/src/server/scripts/Commands/cs_account.cpp b/src/server/scripts/Commands/cs_account.cpp index 9b87179aa7d..aec025e0301 100644 --- a/src/server/scripts/Commands/cs_account.cpp +++ b/src/server/scripts/Commands/cs_account.cpp @@ -27,6 +27,7 @@ EndScriptData */ #include "Base32.h" #include "Chat.h" #include "CryptoGenerics.h" +#include "CryptoRandom.h" #include "DatabaseEnv.h" #include "IpAddress.h" #include "IPLocation.h" @@ -39,7 +40,6 @@ EndScriptData */ #include "World.h" #include "WorldSession.h" #include <unordered_map> -#include <openssl/rand.h> using namespace Trinity::ChatCommands; @@ -131,7 +131,7 @@ public: static std::unordered_map<uint32, Trinity::Crypto::TOTP::Secret> suggestions; auto pair = suggestions.emplace(std::piecewise_construct, std::make_tuple(accountId), std::make_tuple(Trinity::Crypto::TOTP::RECOMMENDED_SECRET_LENGTH)); // std::vector 1-argument size_t constructor invokes resize if (pair.second) // no suggestion yet, generate random secret - RAND_bytes(pair.first->second.data(), pair.first->second.size()); + Trinity::Crypto::GetRandomBytes(pair.first->second); if (!pair.second && token) // suggestion already existed and token specified - validate { diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 549786f3aee..149545d10d6 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -20,6 +20,7 @@ #include "Define.h" #include "ByteConverter.h" +#include <array> #include <string> #include <vector> #include <cstring> @@ -351,6 +352,12 @@ class TC_SHARED_API ByteBuffer _rpos += len; } + template <size_t Size> + void read(std::array<uint8, Size>& arr) + { + read(arr.data(), Size); + } + void readPackGUID(uint64& guid) { if (rpos() + 1 > size()) @@ -438,6 +445,12 @@ class TC_SHARED_API ByteBuffer append(buffer.contents(), buffer.wpos()); } + template <size_t Size> + void append(std::array<uint8, Size> const& arr) + { + append(arr.data(), Size); + } + // can be used in SMSG_MONSTER_MOVE opcode void appendPackXYZ(float x, float y, float z) { diff --git a/src/server/shared/Secrets/SecretMgr.cpp b/src/server/shared/Secrets/SecretMgr.cpp index 590440973f5..a0180ae2363 100644 --- a/src/server/shared/Secrets/SecretMgr.cpp +++ b/src/server/shared/Secrets/SecretMgr.cpp @@ -190,13 +190,13 @@ Optional<std::string> SecretMgr::AttemptTransition(Secrets i, Optional<BigNumber if (!oldSecret) return Trinity::StringFormat("Cannot decrypt old TOTP tokens - add config key '%s' to authserver.conf!", secret_info[i].oldKey); - bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(totpSecret, oldSecret->AsByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>()); + bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(totpSecret, oldSecret->ToByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>()); if (!success) return Trinity::StringFormat("Cannot decrypt old TOTP tokens - value of '%s' is incorrect for some users!", secret_info[i].oldKey); } if (newSecret) - Trinity::Crypto::AEEncryptWithRandomIV<Trinity::Crypto::AES>(totpSecret, newSecret->AsByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>()); + Trinity::Crypto::AEEncryptWithRandomIV<Trinity::Crypto::AES>(totpSecret, newSecret->ToByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>()); LoginDatabasePreparedStatement* updateStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_TOTP_SECRET); updateStmt->setBinary(0, totpSecret); |