diff --git a/Server/mods/deathmatch/logic/CResourceChecker.Data.h b/Server/mods/deathmatch/logic/CResourceChecker.Data.h index 47292bb388..99ea3ecb0b 100644 --- a/Server/mods/deathmatch/logic/CResourceChecker.Data.h +++ b/Server/mods/deathmatch/logic/CResourceChecker.Data.h @@ -146,6 +146,10 @@ namespace // Ped jetpacks //{false, "doesPedHaveJetPack", "isPedWearingJetpack"}, + + // Base Encoding & Decoding + {false, "base64Encode", "encodeString"}, + {false, "base64Decode", "decodeString"} }; SDeprecatedItem serverDeprecatedList[] = { @@ -244,5 +248,9 @@ namespace // Old Discord implementation (see #2499) {true, "setPlayerDiscordJoinParams", "See GitHub PR #2499 for more details"}, + + // Base Encoding & Decoding + {false, "base64Encode", "encodeString"}, + {false, "base64Decode", "decodeString"} }; } // namespace diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaCompatibilityDefs.cpp b/Server/mods/deathmatch/logic/luadefs/CLuaCompatibilityDefs.cpp index 368feac3c1..0336b375b0 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaCompatibilityDefs.cpp +++ b/Server/mods/deathmatch/logic/luadefs/CLuaCompatibilityDefs.cpp @@ -13,6 +13,7 @@ #include "CLuaVehicleDefs.h" #include "CLuaPedDefs.h" #include "CLuaPlayerDefs.h" +#include "luadefs/CLuaCryptDefs.h" #include "luadefs/CLuaXMLDefs.h" #include diff --git a/Shared/mods/deathmatch/logic/Enums.cpp b/Shared/mods/deathmatch/logic/Enums.cpp index f81cc6a364..d08eee1450 100644 --- a/Shared/mods/deathmatch/logic/Enums.cpp +++ b/Shared/mods/deathmatch/logic/Enums.cpp @@ -67,6 +67,8 @@ IMPLEMENT_ENUM_CLASS_BEGIN(StringEncodeFunction) ADD_ENUM(StringEncodeFunction::TEA, "tea") ADD_ENUM(StringEncodeFunction::AES128, "aes128") ADD_ENUM(StringEncodeFunction::RSA, "rsa") +ADD_ENUM(StringEncodeFunction::BASE64, "base64") +ADD_ENUM(StringEncodeFunction::BASE32, "base32") IMPLEMENT_ENUM_CLASS_END("string-encode-function") IMPLEMENT_ENUM_CLASS_BEGIN(KeyPairAlgorithm) diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp index 29d5689bb5..ec63d4ce7f 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp @@ -31,7 +31,7 @@ void CLuaCryptDefs::LoadFunctions() {"generateKeyPair", ArgumentParser}, {"passwordVerify", PasswordVerify}, {"encodeString", EncodeString}, - {"decodeString", DecodeString}, + {"decodeString", DecodeString} }; // Add functions @@ -402,7 +402,11 @@ int CLuaCryptDefs::EncodeString(lua_State* luaVM) CScriptArgReader argStream(luaVM); argStream.ReadEnumString(algorithm); argStream.ReadString(data); - argStream.ReadStringMap(options); + + if ((algorithm != StringEncodeFunction::BASE64 && algorithm != StringEncodeFunction::BASE32) || argStream.NextIsTable()) + { + argStream.ReadStringMap(options); + } argStream.ReadFunction(luaFunctionRef, LUA_REFNIL); argStream.ReadFunctionComplete(); @@ -589,6 +593,140 @@ int CLuaCryptDefs::EncodeString(lua_State* luaVM) } return 1; } + case StringEncodeFunction::BASE64: + { + const SString variant = options["variant"].ToUpper(); + + if (!variant.empty() && variant != "URL") + { + m_pScriptDebugging->LogCustom(luaVM, "Invalid value for field 'variant'"); + lua::Push(luaVM, false); + return 1; + } + + // Async + if (VERIFY_FUNCTION(luaFunctionRef)) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + if (pLuaMain) + { + CLuaShared::GetAsyncTaskScheduler()->PushTask( + [data, variant] + { + try + { + return std::make_pair(SharedUtil::Base64encode(data, variant), true); + } + catch (const CryptoPP::Exception& ex) + { + return std::make_pair(SString(ex.GetWhat()), false); + } + }, + [luaFunctionRef](const std::pair& result) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM()); + if (pLuaMain) + { + CLuaArguments arguments; + if (result.second) + { + arguments.PushString(result.first); + arguments.Call(pLuaMain, luaFunctionRef); + } + else + { + m_pScriptDebugging->LogWarning(luaFunctionRef.GetLuaVM(), result.first.c_str()); + arguments.PushBoolean(false); + arguments.Call(pLuaMain, luaFunctionRef); + } + } + }); + + lua::Push(luaVM, true); + } + } + else // Sync + { + try + { + lua::Push(luaVM, SharedUtil::Base64encode(data, variant)); + } + catch (const CryptoPP::Exception& ex) + { + m_pScriptDebugging->LogWarning(luaVM, ex.what()); + lua::Push(luaVM, false); + } + return 1; + } + return 1; + } + case StringEncodeFunction::BASE32: + { + const SString variant = options["variant"].ToUpper(); + + if (!variant.empty() && variant != "HEX") + { + m_pScriptDebugging->LogCustom(luaVM, "Invalid value for field 'variant'"); + lua::Push(luaVM, false); + return 1; + } + + // Async + if (VERIFY_FUNCTION(luaFunctionRef)) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + if (pLuaMain) + { + CLuaShared::GetAsyncTaskScheduler()->PushTask( + [data, variant] + { + try + { + return std::make_pair(SharedUtil::Base32encode(data, variant), true); + } + catch (const CryptoPP::Exception& ex) + { + return std::make_pair(SString(ex.GetWhat()), false); + } + }, + [luaFunctionRef](const std::pair& result) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM()); + if (pLuaMain) + { + CLuaArguments arguments; + if (result.second) + { + arguments.PushString(result.first); + arguments.Call(pLuaMain, luaFunctionRef); + } + else + { + m_pScriptDebugging->LogWarning(luaFunctionRef.GetLuaVM(), result.first.c_str()); + arguments.PushBoolean(false); + arguments.Call(pLuaMain, luaFunctionRef); + } + } + }); + + lua::Push(luaVM, true); + } + } + else // Sync + { + try + { + lua::Push(luaVM, SharedUtil::Base32encode(data, variant)); + } + catch (const CryptoPP::Exception& ex) + { + m_pScriptDebugging->LogWarning(luaVM, ex.what()); + lua::Push(luaVM, false); + } + return 1; + } + return 1; + } default: { m_pScriptDebugging->LogCustom(luaVM, "Unknown encryption algorithm"); @@ -614,7 +752,11 @@ int CLuaCryptDefs::DecodeString(lua_State* luaVM) CScriptArgReader argStream(luaVM); argStream.ReadEnumString(algorithm); argStream.ReadString(data); - argStream.ReadStringMap(options); + + if ((algorithm != StringEncodeFunction::BASE64 && algorithm != StringEncodeFunction::BASE32) || argStream.NextIsTable()) + { + argStream.ReadStringMap(options); + } argStream.ReadFunction(luaFunctionRef, LUA_REFNIL); argStream.ReadFunctionComplete(); @@ -808,6 +950,140 @@ int CLuaCryptDefs::DecodeString(lua_State* luaVM) } return 1; } + case StringEncodeFunction::BASE64: + { + const SString variant = options["variant"].ToUpper(); + + if (!variant.empty() && variant != "URL") + { + m_pScriptDebugging->LogCustom(luaVM, "Invalid value for field 'variant'"); + lua::Push(luaVM, false); + return 1; + } + + // Async + if (VERIFY_FUNCTION(luaFunctionRef)) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + if (pLuaMain) + { + CLuaShared::GetAsyncTaskScheduler()->PushTask( + [data, variant] + { + try + { + return std::make_pair(SharedUtil::Base64decode(data, variant), true); + } + catch (const CryptoPP::Exception& ex) + { + return std::make_pair(SString(ex.GetWhat()), false); + } + }, + [luaFunctionRef](const std::pair& result) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM()); + if (pLuaMain) + { + CLuaArguments arguments; + if (result.second) + { + arguments.PushString(result.first); + arguments.Call(pLuaMain, luaFunctionRef); + } + else + { + m_pScriptDebugging->LogWarning(luaFunctionRef.GetLuaVM(), result.first.c_str()); + arguments.PushBoolean(false); + arguments.Call(pLuaMain, luaFunctionRef); + } + } + }); + + lua::Push(luaVM, true); + } + } + else // Sync + { + try + { + lua::Push(luaVM, SharedUtil::Base64decode(data, variant)); + } + catch (const CryptoPP::Exception& ex) + { + m_pScriptDebugging->LogWarning(luaVM, ex.what()); + lua::Push(luaVM, false); + } + return 1; + } + return 1; + } + case StringEncodeFunction::BASE32: + { + const SString variant = options["variant"].ToUpper(); + + if (!variant.empty() && variant != "HEX") + { + m_pScriptDebugging->LogCustom(luaVM, "Invalid value for field 'variant'"); + lua::Push(luaVM, false); + return 1; + } + + // Async + if (VERIFY_FUNCTION(luaFunctionRef)) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + if (pLuaMain) + { + CLuaShared::GetAsyncTaskScheduler()->PushTask( + [data, variant] + { + try + { + return std::make_pair(SharedUtil::Base32decode(data, variant), true); + } + catch (const CryptoPP::Exception& ex) + { + return std::make_pair(SString(ex.GetWhat()), false); + } + }, + [luaFunctionRef](const std::pair& result) + { + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM()); + if (pLuaMain) + { + CLuaArguments arguments; + if (result.second) + { + arguments.PushString(result.first); + arguments.Call(pLuaMain, luaFunctionRef); + } + else + { + m_pScriptDebugging->LogWarning(luaFunctionRef.GetLuaVM(), result.first.c_str()); + arguments.PushBoolean(false); + arguments.Call(pLuaMain, luaFunctionRef); + } + } + }); + + lua::Push(luaVM, true); + } + } + else // Sync + { + try + { + lua::Push(luaVM, SharedUtil::Base32decode(data, variant)); + } + catch (const CryptoPP::Exception& ex) + { + m_pScriptDebugging->LogWarning(luaVM, ex.what()); + lua::Push(luaVM, false); + } + return 1; + } + return 1; + } default: { m_pScriptDebugging->LogCustom(luaVM, "Unknown encryption algorithm"); diff --git a/Shared/sdk/SharedUtil.Crypto.h b/Shared/sdk/SharedUtil.Crypto.h index 7d5413c94c..a44cb22c5a 100644 --- a/Shared/sdk/SharedUtil.Crypto.h +++ b/Shared/sdk/SharedUtil.Crypto.h @@ -9,6 +9,7 @@ *****************************************************************************/ #pragma once #include +#include #include #include #include @@ -25,18 +26,66 @@ namespace SharedUtil SString publicKey, privateKey; }; - inline SString Base64encode(const SString& data) + inline SString Base64encode(const SString& data, const SString& variant = SString()) { - SString result; - CryptoPP::StringSource ss(data, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(result), false)); // Memory is freed automatically + SString result; + + if (variant == "URL") + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base64URLEncoder(new CryptoPP::StringSink(result), false)); + } + else + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base64Encoder(new CryptoPP::StringSink(result), false)); + } + + return result; + } + + inline SString Base64decode(const SString& data, const SString& variant = SString()) + { + SString result; + + if (variant == "URL") + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base64URLDecoder(new CryptoPP::StringSink(result))); + } + else + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(result))); + } return result; } - inline SString Base64decode(const SString& data) + inline SString Base32encode(const SString& data, const SString& variant = SString()) { - SString result; - CryptoPP::StringSource ss(data, true, new CryptoPP::Base64Decoder(new CryptoPP::StringSink(result))); // Memory is freed automatically + SString result; + + if (variant == "HEX") + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base32HexEncoder(new CryptoPP::StringSink(result), false)); + } + else + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base32Encoder(new CryptoPP::StringSink(result), false)); + } + + return result; + } + + inline SString Base32decode(const SString& data, const SString& variant = SString()) + { + SString result; + + if (variant == "HEX") + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base32HexDecoder(new CryptoPP::StringSink(result))); + } + else + { + CryptoPP::StringSource ss(data, true, new CryptoPP::Base32Decoder(new CryptoPP::StringSink(result))); + } return result; } diff --git a/Shared/sdk/SharedUtil.Hash.h b/Shared/sdk/SharedUtil.Hash.h index 29426c569a..1aa28e82ce 100644 --- a/Shared/sdk/SharedUtil.Hash.h +++ b/Shared/sdk/SharedUtil.Hash.h @@ -48,6 +48,8 @@ enum class StringEncodeFunction TEA, AES128, RSA, + BASE64, + BASE32 }; enum class KeyPairAlgorithm