使用constexpr编译时间字符串加密 [英] Compile time string encryption using constexpr

查看:358
本文介绍了使用constexpr编译时间字符串加密的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个编译时字符串加密,这样我可以写在我的代码:

  const auto encryptedInvalidLicense = ENCRYPT(无效许可证); 
std :: cout<< encryptedInvalidLicense.decrypt()< std :: endl; //输出无效的许可证

并且字符串无效的许可证不会出现在二进制文件中。
预构建可能是答案,但我正在寻找一个纯的c ++ constexpr 解决这个问题,它将由VS2015支持。 / p>

有任何建议吗?







  1. 我已经调查过编译时字符串加密,它不提供一个constexpr解决方案的问题。


  2. 我也看了 http://www.unknowncheats.me/forum/c-and-c/113715-compile-time-string-encryption.html 。虽然它是一个constexpr解决方案,VS2015仍然将字符串纯文本添加到二进制文件。



解决方案

这是我如何做的:



1)使用 str_const 模板constexpr字符串操作描述如下:在C ++中方便地声明编译时字符串



代码:

  class str_const {
// constexpr string
private:
const char * const p_;
const std :: size_t sz_;

public:
template< std :: size_t N>
constexpr str_const(const char(& a)[N])
:p_(a)
,sz_(N - 1)
{}

constexpr char operator [](std :: size_t n)const {return n< sz_? p_ [n]:throw std :: out_of_range(); }
constexpr std :: size_t size()const {return sz_; }

constexpr const char * get()const {return p_; }
};

这可以让你做 str_const message =Invalid license code>并在constexpr函数中操作消息



2。)创建一个简单的编译时伪随机生成器,使用宏 __ TIME __ __ LINE __ 生成种子。这在此详细描述:在编译时生成C ++中的随机数?



他们提供一些基于模板的代码。



3。一个 constexpr ctor,它接受 const char [] 和模板本身的大小类似于 str_const 示例,或者只需要一个 str_const ,并生成两个 str_const 是其成员变量。




  • 长度 str_const n 包含伪随机unsigned chars,使用伪随机生成器生成,其中 n 是输入的长度。 (噪音字符串)

  • 包含长度 n str_const 输入字符与噪声字符的入口方和(作为无符号字符)。 (密文)



然后它有一个成员函数 decrypt 它不需要是constexpr,并且可以返回 std :: string ,它简单地从密文的相应字符中减去噪声字符串的每个字符,并返回结果字符串。



如果你的编译器仍然将原始字符串文字存储在二进制文件中,则意味着它存储的是输入字符串文字(构造函数参数)认为它应该是因为它的一个临时的,或者它基本上内联 decrypt 函数,你应该能够通过使用函数指针模糊化它,或者标记它 volatile 或类似的。



编辑:我不确定标准是否要求临时constexpr对象不应出现二进制。其实我很好奇现在。我的期望是,至少在发布版本中,一个好的编译器应该在不再需要它们时删除它们。



编辑:所以,你已经接受了我的答案。但无论如何完整性,这里有一些源代码实现上述想法,只使用C ++ 11标准。它适用于gcc-4.9和clang-3.6,即使优化被禁用,正如我可以告诉。

  #include < array> 
#include< iostream>
#include< string>

typedef uint32_t u32;
typedef uint64_t u64;
typedef unsigned char uchar;

模板< u32 S,u32 A = 16807UL,u32 C = 0UL,u32 M =(1UL<< 31)
struct LinearGenerator {
static const u32 state =((u64)S * A + C)%M;
static const u32 value = state;
typedef LinearGenerator< state>下一个;
struct Split {// Leapfrog
typedef LinearGenerator<状态,A * A,0,M> Gen1;
typedef LinearGenerator< next :: state,A * A,0,M> Gen2;
};
};

//从生成器获取特定索引的元函数
template< u32 S,std :: size_t index>
struct Generate {
static const uchar value = Generate< LinearGenerator< S> :: state,index-1> :: value;
};

模板< u32 S>
struct Generate< S,0> {
static const uchar value = static_cast< uchar> (LinearGenerator S :: value);
};

