Skip to content

Commit

Permalink
update AYObfuscate
Browse files Browse the repository at this point in the history
  • Loading branch information
samtupy committed Aug 6, 2024
1 parent eb73945 commit 9749039
Showing 1 changed file with 55 additions and 20 deletions.
75 changes: 55 additions & 20 deletions dep/obfuscate.h
Original file line number Diff line number Diff line change
Expand Up @@ -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*
Expand All @@ -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
Expand All @@ -49,8 +56,33 @@ namespace ay
using size_type = unsigned long long;
using key_type = unsigned long long;

// libstdc++ has std::remove_cvref_t<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 <typename T>
struct remove_const_ref {
using type = T;
};

template <typename T>
struct remove_const_ref<T&> {
using type = T;
};

template <typename T>
struct remove_const_ref<const T> {
using type = T;
};

template <typename T>
struct remove_const_ref<const T&> {
using type = T;
};

template <typename T>
using char_type = typename remove_const_ref<T>::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;
Expand All @@ -67,22 +99,23 @@ namespace ay
}

// Obfuscates or deobfuscates data with key
constexpr void cipher(char* data, size_type size, key_type key)
template <typename CHAR_TYPE>
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 <size_type N, key_type KEY>
template <size_type N, key_type KEY, typename CHAR_TYPE = char>
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++)
Expand All @@ -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 <size_type N, key_type KEY>
template <size_type N, key_type KEY, typename CHAR_TYPE = char>
class obfuscated_data
{
public:
obfuscated_data(const obfuscator<N, KEY>& obfuscator)
obfuscated_data(const obfuscator<N, KEY, CHAR_TYPE>& obfuscator)
{
// Copy obfuscated data
for (size_type i = 0; i < N; i++)
Expand All @@ -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;
Expand Down Expand Up @@ -176,18 +209,18 @@ 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 };
};

// This function exists purely to extract the number of elements 'N' in the
// array 'data'
template <size_type N, key_type KEY = AY_OBFUSCATE_DEFAULT_KEY>
constexpr auto make_obfuscator(const char(&data)[N])
template <size_type N, key_type KEY = AY_OBFUSCATE_DEFAULT_KEY, typename CHAR_TYPE = char>
AY_CONSTEVAL auto make_obfuscator(const CHAR_TYPE(&data)[N])
{
return obfuscator<N, KEY>(data);
return obfuscator<N, KEY, CHAR_TYPE>(data);
}
}

Expand All @@ -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<sizeof(data)/sizeof(data[0]), key>& { \
[]() -> ay::obfuscated_data<sizeof(data)/sizeof(data[0]), key, ay::char_type<decltype(*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<decltype(*data)>; \
constexpr auto n = sizeof(data)/sizeof(data[0]); \
constexpr auto obfuscator = ay::make_obfuscator<n, key>(data); \
thread_local auto obfuscated_data = ay::obfuscated_data<n, key>(obfuscator); \
constexpr auto obfuscator = ay::make_obfuscator<n, key, char_type>(data); \
thread_local auto obfuscated_data = ay::obfuscated_data<n, key, char_type>(obfuscator); \
return obfuscated_data; \
}()

#ifndef NO_OBFUSCATE
#define _O(x) AY_OBFUSCATE(x)
#else
Expand Down

0 comments on commit 9749039

Please sign in to comment.