Обфусцировать std::array используя constexpr

Я ищу небольшую функцию, которая может преобразовать std::array добавляя увеличивающиеся значения. Функция должна быть функцией времени компиляции.

Мне удалось написать небольшую функцию constexpr, которая делает это для массива длиной 3, но я не смог обобщить ее std::arrayс произвольной длины. Я также не смог обобщить это, чтобы содержать что-то другое, чем chars.

Кто-нибудь знает как это сделать?

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

2 ответа

Решение

Ты можешь использовать 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>{});
}

Существует несколько методов, использующих пакеты кортежей, но они великолепны, за исключением того, что у MSVC есть проблема с производительностью при компиляции больших строк.

Я обнаружил, что этот компромисс хорошо работает в 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)

А где-то позже

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());

Вы можете посмотреть разговор этого парня для более сложных методов: https://www.blackhat.com/docs/eu-14/materials/eu-14-Andrivet-C-plus-plus11-Metaprogramming-Applied-To-software-Obfuscation.pdf

Другие вопросы по тегам