crime-trix/metastr-cpp

GitHub: crime-trix/metastr-cpp

metastr-cpp 是一个用于编译时字符串编码和作用域内运行时解码的 C++20 头文件库。

Stars: 0 | Forks: 0

# metastr-cpp -> metastr-cpp `metastr-cpp` 是一个用于编译时字符串编码和作用域内运行时解码的 C++20 头文件库。 [![ci](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/33a092094f190255.svg)](https://github.com/crime-trix/metastr-cpp/actions/workflows/ci.yml) 该库旨在减少编译二进制文件中明显的字符串暴露。它不是一个加密存储格式,也不声称在运行时解码字符串后保护字符串。对于需要真正机密性和完整性的数据,请使用 `metacrypt-cpp` 或其他认证加密方案。 ## 功能 - `consteval` 文字编码; - 流和自动机支持的编码模式; - 从文件、行和计数器获取的每个调用站点种子材料; - 由 CMake 生成并混合到种子/流生成的每个构建密钥材料; - 没有固定的最大字符串长度; - 支持 `char`、`wchar_t`、`char8_t`、`char16_t` 和 `char32_t`; - 只能移动的解码缓冲区,在销毁时擦除存储; - 使用 `with_decoded` 的作用域回调解码; - 手动解码到调用者提供的缓冲区; - 非零掩码字节以避免由零密钥流字节引起的未更改的明文字节; - 编码的 blob 元数据:种子、大小、字节大小、校验和和格式版本; - CMake 目标、安装规则、示例和 CI 测试的测试覆盖率; - 不将平台头文件拉入用户翻译单元。 ## 快速入门 ``` #include #include int main() { auto text = METASTR("compile-time encoded string"); std::puts(text.c_str()); } ``` 宽度和 UTF 文字使用专用宏: ``` auto wide = METASTR_W(L"wide string"); auto utf8 = METASTR_U8(u8"utf8 string"); auto utf16 = METASTR_U16(u"utf16 string"); auto utf32 = METASTR_U32(U"utf32 string"); ``` 对于有状态的有限自动机转换,使用 `AUTO` 宏: ``` auto text = METASTR_AUTO("encoded through a state machine"); auto wide = METASTR_AUTO_W(L"wide state machine string"); ``` ## 应用字符串 典型应用使用故意很小: ``` #include #include bool login(std::string_view user, std::string_view password) { const auto expected_user = METASTR("admin"); const auto expected_password = METASTR_AUTO("change-me"); return user == expected_user.view() && password == expected_password.view(); } ``` 使用 `METASTR` 进行默认紧凑转换。当您想要具有每个字符自动机状态的有状态转换时,请使用 `METASTR_AUTO`。两者都是编译时编码器,并且仅在表达式评估时进行解码。 ## 作用域解码 当明文只应在调用期间存在时,请使用 `with_decoded`: ``` constexpr auto label = metastr::make_blob<0x1234fedc98760011ull>("scoped decode"); label.with_decoded([](std::string_view text) { std::puts(text.data()); }); ``` 回调接收一个 `std::basic_string_view`。在回调返回后不要存储该视图。 ## 手动缓冲区 对于已经拥有存储的代码,直接将解码内容写入调用者提供的 span: ``` constexpr auto blob = metastr::make_blob<0xdecafbad10002000ull>("manual buffer"); std::array output{}; if (blob.decode_into(std::span(output.data(), output.size()))) { std::puts(output.data()); } metastr::secure_zero(std::span(output.data(), output.size())); ``` ## API 说明 `METASTR(...)` 是正常使用的便捷宏。它返回一个只能移动的 `decoded_string`。 `make_blob(literal)` 创建一个编码的编译时 blob。这对于需要稳定种子的测试、示例或生成代码非常有用。 `decoded_string` 拥有明文存储,并在销毁或重新分配时擦除该存储。 `basic_blob::decode()` 返回一个 `decoded_string`。 `basic_blob::decode_into(span)` 将解码文本加上空终止符写入现有缓冲区。 `basic_blob::with_decoded(fn)` 解码,调用 `fn(view)`,然后在调用完成后擦除临时缓冲区。 ## 安全模型 此库可以防止简单的静态字符串扫描和从二进制数据中提取的低工作量。它不能防止: - 在字符串解码时附加调试器; - 运行时内存检查; - 跟踪或模拟解码例程; - 可以执行二进制文件并观察行为的攻击者; - 应该永远不会发送给客户端的秘密。 将此视为字符串隐藏,而不是密码学。 将解码视图复制到 `std::string` 或其他长生存期缓冲区会创建一个 `metastr-cpp` 无法擦除的副本。对于短作用域使用,请首选 `with_decoded`。 ## 构建 ``` cmake -S . -B build -DMETASTR_BUILD_EXAMPLES=ON -DMETASTR_BUILD_TESTS=ON cmake --build build --config Release ctest --test-dir build -C Release --output-on-failure ``` CMake 构建生成 `metastr/metastr_build_config.hpp`,其中包含每个构建的密钥材料。如果使用公共头文件而不使用该生成的文件,则库将回退到确定性密钥并发出编译时警告。回退使仅包含头文件的使用保持正常,但使单独的构建更容易关联。 ## 大小基准 存储库包含一个包含 40 个相同字符串调用站点的小型大小基准: ``` ./tools/run_size_bench.ps1 ``` 它构建了三个发布可执行文件: - `baseline`:普通字符串文字; - `metastr_stream`:`METASTR`; - `metastr_auto`:`METASTR_AUTO`。 脚本报告可执行文件大小、与基线的差异、`api.secret.endpoint` 的明文命中次数以及运行时哈希退出代码。 基线中的明文命中次数可能会因编译器/链接器将相同的文字池化而变化。 一次 MSVC `/O2 /GL /MT` 运行测量: | 程序 | 大小 | 差异 | 明文命中 | | --- | ---: | ---: | ---: | | baseline | 110.0 KB | - | 40 | | metastr_stream | 118.5 KB | +8.7 KB | 0 | | metastr_auto | 124.0 KB | +14.3 KB | 0 | 确切数字因编译器、CRT、链接器选项和优化级别而异。 ## 安装 ``` cmake --install build --config Release --prefix ./install ``` 然后链接导出的目标: ``` find_package(metastr-cpp CONFIG REQUIRED) target_link_libraries(app PRIVATE metastr::metastr-cpp) ``` ## 许可证 MIT.
标签:Bash脚本