Skip to content

Commit

Permalink
Add HMAC support (PR #2496)
Browse files Browse the repository at this point in the history
  • Loading branch information
Inder00 committed Sep 22, 2022
1 parent cece630 commit eebf228
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 3 deletions.
19 changes: 19 additions & 0 deletions Shared/mods/deathmatch/logic/Enums.cpp
Expand Up @@ -49,6 +49,16 @@ ADD_ENUM(EHashFunction::SHA384, "sha384")
ADD_ENUM(EHashFunction::SHA512, "sha512")
IMPLEMENT_ENUM_END("hash-function")

IMPLEMENT_ENUM_CLASS_BEGIN(HashFunctionType)
ADD_ENUM(HashFunctionType::MD5, "md5")
ADD_ENUM(HashFunctionType::SHA1, "sha1")
ADD_ENUM(HashFunctionType::SHA224, "sha224")
ADD_ENUM(HashFunctionType::SHA256, "sha256")
ADD_ENUM(HashFunctionType::SHA384, "sha384")
ADD_ENUM(HashFunctionType::SHA512, "sha512")
ADD_ENUM(HashFunctionType::HMAC, "hmac")
IMPLEMENT_ENUM_CLASS_END("hash-function")

IMPLEMENT_ENUM_CLASS_BEGIN(PasswordHashFunction)
ADD_ENUM(PasswordHashFunction::Bcrypt, "bcrypt")
IMPLEMENT_ENUM_CLASS_END("password-hash-function")
Expand All @@ -63,6 +73,15 @@ IMPLEMENT_ENUM_CLASS_BEGIN(KeyPairAlgorithm)
ADD_ENUM(KeyPairAlgorithm::RSA, "rsa")
IMPLEMENT_ENUM_CLASS_END("key-pair-algorithm")

IMPLEMENT_ENUM_CLASS_BEGIN(HmacAlgorithm)
ADD_ENUM(HmacAlgorithm::MD5, "md5")
ADD_ENUM(HmacAlgorithm::SHA1, "sha1")
ADD_ENUM(HmacAlgorithm::SHA224, "sha224")
ADD_ENUM(HmacAlgorithm::SHA256, "sha256")
ADD_ENUM(HmacAlgorithm::SHA384, "sha384")
ADD_ENUM(HmacAlgorithm::SHA512, "sha512")
IMPLEMENT_ENUM_CLASS_END("hmac-algorithm")

IMPLEMENT_ENUM_BEGIN(ePacketID)
ADD_ENUM1(PACKET_ID_SERVER_JOIN)
ADD_ENUM1(PACKET_ID_SERVER_JOIN_DATA)
Expand Down
2 changes: 2 additions & 0 deletions Shared/mods/deathmatch/logic/Enums.h
Expand Up @@ -67,8 +67,10 @@ enum eEulerRotationOrder
DECLARE_ENUM(eEulerRotationOrder);

DECLARE_ENUM(EHashFunction::EHashFunctionType);
DECLARE_ENUM_CLASS(HashFunctionType);
DECLARE_ENUM_CLASS(PasswordHashFunction);
DECLARE_ENUM_CLASS(StringEncodeFunction);
DECLARE_ENUM_CLASS(KeyPairAlgorithm);
DECLARE_ENUM_CLASS(HmacAlgorithm);

DECLARE_ENUM(ePacketID);
83 changes: 81 additions & 2 deletions Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp
Expand Up @@ -54,9 +54,88 @@ std::string CLuaCryptDefs::Sha256(std::string strSourceData)
return GenerateSha256HexString(strSourceData);
}

