Я пытаюсь написать функцию для скрытия (обфускации) текстовых строк во время компиляции в двоичном коде. Назначение: отключить удобный поиск и модифицировать текстовые сообщения с помощью бинарного редактора.
Алгоритм прост: преобразовать символы в строке в deltas, т.е. е. строка abcd должна быть сохранена в двоичном файле как a\001\001\001.
Я написал следующий код, он работает:
#include <string>
#include <stdio.h>
#include <string.h>
constexpr std::string str_encrypt(const char *str) {
std::string rc;
unsigned char x = 0, c;
while(c = *str++) {
rc.push_back(c - x);
x = c;
}
return rc;
}
std::string str_decrypt(const std::string &str) {
std::string rc;
unsigned char x = 0;
for(unsigned char c : str)
rc.push_back(x += c);
return rc;
}
const std::string hello(str_encrypt("Hello, world!"));
int main(int argc, char **argv) {
for(unsigned char c : hello)
printf("%d ", c);
putchar('\n');
printf("S=[%s]\n", str_decrypt(hello).c_str());
return 0;
}
Но строка все еще не "зашифрована" в двоичном файле:
$ c++ -std=c++2b -O2 constexpr.cpp && strings a.out | grep Hello
Hello, world!
Когда я меняю constexpr на consteval, я вижу ошибку компиляции:
$ c++ -std=c++2b -O2 constexpr.cpp
constexpr.cpp:23:36: error: ‘std::string{std::__cxx11::basic_string<char>::_Alloc_hider{((char*)(&<anonymous>.std::__cxx11::basic_string<char>::<anonymous>.std::__cxx11::basic_string<char>::<unnamed union>::_M_local_buf))}, 13, std::__cxx11::basic_string<char>::<unnamed union>{char [16]{'H', '\035', '\007', '\000', '\003', '\37777777675', '\37777777764', 'W', '\37777777770', '\003', '\37777777772', '\37777777770', '\37777777675', 0}}}’ is not a constant expression
23 | const std::string hello(str_encrypt("Hello, world!"));
Мой вопрос: Можно ли написать такое шифрование во время компиляции? Если да, то подскажите, как быть.
Мой компилятор: g++ (GCC) 12.2.1 20230201
Взгляните и на это: stackoverflow.com/questions/32287125/…





Проблема в том, что str_encrypt не оценивается во время компиляции.
Когда я меняю constexpr на consteval, я вижу ошибку компиляции
Это подсказка, когда мы переключаемся на consteval, который требует, чтобы str_encrypt была функцией немедленного/времени компиляции, компилятор выдает ошибку.
Начиная с C++20, std::string можно использовать в контексте времени компиляции, если это временное выделение, т. е. строка должна быть уничтожена перед выходом из контекста времени компиляции.
В этом примере это не так, поэтому str_encrypt не может быть функцией времени компиляции.
Если бы мы поставили:
constexpr std::string hello(str_encrypt("Hello, world!"));
Тогда мы увидим ту же ошибку, что и при использовании consteval на str_encrypt.
Однако массивы или std::arrays могут быть constexpr.
Поэтому, если вместо возврата std::string мы вернем std::array, то пример может работать так, как ожидалось.
Этот модифицированный пример работает с g++ / clang++ и требует C++17.
Было бы целесообразно использовать consteval для принудительной оценки времени компиляции, но, конечно, требуется C++20.
#include <string>
#include <stdio.h>
#include <string.h>
#include <array>
template <size_t N>
constexpr std::array<char, N> str_encrypt(const char (&str)[N]) {
std::array<char, N> output{};
unsigned char x = 0, c = 0;
for (int i = 0; i < N; ++i) {
c = str[i];
output[i] = (c - x);
x = c;
}
return output;
}
template <size_t N>
std::string str_decrypt(const std::array<char, N> &str) {
std::string rc;
unsigned char x = 0;
for(unsigned char c : str)
rc.push_back(x += c);
return rc;
}
constexpr auto hello = str_encrypt("Hello, world!");
int main(int argc, char **argv) {
for(unsigned char c : hello)
printf("%d ", c);
putchar('\n');
printf("S=[%s]\n", str_decrypt(hello).c_str());
return 0;
}
Выход:
$ ./example
72 29 7 0 3 189 244 87 248 3 250 248 189 223
S=[Hello, world!]
Строка «Привет, мир!» не находится в двоичном формате, как и функция str_encrypt.
$ strings example | grep Hello
$ objdump -t -C example | grep str_
0000000000001302 w F .text 00000000000000a6 std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > str_decrypt<14ul>(std::array<char, 14ul> const&)
Годболт: https://godbolt.org/z/vPj3bW6Yz
Если вы не хотите заново изобретать завещание, вы можете использовать github.com/JustasMasiulis/xorstr