2015-08-29 5 views
13

Ich möchte einen Compiler-String-Verschlüsselung haben, so dass ich in meinem Code schreiben konnte:Compile Zeit-String-Verschlüsselung constexpr

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

und die Zeichenfolge „Ungültige Lizenz“ wird nicht in den Binärdateien erscheinen. Pre-Builds könnte die Antwort sein, aber ich bin auf der Suche nach einer reinen C++ constexpr Lösung für dieses Problem, und dass es von VS2015 unterstützt wird.

Irgendwelche Vorschläge?


  1. Ich habe schon in Compile-time string encryption sah, die keine constexpr Lösung für das Problem bietet.

  2. Ich habe auch in http://www.unknowncheats.me/forum/c-and-c/113715-compile-time-string-encryption.html untersucht. Obwohl es sich um eine consExpr-Lösung handelt, fügt VS2015 den Binärdateien weiterhin den String-Klartext hinzu.

+0

Mögliches Duplikat von [Verschlüsseln/Verschleiern eines String-Literals zur Kompilierzeit] (https://stackoverflow.com/questions/6934217/encrypting-obfuscating-a-string-literal-at-compile-time) – karliwson

Antwort

13

Hier ist, wie ich es tun würde:

1.) Verwenden Sie die str_const Vorlage für constexpr String-Manipulation hier beschrieben: 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_; } 
}; 

Auf diese Weise können Sie tun Dinge wie str_const message = "Invalid license" und manipulieren message in constexpr Funktionen.

2.) Erstellen Sie einen einfachen Pseudozufallsgenerator zur Kompilierungszeit und verwenden Sie die Makros __TIME__ und __LINE__, um den Seed zu generieren. Dies wird hier im Detail beschrieben: Generate random numbers in C++ at compile time

Sie geben einige Vorlage-basierten Code.

3.) kann man eine struct, mit einem constexpr Ctor die entweder const char [] und Vorlagen selbst gegen die Größe ähnlich zu dem str_const Beispiel nimmt, oder die dauert nur ein str_const und erzeugt zwei str_const die es seine Mitgliedsvariablen sind.

  • A str_const Längen n Pseudo-Zufall unsigned Zeichen enthalten, wobei den Pseudo-Zufalls-Generator erzeugt wird, wobei die Länge n der Eingabe ist. (die "Rauschzeichenkette")
  • Eine str_const der Länge n, die die eintragsmässige Summe (als vorzeichenlose Zeichen) der Eingabezeichen mit den Rauschzeichen enthält. (Der „Chiffretext“)

dann hat es eine Elementfunktion decrypt die constexpr müssen nicht, und kann eine std::string zurückkehren, die einfach jedes Zeichen des Rausch Zeichenkette subtrahiert von dem entsprechenden Zeichen des Chiffretext und gibt die resultierende Zeichenfolge zurück.

Wenn Ihr Compiler noch das ursprüngliche Zeichenfolgenliteral in der Binärdatei speichert, bedeutet dies, dass entweder das Eingabezeichenfolgenliteral (das Konstruktorargument) gespeichert wird, von dem ich glaube, dass es nicht ausgeführt werden sollte, da es ein temporäres oder its ist im Grunde inline die decrypt Funktion, und Sie sollten in der Lage sein, dies zu verhindern, indem Sie es mit Funktionszeiger verschleiern, oder markieren Sie volatile oder ähnliches.

Edit: Ich bin mir nicht sicher, ob der Standard erfordert, dass temporäre consxpr Objekte nicht in der Binärdatei erscheinen sollten. Eigentlich bin ich jetzt neugierig darauf. Meine Erwartung ist, dass zumindest in einem Release-Build ein guter Compiler sie entfernen sollte, wenn sie nicht mehr benötigt werden.

Edit: Also, Sie haben bereits meine Antwort akzeptiert. Aber zur Vollständigkeit, hier ist ein Quellcode, der die obigen Ideen implementiert und nur den C++ 11-Standard benutzt. Es funktioniert auf gcc-4.9 und clang-3.6, auch wenn Optimierungen deaktiviert sind, so gut wie ich sagen kann.

#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; 
} 
+1

Scheint so arbeiten nur mit Whole Level Optimization und "Maximize Speed ​​(/ O2)" oder "Minimize Size (/ O1)". –

+1

Works auf Visual Studio 2015 Update 1 :) –

+1

'#include ', auch wahrscheinlich Boost entfernen – Mikhail

-1

würde ich Code wie diese:

#if GENERATE_CODE 
.... code to generate the C++ code describing the encrypted literal 
.... generating exactly the code in the #else part 
#else 
static char encryptedLicense [32] = "..."; or whatever 
#endif 

nicht klug zu sein versuchen. Kopieren Sie den #if-Code in eine separate Datei, kompilieren Sie ihn und führen Sie ihn aus, und fügen Sie das Ergebnis wieder ein.