//索引列表
template< std :: size_t ...>
struct StList {};

//连接
模板< typename TL,typename TR>
struct Concat;

template< std :: size_t ... SL,std :: size_t ... SR>
struct Concat< StList< SL ...>,StList< SR ...> {
typedef StList< SL ...,SR ...>类型;
};

template< typename TL,typename TR>
使用Concat_t = typename Concat< TL,TR> :: type;

//从零到n-1计数
template< size_t s>
struct Count {
typedef Concat_t< typename Count< s-1> :: type,StList< s-1>类型;
};

模板<>
struct Count< 0> {
typedef StList<>类型;
};

template< size_t s>
using Count_t = typename Count< s> :: type;

//获取字符串的乱码字符
模板< u32 seed,std :: size_t index,std :: size_t N>
constexpr uchar get_scrambled_char(const char(& a)[N]){
return static_cast< uchar>(a [index])+ Generate< seed,index&
}

//从明文字符串中获取密文
template< u32 seed,typename T&
struct cipher_helper;

template< u32 seed,std :: size_t ... SL>
struct cipher_helper< seed,StList< SL ...>> {
static constexpr std :: array< uchar,sizeof ...(SL)> get_array(const char(& a)[sizeof ...(SL)]){
return {{get_scrambled_char< seed,SL>(a)...}};
}
};

template< u32 seed,std :: size_t N>
constexpr std :: array< uchar,N> get_cipher_text(const char(& a)[N]){
return cipher_helper< seed,Count_t N> :: get_array(a);
}

//从种子和字符串长度获得噪声序列
模板< u32 seed,typename T&
struct noise_helper;

template< u32 seed,std :: size_t ... SL>
struct noise_helper< seed,StList< SL ...>> {
static constexpr std :: array< uchar,sizeof ...(SL)> get_array(){
return {{Generate< seed,SL> :: value ...}};
}
};

template< u32 seed,std :: size_t N>
constexpr std :: array< uchar,N> get_key(){
return noise_helper< seed,Count_t< N> :: get_array();
}


/ *
//获取字符串的解扰字符
模板< u32 seed,std :: size_t index,std :: size_t N>
char get_unscrambled_char(const std :: array< uchar,N>& a){
return static_cast< char> (a [index] - Generate< seed,index> :: value);
}
* /

//获取数组大小的元函数
template< typename T>
struct array_info;

template< typename T,size_t N>
struct array_info< T [N]>
{
typedef T type;
enum {size = N};
};

template< typename T,size_t N>
struct array_info< const T(&)[N] :array_info< T [N] {};

//扰乱字符串
template< u32 seed,std :: size_t N>
class obfuscated_string {
private:
std :: array< uchar,N> cipher_text_;
std :: array public:
explicit constexpr obfuscated_string(const char(& a)[N])
:cipher_text_(get_cipher_text< seed,N(a))
,key_(get_key< ; seed,N>())
{}

operator std :: string()const {
char plain_text [N];
for(volatile std :: size_t i = 0; i volatile char temp = static_cast< char>(cipher_text_ [i] -key_ [i]);
plain_text [i] = temp;
}
return std :: string {plain_text,plain_text + N};
}
};

template< u32 seed,std :: size_t N>
std :: ostream&运算符<< (std :: ostream& s,const obfuscated_string< seed,N& str){
s< static_cast< std :: string>(str);
return s;
}

#define RNG_SEED((__TIME __ [7] - '0')* 1 +(__TIME __ [6] - '0')* 10 + \
__TIME __ [4] - '0')* 60 +(__TIME __ [3] - '0')* 600 + \
(__TIME __ [1] - '0')* 3600 + '0')* 36000)+ \
(__LINE__ * 100000)


#define LIT(STR)\
obfuscated_string< RNG_SEED,array_info& (STR)> :: size> {STR}

