Reduce m2pack client hot-path overhead
Some checks failed
build / Windows Build (push) Has been cancelled
Some checks failed
build / Windows Build (push) Has been cancelled
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -12,3 +12,4 @@ bool HasM2PackRuntimeMasterKey();
|
||||
bool HasM2PackRuntimeKeysForArchiveLoad(uint32_t keyId);
|
||||
bool IsM2PackUsingRuntimeMasterKey();
|
||||
bool IsM2PackUsingRuntimePublicKey();
|
||||
bool ShouldVerifyM2PackPlaintextHash();
|
||||
|
||||
Reference in New Issue
Block a user