Home

Awesome

xorlit

Compile time string literal encryptor for C++.

license release godbolt

Usage

XORLIT

The XORLIT macro can be used to create an encrypted string which evaluates to its original contents (e.g. XORLIT("foo") would evalute as the string "foo", but be stored as some other encrypted value). As it wraps xorlit::make_str, one can pass either one argument, a string literal, or two arguments, a string literal and a key. In the case that one argument is passed, the key used will default to xorlit::seed.

[!WARNING] Exercise caution when using XORLIT, xorlit::make_str(__VA_ARGS__).rexor(), or xorlit::strings in any context where they are not explicitly stored, as some compilers, such as MSVC, may sporadically encrypt strings non-constexpr-ly depending on the string literal's content or the context of its usage. It may be advisable to search binary contents for any unencrypted string literals in this case.

xorlit::seed

xorlit::seed is a constexpr std::uint_least32_t which is based on the predefined __TIME__ macro to generate values. It is the default value used by xorlit::make_str and by extension XORLIT for the key. Since xorlit::seed or static_cast<char>(xorlit::seed) may evaluate to 0, which, in such a case, would lead to an unencrypted string, by defining XORLIT_SEED_STATIC_ASSERT before including the xorlit.hpp header, a static assertion by the compiler will be enabled to check if xorlit::seed is equal to 0.

xorlit::string

xorlit::string is the provided type for storing encrypted strings. A xorlit::string should always be decorated with the constexpr specifier to ensure it is stored in its encrypted form. xorlit::string defines the following member functions:

[!IMPORTANT] Results of xorlit::string::xor_data() must be managed manually, whether that be via delete, smart pointers, etc.

Example

#include <string>
#include <iostream>
#include <format>
#define XORLIT_SEED_STATIC_ASSERT // enable compiler check if xorlit::seed is 0
#include <xorlit.hpp>

int main()
{
    std::cout
        << XORLIT("Default, xorlit::seed is passed as the key\n")
        << XORLIT("Or you can use xorlit::seed yourself\n", xorlit::seed + __LINE__) // when passing your own seeds, you should check that they aren't 0
        << XORLIT("Or you can choose your own key\n", 12) << std::endl;

    constexpr auto s = xorlit::make_str("You can manually store a xorlit::string"); // always declare the results of xorlit::make_str constexpr
    const std::string raw(s.data(), decltype(s)::size);
    const char* original_data = s.xor_data(); // results of xorlit::string::xor_data must be manually managed, smart pointers are recommended
    const std::string original(original_data, decltype(s)::size);
    delete[] original_data;
    std::cout << std::format("Raw: {}\nOriginal: {}", raw, original) << std::endl;
}

////////////////// Possible output: //////////////////
// Default, xorlit::seed is passed as the key
// Or you can use xorlit::seed yourself
// Or you can choose your own seed
//
// Raw:    ?%p31>p=1>%1<<)p#$?"5p1p(?"<9$jj#$"9>7P
// Original: You can manually store a xorlit::string