diff options
Diffstat (limited to 'src/common')
23 files changed, 557 insertions, 495 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); |