std::string CLuaCryptDefs::Hash(EHashFunctionType hashFunction, std::string strSourceData)
std::variant<std::string, bool> CLuaCryptDefs::Hash(lua_State* const luaVM, HashFunctionType hashFunction, std::string strSourceData,
std::optional<std::unordered_map<std::string, std::string>> options)
{
return GenerateHashHexString(hashFunction, strSourceData).ToLower();
try
{
switch (hashFunction)
{
case HashFunctionType::MD5:
return SharedUtil::Hash<CryptoPP::MD5>(strSourceData).ToLower();

case HashFunctionType::SHA1:
return SharedUtil::Hash<CryptoPP::SHA1>(strSourceData).ToLower();

case HashFunctionType::SHA224:
return SharedUtil::Hash<CryptoPP::SHA224>(strSourceData).ToLower();

case HashFunctionType::SHA256:
return SharedUtil::Hash<CryptoPP::SHA256>(strSourceData).ToLower();

case HashFunctionType::SHA384:
return SharedUtil::Hash<CryptoPP::SHA384>(strSourceData).ToLower();

case HashFunctionType::SHA512:
return SharedUtil::Hash<CryptoPP::SHA512>(strSourceData).ToLower();

case HashFunctionType::HMAC:

// check does option table exists
if (!options.has_value())
throw std::invalid_argument("Invalid value for fields 'key' and 'algorithm'");

// vars
std::unordered_map<std::string, std::string>& optionsMap = options.value();
std::string& key = optionsMap["key"];
std::string& algorithm = optionsMap["algorithm"];
HmacAlgorithm hmacAlgorithm;

// check does key option is empty
if (key.empty())
throw std::invalid_argument("Invalid value for field 'key'");

// check does algorithm option is empty
if (algorithm.empty())
throw std::invalid_argument("Invalid value for field 'algorithm'");

// Parse algorithm string to enum
StringToEnum(algorithm, hmacAlgorithm);

// process
switch (hmacAlgorithm)
{
case HmacAlgorithm::MD5:
return SharedUtil::Hmac<CryptoPP::MD5>(strSourceData, key).ToLower();

case HmacAlgorithm::SHA1:
return SharedUtil::Hmac<CryptoPP::SHA1>(strSourceData, key).ToLower();

case HmacAlgorithm::SHA224:
return SharedUtil::Hmac<CryptoPP::SHA224>(strSourceData, key).ToLower();

case HmacAlgorithm::SHA256:
return SharedUtil::Hmac<CryptoPP::SHA256>(strSourceData, key).ToLower();

case HmacAlgorithm::SHA384:
return SharedUtil::Hmac<CryptoPP::SHA384>(strSourceData, key).ToLower();

case HmacAlgorithm::SHA512:
return SharedUtil::Hmac<CryptoPP::SHA512>(strSourceData, key).ToLower();

}

throw std::invalid_argument("Invalid hmac algorithm");
}

throw std::invalid_argument("Unknown algorithm");

}
catch (std::exception& ex)
{
m_pScriptDebugging->LogWarning(luaVM, ex.what());
return false;
}
}

std::string CLuaCryptDefs::TeaEncode(std::string str, std::string key)
Expand Down
3 changes: 2 additions & 1 deletion Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.h
Expand Up @@ -20,7 +20,8 @@ class CLuaCryptDefs : public CLuaDefs

static std::string Md5(std::string strMd5);

static std::string Hash(EHashFunctionType hashFunction, std::string strSourceData);
static std::variant<std::string, bool> Hash(lua_State* const luaVM, HashFunctionType hashFunction, std::string strSourceData,
std::optional<std::unordered_map<std::string, std::string>> options);

static std::string TeaEncode(std::string str, std::string key);
static std::string TeaDecode(std::string str, std::string key);
Expand Down
29 changes: 29 additions & 0 deletions Shared/sdk/SharedUtil.Crypto.h
Expand Up @@ -13,6 +13,9 @@
#include <cryptopp/rsa.h>
#include <cryptopp/modes.h>
#include <cryptopp/osrng.h>
#include <cryptopp/hmac.h>
#include <cryptopp/hex.h>
#include <cryptopp/md5.h>
#include "SString.h"

namespace SharedUtil
Expand All @@ -38,6 +41,32 @@ namespace SharedUtil
return result;
}

template <class HashType>
inline SString Hash(const SString& value)
{
SString result;
HashType hashType{};

CryptoPP::StringSource ss(value, true, new CryptoPP::HashFilter(hashType, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result))));

return result;
}

