Reduce m2pack client hot-path overhead
Some checks failed
build / Windows Build (push) Has been cancelled

This commit is contained in:
server
2026-04-15 15:43:26 +02:00
parent cb0867432e
commit ef7cdf2809
3 changed files with 108 additions and 14 deletions

View File

@@ -190,24 +190,19 @@ bool CM2Pack::ValidateManifest()
bool CM2Pack::DecryptEntryPayload(const TM2PackEntry& entry, std::vector<uint8_t>& decrypted, CBufferPool* pPool)
{
const uint64_t begin = sizeof(TM2PackHeader) + entry.data_offset;
const auto* ciphertext = reinterpret_cast<const uint8_t*>(m_file.data() + begin);
std::vector<uint8_t> ciphertext_copy;
const auto* ciphertext = reinterpret_cast<const unsigned char*>(m_file.data() + begin);
if (pPool)
{
ciphertext_copy = pPool->Acquire(entry.stored_size);
decrypted = pPool->Acquire(entry.stored_size);
}
ciphertext_copy.resize(entry.stored_size);
memcpy(ciphertext_copy.data(), ciphertext, entry.stored_size);
decrypted.resize(entry.stored_size);
unsigned long long written = 0;
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
decrypted.data(),
&written,
nullptr,
ciphertext_copy.data(),
ciphertext_copy.size(),
ciphertext,
entry.stored_size,
reinterpret_cast<const unsigned char*>(entry.path.data()),
entry.path.size(),
entry.nonce.data(),
@@ -215,16 +210,12 @@ bool CM2Pack::DecryptEntryPayload(const TM2PackEntry& entry, std::vector<uint8_t
{
if (pPool)
{
pPool->Release(std::move(ciphertext_copy));
pPool->Release(std::move(decrypted));
}
return false;
}
decrypted.resize(static_cast<std::size_t>(written));
if (pPool)
{
pPool->Release(std::move(ciphertext_copy));
}
return true;
}
@@ -253,6 +244,10 @@ bool CM2Pack::GetFileWithPool(const TM2PackEntry& entry, std::vector<uint8_t>& r
result.resize(entry.original_size);
ZSTD_DCtx* dctx = GetThreadLocalZstdContext();
size_t written = ZSTD_decompressDCtx(dctx, result.data(), result.size(), compressed.data(), compressed.size());
if (pPool)
{
pPool->Release(std::move(compressed));
}
if (ZSTD_isError(written) || written != entry.original_size)
{
TraceError("CM2Pack::GetFileWithPool: zstd failed for '%s'", entry.path.c_str());
@@ -262,10 +257,19 @@ bool CM2Pack::GetFileWithPool(const TM2PackEntry& entry, std::vector<uint8_t>& r
}
default:
if (pPool)
{
pPool->Release(std::move(compressed));
}
TraceError("CM2Pack::GetFileWithPool: unsupported compression %u for '%s'", entry.compression, entry.path.c_str());
return false;
}
if (!ShouldVerifyM2PackPlaintextHash())
{
return true;
}
std::array<uint8_t, M2PACK_HASH_SIZE> plain_hash {};
crypto_generichash(
plain_hash.data(),

View File

@@ -1,6 +1,7 @@
#include "M2PackRuntimeKeyProvider.h"
#include <algorithm>
#include <cctype>
#include <cstring>
#include <string>
@@ -18,6 +19,7 @@ constexpr const char* M2PACK_ENV_MASTER_KEY = "M2PACK_MASTER_KEY_HEX";
constexpr const char* M2PACK_ENV_PUBLIC_KEY = "M2PACK_SIGN_PUBKEY_HEX";
constexpr const char* M2PACK_ENV_MAP_NAME = "M2PACK_KEY_MAP";
constexpr const char* M2PACK_ENV_KEY_ID = "M2PACK_KEY_ID";
constexpr const char* M2PACK_ENV_STRICT_HASH = "M2PACK_STRICT_HASH";
#pragma pack(push, 1)
struct M2PackSharedKeys
@@ -38,6 +40,7 @@ struct RuntimeKeyState
std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE> public_key {};
bool runtime_master_key = false;
bool runtime_public_key = false;
bool verify_plaintext_hash = false;
bool initialized = false;
};
@@ -100,6 +103,31 @@ uint32_t ParseUInt32(const std::string& value)
}
}
bool ParseBoolFlag(std::string value, bool& out)
{
value.erase(std::remove_if(value.begin(), value.end(), [](unsigned char ch) {
return std::isspace(ch) != 0;
}), value.end());
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char ch) {
return static_cast<char>(std::tolower(ch));
});
if (value == "1" || value == "true" || value == "yes" || value == "on")
{
out = true;
return true;
}
if (value == "0" || value == "false" || value == "no" || value == "off")
{
out = false;
return true;
}
return false;
}
const std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE>* FindCompiledPublicKey(uint32_t keyId)
{
for (std::size_t i = 0; i < M2PACK_SIGN_KEY_IDS.size(); ++i)
@@ -191,6 +219,19 @@ void ApplyCommandLineOption(const std::string& key, const std::string& value)
LoadFromSharedMapping(value);
return;
}
if (key == "--m2pack-strict-hash")
{
bool enabled = false;
if (ParseBoolFlag(value, enabled))
{
g_state.verify_plaintext_hash = enabled;
}
else
{
TraceError("Invalid value for --m2pack-strict-hash");
}
}
}
} // namespace
@@ -201,6 +242,9 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
return true;
g_state = RuntimeKeyState {};
#ifdef _DEBUG
g_state.verify_plaintext_hash = true;
#endif
const std::string mapName = GetEnvString(M2PACK_ENV_MAP_NAME);
if (!mapName.empty())
@@ -240,6 +284,16 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
TraceError("Invalid M2PACK_SIGN_PUBKEY_HEX value");
}
const std::string envStrictHash = GetEnvString(M2PACK_ENV_STRICT_HASH);
if (!envStrictHash.empty())
{
bool enabled = false;
if (ParseBoolFlag(envStrictHash, enabled))
g_state.verify_plaintext_hash = enabled;
else
TraceError("Invalid M2PACK_STRICT_HASH value");
}
int argc = 0;
PCHAR* argv = CommandLineToArgv(const_cast<PCHAR>(commandLine ? commandLine : ""), &argc);
if (argv)
@@ -247,6 +301,31 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
for (int i = 0; i < argc; ++i)
{
const std::string key = argv[i];
if (key == "--m2pack-strict-hash")
{
bool enabled = true;
if (i + 1 < argc)
{
const std::string next = argv[i + 1];
if (!next.starts_with("--"))
{
if (!ParseBoolFlag(next, enabled))
{
TraceError("Invalid value for --m2pack-strict-hash");
}
else
{
g_state.verify_plaintext_hash = enabled;
}
++i;
continue;
}
}
g_state.verify_plaintext_hash = enabled;
continue;
}
if ((key == "--m2pack-key-hex" || key == "--m2pack-pubkey-hex" || key == "--m2pack-key-map" || key == "--m2pack-key-id") && i + 1 < argc)
{
ApplyCommandLineOption(key, argv[i + 1]);
@@ -268,6 +347,11 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
Tracef("M2Pack runtime key provider: no runtime master key available; .m2p loading will be denied\n");
}
if (g_state.verify_plaintext_hash)
{
Tracef("M2Pack runtime key provider: plaintext hash verification enabled\n");
}
g_state.initialized = true;
return true;
}
@@ -311,3 +395,8 @@ bool IsM2PackUsingRuntimePublicKey()
{
return g_state.runtime_public_key;
}
bool ShouldVerifyM2PackPlaintextHash()
{
return g_state.verify_plaintext_hash;
}

View File

@@ -12,3 +12,4 @@ bool HasM2PackRuntimeMasterKey();
bool HasM2PackRuntimeKeysForArchiveLoad(uint32_t keyId);
bool IsM2PackUsingRuntimeMasterKey();
bool IsM2PackUsingRuntimePublicKey();
bool ShouldVerifyM2PackPlaintextHash();