3

I'm looking for a small function that is able to transform a std::array by adding increasing values. The function must be a compile time function.

I was able to write a small constexpr function which does so for an array of length 3, but I was unable to generalize it to std::arrays of arbitrary lengths. I also failed to generalize it to contain something different than chars.

Does anyone knows how to do it?

#include <array>
#include <iostream>
#include <valarray>

constexpr std::array<char,3> obfuscate(const std::array<char,3>& x)  {
     return std::array<char, 3>{x.at(0)+1, x.at(1) + 2, x.at(2) + 3 };
}

/* Won't compile

template<typename T,typename S, template<typename, typename> L=std::array<T, U>>
constexpr L<T,U> obfuscate(const L<T, U>& x) {
    return {x.at(0) + 1, x.at(0) + 2, x.at(0) + 3 };
}
*/

std::ostream& operator<<(std::ostream& str, const std::array<char, 3>& x) {
    for (auto i = 0; i < 3; i++) {
        str << x.at(i);
    }
    return str;
}

int main(int argc, char** args) {
    std::array<char, 3> x{ 'a','b','c' };
    std::cout << x << std::endl;
    std::cout << obfuscate(x) << std::endl;
//  std::cout << obfuscate<3>(x) << std::endl;
}
Guillaume Gris
  • 2,135
  • 17
  • 34
Aleph0
  • 5,816
  • 4
  • 29
  • 80
  • Are you looking to actually obfuscate the array or get your program working? I have a bunch of code for the former, although it typically kills the MSVC compiler for large packs. – Mikhail Mar 16 '18 at 10:08
  • @Mikhail: I really want to obfuscate my string, so that no one can read the string in the compiled file. My strings are normally very short. I'm just curious how this can be done. – Aleph0 Mar 16 '18 at 10:13
  • @Holt: I have to stick to C++11. But what would be your solution? Is it a compile time expression? – Aleph0 Mar 16 '18 at 10:14
  • What's the purpose? Obfuscation is not encryption, it's not going to be hard for an attacker to un-obfuscate your string, so why even bother? – Jesper Juhl Mar 16 '18 at 10:53
  • I'm bothering for being curios what can be done in compile time. It's clear, that one can break the obfuscator with enough efforts. – Aleph0 Mar 16 '18 at 10:54

2 Answers2

2

There are a few methods that use tuple packs, these are great except that MSVC has a performance problem compiling large strings.

I've found this compromise works well in MSVC.

template<typename I>
struct encrypted_string;

template<size_t... I>
struct encrypted_string<std::index_sequence<I...>>
{
    std::array<char, sizeof...(I)+1> buf;

    constexpr static char encrypt(char c) { return c ^ 0x41; }
    constexpr static char decrypt(char c) { return encrypt(c); }
    constexpr explicit __forceinline encrypted_string(const char* str)
        : buf{ encrypt(str[I])... } { }
    inline const char* decrypt()
    {
        for (size_t i = 0; i < sizeof...(I); ++i)
        {
            buf[i] = decrypt(buf[i]);
        }
        buf[sizeof...(I)] = 0;
        return buf.data();
    }
};
#define enc(str) encrypted_string<std::make_index_sequence<sizeof(str)>>(str)

And somewhere later

auto stringo = enc(R"(  
    kernel void prg_PassThru_src(const global unsigned short * restrict A, int srcstepA, int srcoffsetA,
    global float * restrict Beta, int srcstepBeta, int srcoffsetBeta,
    int rows, int cols) {
        int x = get_global_id(0);
        int y0 = get_global_id(1);
        if (x < cols) {
            int srcA_index = mad24(y0, srcstepA / 2, x + srcoffsetA / 2);
            int srcBeta_index = mad24(y0, srcstepBeta / 4, x + srcoffsetBeta / 4);
            Beta[srcBeta_index] = A[srcA_index];
        }
    }
//somewhere later
cv::ocl::ProgramSource programSource(stringo.decrypt());

You can see this guy's talk for more sophisticated methods: https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf

Mikhail
  • 7,749
  • 11
  • 62
  • 136
2

You can use std::index_sequence:

template<class T, std::size_t N, std::size_t... Is>
constexpr std::array<T, N> helper (const std::array<T, N> &x, std::index_sequence<Is...>) {
     return std::array<T, N>{static_cast<T>(x.at(Is)+Is+1)...};
}

template<class T, std::size_t N>
constexpr std::array<T, N> obfuscate(const std::array<T, N> &x) {
     return helper(x, std::make_index_sequence<N>{});
}
llllllllll
  • 16,169
  • 4
  • 31
  • 54
  • Great job. Seems to be the right approach. Unfortunately it doesn't seem to obfuscate the string? Any idea why? I adapted my operator<< to print the obfuscated string, but it stays the same. – Aleph0 Mar 16 '18 at 10:24
  • @Aleph0 You are using `x.at(0)` in your own code for every item. I just copied it. Is it a typo? – llllllllll Mar 16 '18 at 10:25
  • Sorry this was a type. I wanted to add increasing numbers to my array. Just corrected my error. – Aleph0 Mar 16 '18 at 10:28
  • Works like charm. I really need some time to digest your solution. Seems, that I can learn a lot from it. – Aleph0 Mar 16 '18 at 10:36
  • I'm wondering if it is possible to use it in the way obfuscate("String"). But then I need a method to convert a const char* to a `std::array`? – Aleph0 Mar 16 '18 at 10:42
  • @Aleph0 string literal is a lvalue with type `const char[N]`, **not** `const char *`, thus it's similar. – llllllllll Mar 16 '18 at 10:51
  • Just found this: https://stackoverflow.com/a/40180971/5762796 It seems to be similar. – Aleph0 Mar 16 '18 at 10:53
  • You are missing a `+1` to actually reproduce OP's code: `static_cast(x.at(Is)+Is+1)...` – Holt Mar 16 '18 at 11:10