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)
|
bool CM2Pack::DecryptEntryPayload(const TM2PackEntry& entry, std::vector<uint8_t>& decrypted, CBufferPool* pPool)
|
||||||
{
|
{
|
||||||
const uint64_t begin = sizeof(TM2PackHeader) + entry.data_offset;
|
const uint64_t begin = sizeof(TM2PackHeader) + entry.data_offset;
|
||||||
const auto* ciphertext = reinterpret_cast<const uint8_t*>(m_file.data() + begin);
|
const auto* ciphertext = reinterpret_cast<const unsigned char*>(m_file.data() + begin);
|
||||||
|
|
||||||
std::vector<uint8_t> ciphertext_copy;
|
|
||||||
if (pPool)
|
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);
|
decrypted.resize(entry.stored_size);
|
||||||
unsigned long long written = 0;
|
unsigned long long written = 0;
|
||||||
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
|
if (crypto_aead_xchacha20poly1305_ietf_decrypt(
|
||||||
decrypted.data(),
|
decrypted.data(),
|
||||||
&written,
|
&written,
|
||||||
nullptr,
|
nullptr,
|
||||||
ciphertext_copy.data(),
|
ciphertext,
|
||||||
ciphertext_copy.size(),
|
entry.stored_size,
|
||||||
reinterpret_cast<const unsigned char*>(entry.path.data()),
|
reinterpret_cast<const unsigned char*>(entry.path.data()),
|
||||||
entry.path.size(),
|
entry.path.size(),
|
||||||
entry.nonce.data(),
|
entry.nonce.data(),
|
||||||
@@ -215,16 +210,12 @@ bool CM2Pack::DecryptEntryPayload(const TM2PackEntry& entry, std::vector<uint8_t
|
|||||||
{
|
{
|
||||||
if (pPool)
|
if (pPool)
|
||||||
{
|
{
|
||||||
pPool->Release(std::move(ciphertext_copy));
|
pPool->Release(std::move(decrypted));
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
decrypted.resize(static_cast<std::size_t>(written));
|
decrypted.resize(static_cast<std::size_t>(written));
|
||||||
if (pPool)
|
|
||||||
{
|
|
||||||
pPool->Release(std::move(ciphertext_copy));
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,6 +244,10 @@ bool CM2Pack::GetFileWithPool(const TM2PackEntry& entry, std::vector<uint8_t>& r
|
|||||||
result.resize(entry.original_size);
|
result.resize(entry.original_size);
|
||||||
ZSTD_DCtx* dctx = GetThreadLocalZstdContext();
|
ZSTD_DCtx* dctx = GetThreadLocalZstdContext();
|
||||||
size_t written = ZSTD_decompressDCtx(dctx, result.data(), result.size(), compressed.data(), compressed.size());
|
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)
|
if (ZSTD_isError(written) || written != entry.original_size)
|
||||||
{
|
{
|
||||||
TraceError("CM2Pack::GetFileWithPool: zstd failed for '%s'", entry.path.c_str());
|
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:
|
default:
|
||||||
|
if (pPool)
|
||||||
|
{
|
||||||
|
pPool->Release(std::move(compressed));
|
||||||
|
}
|
||||||
TraceError("CM2Pack::GetFileWithPool: unsupported compression %u for '%s'", entry.compression, entry.path.c_str());
|
TraceError("CM2Pack::GetFileWithPool: unsupported compression %u for '%s'", entry.compression, entry.path.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ShouldVerifyM2PackPlaintextHash())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::array<uint8_t, M2PACK_HASH_SIZE> plain_hash {};
|
std::array<uint8_t, M2PACK_HASH_SIZE> plain_hash {};
|
||||||
crypto_generichash(
|
crypto_generichash(
|
||||||
plain_hash.data(),
|
plain_hash.data(),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "M2PackRuntimeKeyProvider.h"
|
#include "M2PackRuntimeKeyProvider.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
#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_PUBLIC_KEY = "M2PACK_SIGN_PUBKEY_HEX";
|
||||||
constexpr const char* M2PACK_ENV_MAP_NAME = "M2PACK_KEY_MAP";
|
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_KEY_ID = "M2PACK_KEY_ID";
|
||||||
|
constexpr const char* M2PACK_ENV_STRICT_HASH = "M2PACK_STRICT_HASH";
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
struct M2PackSharedKeys
|
struct M2PackSharedKeys
|
||||||
@@ -38,6 +40,7 @@ struct RuntimeKeyState
|
|||||||
std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE> public_key {};
|
std::array<uint8_t, M2PACK_PUBLIC_KEY_SIZE> public_key {};
|
||||||
bool runtime_master_key = false;
|
bool runtime_master_key = false;
|
||||||
bool runtime_public_key = false;
|
bool runtime_public_key = false;
|
||||||
|
bool verify_plaintext_hash = false;
|
||||||
bool initialized = 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)
|
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)
|
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);
|
LoadFromSharedMapping(value);
|
||||||
return;
|
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
|
} // namespace
|
||||||
@@ -201,6 +242,9 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
|
|||||||
return true;
|
return true;
|
||||||
|
|
||||||
g_state = RuntimeKeyState {};
|
g_state = RuntimeKeyState {};
|
||||||
|
#ifdef _DEBUG
|
||||||
|
g_state.verify_plaintext_hash = true;
|
||||||
|
#endif
|
||||||
|
|
||||||
const std::string mapName = GetEnvString(M2PACK_ENV_MAP_NAME);
|
const std::string mapName = GetEnvString(M2PACK_ENV_MAP_NAME);
|
||||||
if (!mapName.empty())
|
if (!mapName.empty())
|
||||||
@@ -240,6 +284,16 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
|
|||||||
TraceError("Invalid M2PACK_SIGN_PUBKEY_HEX value");
|
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;
|
int argc = 0;
|
||||||
PCHAR* argv = CommandLineToArgv(const_cast<PCHAR>(commandLine ? commandLine : ""), &argc);
|
PCHAR* argv = CommandLineToArgv(const_cast<PCHAR>(commandLine ? commandLine : ""), &argc);
|
||||||
if (argv)
|
if (argv)
|
||||||
@@ -247,6 +301,31 @@ bool InitializeM2PackRuntimeKeyProvider(const char* commandLine)
|
|||||||
for (int i = 0; i < argc; ++i)
|
for (int i = 0; i < argc; ++i)
|
||||||
{
|
{
|
||||||
const std::string key = argv[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)
|
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]);
|
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");
|
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;
|
g_state.initialized = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -311,3 +395,8 @@ bool IsM2PackUsingRuntimePublicKey()
|
|||||||
{
|
{
|
||||||
return g_state.runtime_public_key;
|
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 HasM2PackRuntimeKeysForArchiveLoad(uint32_t keyId);
|
||||||
bool IsM2PackUsingRuntimeMasterKey();
|
bool IsM2PackUsingRuntimeMasterKey();
|
||||||
bool IsM2PackUsingRuntimePublicKey();
|
bool IsM2PackUsingRuntimePublicKey();
|
||||||
|
bool ShouldVerifyM2PackPlaintextHash();
|
||||||
|
|||||||
Reference in New Issue
Block a user