Anne Quinn
Anne Quinn

Reputation: 13002

Creating hash values and/or encrypted strings at compile time?

Is there a way to create hash values to strings, or encrypted strings, at compile time? I want to put the raw string that generates the encrypted text or hash values directly in my code as a string literal, but I don't want them to be compiled into the executable in their untransformed form.

Something like this?

constexpr uint32 hash(const char * string){
    ... // turns a string into a value to represent it
}
constexpr std::string encrypt(const char * string){
    ... // turns a string into a cyphertext (unsure what return type would work best here)
}

void f(){

    std::string input << std::cin();

    switch(hashedKey){
        case hash("help"): // legal?
            if(0 == encryptRT(input).compare(encrypt("secret string")){
                // the secret string should never appear in the executable
            }
            break;
    }
}

It's very important that the strings put directly into the constexpr functions never be put into the string table. Is this possible?

Upvotes: 2

Views: 400

Answers (1)

user7860670
user7860670

Reputation: 37549

Example of compile-time xor obfuscation:

#include <iostream>
#include <iomanip>
#include <cstddef>
#include <cstdint>
#include <array>

template<::std::size_t x_data_bytes_count, ::std::size_t x_key_bytes_count> constexpr auto
obfuscate
(
    ::std::array<::std::uint8_t, x_data_bytes_count> const & input
,   ::std::array<::std::uint8_t, x_key_bytes_count> const &  key
) noexcept
{
    static_assert(::std::size_t{0} < x_data_bytes_count);
    // Assuming null-terminated string is used as a key.
    static_assert(::std::size_t{1} < x_key_bytes_count);
    ::std::array<::std::uint8_t, x_data_bytes_count> output{};
    ::std::size_t data_byte_index{};
    ::std::size_t key_byte_index{};
    do
    {
        output[data_byte_index] = input[data_byte_index] xor key[key_byte_index];
        data_byte_index = data_byte_index + ::std::size_t{1};
        key_byte_index = key_byte_index + ::std::size_t{1};
        key_byte_index = key_byte_index % (key.size() - ::std::size_t{1});
    }
    while(input.size() != data_byte_index);
    return output;
}

// Following two overloads may accept string literals
// so calling obfuscation function would be more convenient.
template<::std::size_t x_data_bytes_count, ::std::size_t x_key_bytes_count> constexpr auto
obfuscate
(
    char const ( & input )[x_data_bytes_count]
,   char const ( & key )[x_key_bytes_count]
) noexcept
{
    ::std::size_t byte_index{};
    ::std::array<::std::uint8_t, x_data_bytes_count> input_arr{};
    for(byte_index = 0; x_data_bytes_count != byte_index; ++byte_index)
    {
        input_arr[byte_index] = static_cast<::std::uint8_t>(input[byte_index]);
    }
    ::std::array<::std::uint8_t, x_key_bytes_count> key_arr{};
    for(byte_index = 0; x_key_bytes_count != byte_index; ++byte_index)
    {
        key_arr[byte_index] = static_cast<::std::uint8_t>(key[byte_index]);
    }
    return obfuscate(input_arr, key_arr);
}

template<::std::size_t x_data_bytes_count, ::std::size_t x_key_bytes_count> constexpr auto
obfuscate
(
    ::std::array<::std::uint8_t, x_data_bytes_count> const & input_arr
,   char const ( &                                           key )[x_key_bytes_count]
) noexcept
{
    ::std::size_t byte_index{};
    ::std::array<::std::uint8_t, x_key_bytes_count> key_arr{};
    for(byte_index = 0; x_key_bytes_count != byte_index; ++byte_index)
    {
        key_arr[byte_index] = static_cast<::std::uint8_t>(key[byte_index]);
    }
    return obfuscate(input_arr, key_arr);
}

int main()
{
    constexpr auto const & key{"Stack overflow"};
    constexpr auto const obfuscated_str{obfuscate("Hello World!", key)};
    for(auto const & ch: obfuscated_str)
    {
        ::std::cout << ::std::hex << ::std::setw(2) << ::std::setfill('0')
            << static_cast<::std::uint32_t>(ch) << " ";
    }
    ::std::cout << ::std::endl;
    auto const deobfuscated_str{obfuscate(obfuscated_str, key)};
    for(auto const & ch: deobfuscated_str)
    {
        ::std::cout << ::std::hex << ::std::setw(2) << ::std::setfill('0')
            << static_cast<::std::uint32_t>(ch) << " ";
    }
    ::std::cout << ::std::endl;
    ::std::cout << reinterpret_cast<char const *>(deobfuscated_str.data()) << ::std::endl;
    return 0;
}

online compiler

Upvotes: 5

Related Questions