template <class HmacType>
inline SString Hmac(const SString& value, const SString& key)
{
SString mac;
SString result;

CryptoPP::HMAC<HmacType> hmac(reinterpret_cast<const CryptoPP::byte*>(key.c_str()), key.size());

CryptoPP::StringSource ssMac(value, true, new CryptoPP::HashFilter(hmac, new CryptoPP::StringSink(mac)));
CryptoPP::StringSource ssResult(mac, true, new CryptoPP::HexEncoder(new CryptoPP::StringSink(result)));

return result;
}


inline KeyPair GenerateRsaKeyPair(const unsigned int size)
{
KeyPair rsaKeyPair;
Expand Down
21 changes: 21 additions & 0 deletions Shared/sdk/SharedUtil.Hash.h
Expand Up @@ -27,6 +27,17 @@ namespace EHashFunction
}
using EHashFunction::EHashFunctionType;

enum class HashFunctionType
{
MD5,
SHA1,
SHA224,
SHA256,
SHA384,
SHA512,
HMAC,
};

enum class PasswordHashFunction
{
Bcrypt
Expand All @@ -44,6 +55,16 @@ enum class KeyPairAlgorithm
RSA
};

enum class HmacAlgorithm
{
MD5,
SHA1,
SHA224,
SHA256,
SHA384,
SHA512,
};

namespace SharedUtil
{
struct MD5
Expand Down
43 changes: 43 additions & 0 deletions Shared/sdk/SharedUtil.Tests.hpp
Expand Up @@ -782,6 +782,49 @@ void SharedUtil_Hash_Tests()
TEST_END
}

// Hmac Test
{
TEST_FUNCTION
SString hmacResult;
switch (algorithm)
{
case HmacAlgorithm::MD5:
hmacResult = SharedUtil::Hmac<CryptoPP::MD5>(data, key);
break;
case HmacAlgorithm::SHA1:
hmacResult = SharedUtil::Hmac<CryptoPP::SHA1>(data, key);
break;
case HmacAlgorithm::SHA224:
hmacResult = SharedUtil::Hmac<CryptoPP::SHA224>(data, key);
break;
case HmacAlgorithm::SHA256:
hmacResult = SharedUtil::Hmac<CryptoPP::SHA256>(data, key);
break;
case HmacAlgorithm::SHA384:
hmacResult = SharedUtil::Hmac<CryptoPP::SHA384>(data, key);
break;
case HmacAlgorithm::SHA512:
hmacResult = SharedUtil::Hmac<CryptoPP::SHA512>(data, key);
break;
}
assert(!hmacResult.empty());
assert(hmacResult == result);
TEST_VARS
const SString data;
const SString key;
const SString result;
const HmacAlgorithm algorithm;
TEST_DATA = {
{"Hello world", "hecker was there", "657C7088ADEA11E6482EE794D3E5489C", HmacAlgorithm::MD5},
{"cstddef", "", "0339B2CA65A63209C656047C5B11ADA73B63A367", HmacAlgorithm::SHA1},
{"Hello thereHello there", "!@#$%^&*()_+|:<>", "A7A00E964617DFB59324502786BB28AEEF22898C00B226A7B4A1D607", HmacAlgorithm::SHA224},
{"!@#$%^&*()_+|:<>", "cppsymbol", "46105B670A55EA8808B16FFC8B88507EAEA3E9D1F5A55891CD04136FB2AADA15", HmacAlgorithm::SHA256},
{"value", "sha384", "CEC945A598261608218BA685EEC02D773F57AFD6410AF67D2A2D1B0D22DAE8624D0F369E55C8C7E774805204A2B5A75A", HmacAlgorithm::SHA384},
{"", "gHtySkGerYnhDxAs", "4E6E87CE637808642B902A07F43CA6A1CFE4346054C0C8C542A67C4BF206708CF5AFE3F1BB6D53DCE3469CDEA1CE11A0892EE2F95322C45D2CB809F165AD3BB3", HmacAlgorithm::SHA512},
};
TEST_END
}

// RSA keypair generation and encryption test
{
TEST_FUNCTION
Expand Down

0 comments on commit eebf228

Please sign in to comment.