diff --git a/dep/obfuscate.h b/dep/obfuscate.h index 1f6b4b3b..b08609a4 100644 --- a/dep/obfuscate.h +++ b/dep/obfuscate.h @@ -17,7 +17,7 @@ following traits: - Global lifetime The actual instantiation of the ay::obfuscated_data takes place inside a lambda as a function level static - - Implicitly convertable to a char* + - Implicitly convertible to a char* This means that you can pass it directly into functions that would normally take a char* or a const char* @@ -27,6 +27,13 @@ std::cout << obfuscated_string << std::endl; ----------------------------------------------------------------------------- */ +#pragma once +#if __cplusplus >= 202002L + #define AY_CONSTEVAL consteval +#else + #define AY_CONSTEVAL constexpr +#endif + // Workaround for __LINE__ not being constexpr when /ZI (Edit and Continue) is enabled in Visual Studio // See: https://developercommunity.visualstudio.com/t/-line-cannot-be-used-as-an-argument-for-constexpr/195665 #ifdef _MSC_VER @@ -49,8 +56,33 @@ namespace ay using size_type = unsigned long long; using key_type = unsigned long long; + // libstdc++ has std::remove_cvref_t since C++20, but because not every user will be + // able or willing to link to the STL, we prefer to do this functionality ourselves here. + template + struct remove_const_ref { + using type = T; + }; + + template + struct remove_const_ref { + using type = T; + }; + + template + struct remove_const_ref { + using type = T; + }; + + template + struct remove_const_ref { + using type = T; + }; + + template + using char_type = typename remove_const_ref::type; + // Generate a pseudo-random key that spans all 8 bytes - constexpr key_type generate_key(key_type seed) + AY_CONSTEVAL key_type generate_key(key_type seed) { // Use the MurmurHash3 64-bit finalizer to hash our seed key_type key = seed; @@ -67,22 +99,23 @@ namespace ay } // Obfuscates or deobfuscates data with key - constexpr void cipher(char* data, size_type size, key_type key) + template + constexpr void cipher(CHAR_TYPE* data, size_type size, key_type key) { // Obfuscate with a simple XOR cipher based on key for (size_type i = 0; i < size; i++) { - data[i] ^= char(key >> ((i % 8) * 8)); + data[i] ^= CHAR_TYPE((key >> ((i % 8) * 8)) & 0xFF); } } // Obfuscates a string at compile time - template + template class obfuscator { public: // Obfuscates the string 'data' on construction - constexpr obfuscator(const char* data) + AY_CONSTEVAL obfuscator(const CHAR_TYPE* data) { // Copy data for (size_type i = 0; i < N; i++) @@ -95,32 +128,32 @@ namespace ay cipher(m_data, N, KEY); } - constexpr const char* data() const + constexpr const CHAR_TYPE* data() const { return &m_data[0]; } - constexpr size_type size() const + AY_CONSTEVAL size_type size() const { return N; } - constexpr key_type key() const + AY_CONSTEVAL key_type key() const { return KEY; } private: - char m_data[N]{}; + CHAR_TYPE m_data[N]{}; }; // Handles decryption and re-encryption of an encrypted string at runtime - template + template class obfuscated_data { public: - obfuscated_data(const obfuscator& obfuscator) + obfuscated_data(const obfuscator& obfuscator) { // Copy obfuscated data for (size_type i = 0; i < N; i++) @@ -140,7 +173,7 @@ namespace ay // Returns a pointer to the plain text string, decrypting it if // necessary - operator char*() + operator CHAR_TYPE* () { decrypt(); return m_data; @@ -176,7 +209,7 @@ namespace ay // Local storage for the string. Call is_encrypted() to check whether or // not the string is currently obfuscated. - char m_data[N]; + CHAR_TYPE m_data[N]; // Whether data is currently encrypted bool m_encrypted{ true }; @@ -184,10 +217,10 @@ namespace ay // This function exists purely to extract the number of elements 'N' in the // array 'data' - template - constexpr auto make_obfuscator(const char(&data)[N]) + template + AY_CONSTEVAL auto make_obfuscator(const CHAR_TYPE(&data)[N]) { - return obfuscator(data); + return obfuscator(data); } } @@ -201,14 +234,16 @@ namespace ay // functions for decrypting the string and is also implicitly convertable to a // char* #define AY_OBFUSCATE_KEY(data, key) \ - []() -> ay::obfuscated_data& { \ + []() -> ay::obfuscated_data>& { \ static_assert(sizeof(decltype(key)) == sizeof(ay::key_type), "key must be a 64 bit unsigned integer"); \ static_assert((key) >= (1ull << 56), "key must span all 8 bytes"); \ + using char_type = ay::char_type; \ constexpr auto n = sizeof(data)/sizeof(data[0]); \ - constexpr auto obfuscator = ay::make_obfuscator(data); \ - thread_local auto obfuscated_data = ay::obfuscated_data(obfuscator); \ + constexpr auto obfuscator = ay::make_obfuscator(data); \ + thread_local auto obfuscated_data = ay::obfuscated_data(obfuscator); \ return obfuscated_data; \ }() + #ifndef NO_OBFUSCATE #define _O(x) AY_OBFUSCATE(x) #else