auto S2 = LIT((Hewwo,I'm hunting wabbits))

int main(){
constexpr auto S1 = LIT((What's up doc));
std :: cout<< S1 < std :: endl;
std :: cout<< S2<< std :: endl;
}


I want to have a compile-time string encryption, such that I could write in my code:

const auto encryptedInvalidLicense = ENCRYPT("Invalid license");
std::cout << encryptedInvalidLicense.decrypt() << std::endl; // outputs "Invalid license"

and the string "Invalid license" wont appear in the binaries. Pre-builds might be the answer, but I'm looking for a pure c++ constexpr solution to this problem, and that it will be supported by VS2015.

Any suggestions?


  1. I've already looked into Compile-time string encryption, which doesn't provide a constexpr solution to the problem.

  2. I've also looked into http://www.unknowncheats.me/forum/c-and-c/113715-compile-time-string-encryption.html . Though it's a constexpr solution, VS2015 still adds the strings plain text to the binaries.

解决方案

Here's how I would do it:

1.) Use the str_const template for constexpr string manipulation described here: Conveniently Declaring Compile-Time Strings in C++

Code:

class str_const {
    // constexpr string
private:
    const char * const p_;
    const std::size_t sz_;

public:
    template <std::size_t N>
    constexpr str_const(const char(&a)[N])
            : p_(a)
            , sz_(N - 1)
    {}

    constexpr char operator[](std::size_t n) const { return n < sz_ ? p_[n] : throw std::out_of_range(""); }
    constexpr std::size_t size() const { return sz_; }

    constexpr const char * get() const { return p_; }
};

This lets you do things like str_const message = "Invalid license" and manipulate message in constexpr functions.

2.) Make a simple compile-time pseudorandom generator, using the macros __TIME__ and __LINE__ to generate the seed. This is described in detail here: Generate random number's in C++ at compile time?

They give some template-based code.

3.) Make a struct, with a constexpr ctor which takes either const char [] and templates itself against the size similarly to the str_const example, or which just takes a str_const, and generates two str_const which it are its member variables.

  • A str_const of length n containing pseudorandom unsigned chars, generated using the pseudorandom generator, where n is the length of the input. (the "noise string")
  • A str_const of length n containing the entry-wise sum (as unsigned chars) of the input characters with the noise characters. (the "cipher text")

Then it has a member function decrypt which need not be constexpr, and can return a std::string, which simply subtracts each character of the noise string from the corresponding character of the cipher text and returns the resulting string.

If your compiler is still storing the original string literal in the binary, it means that either it's storing the input string literal (the constructor argument) which I don't think it should be doing since its a temporary, or its basically inlining the decrypt function, and you should be able to prevent that by obfuscating it with function pointers, or marking it volatile or similar.

Edit: I'm not sure if the standard requires that temporary constexpr objects should not appear in the binary. Actually I'm curious about that now. My expectation is that at least in a release build, a good compiler should remove them when they are no longer needed.

Edit: So, you already accepted my answer. But anyways for completeness, here's some source code that implements the above ideas, using only C++11 standard. It works on gcc-4.9 and clang-3.6, even when optimizations are disabled, as nearly as I can tell.

#include <array>
#include <iostream>
#include <string>

typedef uint32_t u32;
typedef uint64_t u64;
typedef unsigned char uchar;

template<u32 S, u32 A = 16807UL, u32 C = 0UL, u32 M = (1UL<<31)-1>
struct LinearGenerator {
    static const u32 state = ((u64)S * A + C) % M;
    static const u32 value = state;
    typedef LinearGenerator<state> next;
    struct Split { // Leapfrog
        typedef LinearGenerator< state, A*A, 0, M> Gen1;
        typedef LinearGenerator<next::state, A*A, 0, M> Gen2;
    };
};

// Metafunction to get a particular index from generator
template<u32 S, std::size_t index>
struct Generate {
    static const uchar value = Generate<LinearGenerator<S>::state, index - 1>::value;
};

template<u32 S>
struct Generate<S, 0> {
    static const uchar value = static_cast<uchar> (LinearGenerator<S>::value);
};

// List of indices
template<std::size_t...>
struct StList {};

// Concatenate
template<typename TL, typename TR>
struct Concat;

template<std::size_t... SL, std::size_t... SR>
struct Concat<StList<SL...>, StList<SR...>> {
    typedef StList<SL..., SR...> type;
};

template<typename TL, typename TR>
using Concat_t = typename Concat<TL, TR>::type;

// Count from zero to n-1
template<size_t s>
struct Count {
    typedef Concat_t<typename Count<s-1>::type, StList<s-1>> type;
};

template<>
struct Count<0> {
    typedef StList<> type;
};

template<size_t s>
using Count_t = typename Count<s>::type;

// Get a scrambled character of a string
template<u32 seed, std::size_t index, std::size_t N>
constexpr uchar get_scrambled_char(const char(&a)[N]) {
    return static_cast<uchar>(a[index]) + Generate<seed, index>::value;
}

// Get a ciphertext from a plaintext string
template<u32 seed, typename T>
struct cipher_helper;

template<u32 seed, std::size_t... SL>
struct cipher_helper<seed, StList<SL...>> {
    static constexpr std::array<uchar, sizeof...(SL)> get_array(const char (&a)[sizeof...(SL)]) {
        return {{ get_scrambled_char<seed, SL>(a)... }};
    }
};

template<u32 seed, std::size_t N>
constexpr std::array<uchar, N> get_cipher_text (const char (&a)[N]) {
    return cipher_helper<seed, Count_t<N>>::get_array(a);
}

// Get a noise sequence from a seed and string length
template<u32 seed, typename T>
struct noise_helper;

template<u32 seed, std::size_t... SL>
struct noise_helper<seed, StList<SL...>> {
    static constexpr std::array<uchar, sizeof...(SL)> get_array() {
        return {{ Generate<seed, SL>::value ... }};
    }
};

template<u32 seed, std::size_t N>
constexpr std::array<uchar, N> get_key() {
    return noise_helper<seed, Count_t<N>>::get_array();
}


/*
// Get an unscrambled character of a string
template<u32 seed, std::size_t index, std::size_t N>
char get_unscrambled_char(const std::array<uchar, N> & a) {
    return static_cast<char> (a[index] - Generate<seed, index>::value);
}
*/

// Metafunction to get the size of an array
template<typename T>
struct array_info;

template <typename T, size_t N>
struct array_info<T[N]>
{
    typedef T type;
    enum { size = N };
};

template <typename T, size_t N>
struct array_info<const T(&)[N]> : array_info<T[N]> {};

// Scramble a string
template<u32 seed, std::size_t N>
class obfuscated_string {
private:
    std::array<uchar, N> cipher_text_;
    std::array<uchar, N> key_;
public:
    explicit constexpr obfuscated_string(const char(&a)[N])
        : cipher_text_(get_cipher_text<seed, N>(a))
        , key_(get_key<seed,N>())
    {}

    operator std::string() const {
        char plain_text[N];
        for (volatile std::size_t i = 0; i < N; ++i) {
            volatile char temp = static_cast<char>( cipher_text_[i] - key_[i] );
            plain_text[i] = temp;
        }
        return std::string{plain_text, plain_text + N};
    }
};

template<u32 seed, std::size_t N>
std::ostream & operator<< (std::ostream & s, const obfuscated_string<seed, N> & str) {
    s << static_cast<std::string>(str);
    return s;
}

#define RNG_SEED ((__TIME__[7] - '0') * 1  + (__TIME__[6] - '0') * 10  + \
              (__TIME__[4] - '0') * 60   + (__TIME__[3] - '0') * 600 + \
              (__TIME__[1] - '0') * 3600 + (__TIME__[0] - '0') * 36000) + \
              (__LINE__ * 100000)


#define LIT(STR) \
    obfuscated_string<RNG_SEED, array_info<decltype(STR)>::size>{STR}

auto S2 = LIT(("Hewwo, I'm hunting wabbits"));

int main() {
    constexpr auto S1 = LIT(("What's up doc"));
    std::cout << S1 << std::endl;
    std::cout << S2 << std::endl;
}

这篇关于使用constexpr编译时间字符串加密的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