C+中隐藏敏感字符串的技术+; 我需要在我的C++应用程序中存储敏感信息(一个我想保密的对称加密密钥)。简单的方法是这样做: std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

C+中隐藏敏感字符串的技术+; 我需要在我的C++应用程序中存储敏感信息(一个我想保密的对称加密密钥)。简单的方法是这样做: std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";,c++,security,obfuscation,defensive-programming,C++,Security,Obfuscation,Defensive Programming,但是,通过strings进程(或从二进制应用程序中提取字符串的任何其他进程)运行应用程序将显示上述字符串 应该使用什么技术来掩盖这些敏感数据 编辑: 好的,你们几乎都说过“你们的可执行文件可以被反向工程”——当然!这是我最讨厌的事,所以我要在这里大声说: 为什么这个网站上99%(好吧,也许我有点夸张了)的所有安全相关问题都会被滔滔不绝的“没有办法创建一个完全安全的程序”所回答?这不是一个有用的答案!安全性是一端完美可用性与无安全性,另一端完美安全性与无可用性之间的滑动比例 关键是,根据您要做的事

但是,通过
strings
进程(或从二进制应用程序中提取字符串的任何其他进程)运行应用程序将显示上述字符串

应该使用什么技术来掩盖这些敏感数据

编辑:

好的,你们几乎都说过“你们的可执行文件可以被反向工程”——当然!这是我最讨厌的事,所以我要在这里大声说:

为什么这个网站上99%(好吧,也许我有点夸张了)的所有安全相关问题都会被滔滔不绝的“没有办法创建一个完全安全的程序”所回答?这不是一个有用的答案!安全性是一端完美可用性与无安全性,另一端完美安全性与无可用性之间的滑动比例

关键是,根据您要做的事情和软件运行的环境,您可以在滑动比例上选择您的位置。我不是在为军事安装编写应用程序,我是在为家用电脑编写应用程序。我需要使用已知的加密密钥在不受信任的网络上加密数据。在这些情况下,“默默无闻的安全”可能已经足够好了!当然,有足够的时间、精力和技能的人可以对二进制文件进行反向工程并找到密码,但是你猜怎么着?我不在乎:

我花在实现顶级安全系统上的时间要比破解版本造成的销售损失更昂贵(不是说我真的在卖这个,但你明白我的意思)。在新程序员中,这种“让它以最好的方式完成”的编程趋势至少可以说是愚蠢的


感谢您抽出时间回答这个问题-他们非常有帮助。不幸的是,我只能接受一个答案,但所有有用的答案我都投了赞成票。

基本上,任何有权访问您的程序和调试器的人都可以而且会在应用程序中找到密钥

但是,如果您只是想确保在二进制文件上运行
strings
时不会显示密钥,您可以确保密钥不在可打印范围内

用异或模糊键

例如,可以使用XOR将密钥拆分为两个字节数组:

key = key1 XOR key2
如果创建的key1的字节长度与
key
相同,则可以使用(完全)随机字节值,然后计算
key2

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]
您可以在构建环境中执行此操作,然后仅在应用程序中存储
key1
key2

保护二进制文件

另一种方法是使用工具来保护二进制文件。例如,有几个安全工具可以确保您的二进制文件被混淆,并启动运行它的虚拟机。这使得调试变得很困难,同时也是许多商业级安全应用程序(也,唉,恶意软件)受到保护的一种便利方式

首要工具之一是,它在保护二进制文件方面做得非常好。众所周知的程序(如Spotify)经常使用它来防止逆向工程。它具有防止在OllyDbg和Ida Pro等程序中调试的功能

还有一个更大的列表,可能有些过时。
其中一些是免费的

密码匹配

这里有人讨论了密码+盐的散列

如果需要存储密钥以与用户提交的某种密码相匹配,则应使用单向散列函数,最好将用户名、密码和salt组合在一起。但问题是,应用程序必须知道salt,才能进行单向运算并比较结果哈希。因此,您仍然需要将盐存储在应用程序中的某个位置。但是,正如@Edward在下面的评论中指出的那样,这将有效地防止字典攻击,例如使用rainbow表


最后,您可以使用上述所有技术的组合。

我同意@Checkers,您的可执行文件可以进行反向工程

更好的方法是动态创建它,例如:

std::string myKey = part1() + part2() + ... + partN();

与在可执行文件中存储私钥不同,您可能希望从用户处请求私钥,并通过类似于Mac OS X Keychain Access的外部方式将其存储。

当然,将私钥数据存储在软件中并发送给用户始终是一种风险。任何受过充分教育(且敬业)的工程师都可以对数据进行逆向工程

也就是说,你可以通过提高人们需要克服的障碍来公开你的私人数据,从而使事情变得足够安全。这通常是一个很好的妥协

在您的情况下,您可以将字符串与不可打印的数据混在一起,然后在运行时使用一个简单的助手函数对其进行解码,如下所示:

void unscramble( char *s )
{
    for ( char *str = s + 1; *str != 0; str += 2 ) {
        *s++ = *str;
    }
    *s = '\0';
}

void f()
{
    char privateStr[] = "\001H\002e\003l\004l\005o";
    unscramble( privateStr ); // privateStr is 'Hello' now.

    string s = privateStr;
    // ...
}

首先,要意识到你所能做的任何事情都无法阻止一个有足够决心的黑客,而且周围还有很多这样的人。每个游戏和控制台上的保护最终都会被破解,所以这只是一个临时修复

你可以做四件事来增加隐藏一段时间的机会

1) 以某种方式隐藏字符串的元素——类似于xoring(^operator)之类的明显操作。使用另一个字符串来隐藏字符串足以使字符串无法搜索

2) 将字符串拆分为多个片段——将字符串拆分,并在奇怪的模块中将其中的一些片段放入命名奇怪的方法中。不要让搜索和查找包含字符串的方法变得容易。当然,有些方法将不得不调用所有这些位,但这仍然使它变得有点困难

3) 永远不要构建字符串
0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL
// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xCF, 0x34, 0xF8, 0x5F, 0x5C, 0x3D, 0x22, 0x13, 0xB4, 0xF3, 0x63, 0x7E, 0x6B, 0x34, 0x01, 0xB7, 0xDB, 0x89, 0x9A, 0xB5, 0x1B, 0x22, 0xD4, 0x29, 0xE6, 0x7C, 0x43, 0x0B, 0x27, 0x00, 0x91, 0x5F, 0x14, 0x39, 0xED, 0x74, 0x7D, 0x4B, 0x22, 0x04, 0x48, 0x49, 0xF1, 0x88, 0xBE, 0x29, 0x1F, 0x27 };

myKey[30] -= 0x18;
myKey[39] -= 0x8E;
myKey[3] += 0x16;
myKey[1] += 0x45;
myKey[0] ^= 0xA2;
myKey[24] += 0x8C;
myKey[44] ^= 0xDB;
myKey[15] ^= 0xC5;
myKey[7] += 0x60;
myKey[27] ^= 0x63;
myKey[37] += 0x23;
myKey[2] ^= 0x8B;
myKey[25] ^= 0x18;
myKey[12] ^= 0x18;
myKey[14] ^= 0x62;
myKey[11] ^= 0x0C;
myKey[13] += 0x31;
myKey[6] -= 0xB0;
myKey[22] ^= 0xA3;
myKey[43] += 0xED;
myKey[29] -= 0x8C;
myKey[38] ^= 0x47;
myKey[19] -= 0x54;
myKey[33] -= 0xC2;
myKey[40] += 0x1D;
myKey[20] -= 0xA8;
myKey[34] ^= 0x84;
myKey[8] += 0xC1;
myKey[28] -= 0xC6;
myKey[18] -= 0x2A;
myKey[17] -= 0x15;
myKey[4] ^= 0x2C;
myKey[9] -= 0x83;
myKey[26] += 0x31;
myKey[10] ^= 0x06;
myKey[16] += 0x8A;
myKey[42] += 0x76;
myKey[5] ^= 0x58;
myKey[23] ^= 0x46;
myKey[32] += 0x61;
myKey[41] ^= 0x3B;
myKey[31] ^= 0x30;
myKey[46] ^= 0x6C;
myKey[35] -= 0x08;
myKey[36] ^= 0x11;
myKey[45] -= 0xB6;
myKey[21] += 0x51;
myKey[47] += 0xD9;
// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
wchar_t myKey[48];

myKey[21] = 0x00A6;
myKey[10] = 0x00B0;
myKey[29] = 0x00A1;
myKey[22] = 0x00A2;
myKey[19] = 0x00B4;
myKey[33] = 0x00A2;
myKey[0] = 0x00B8;
myKey[32] = 0x00A0;
myKey[16] = 0x00B0;
myKey[40] = 0x00B0;
myKey[4] = 0x00A5;
myKey[26] = 0x00A1;
myKey[18] = 0x00A5;
myKey[17] = 0x00A1;
myKey[8] = 0x00A0;
myKey[36] = 0x00B9;
myKey[34] = 0x00BC;
myKey[44] = 0x00B0;
myKey[30] = 0x00AC;
myKey[23] = 0x00BA;
myKey[35] = 0x00B9;
myKey[25] = 0x00B1;
myKey[6] = 0x00A7;
myKey[27] = 0x00BD;
myKey[45] = 0x00A6;
myKey[3] = 0x00A0;
myKey[28] = 0x00B4;
myKey[14] = 0x00B6;
myKey[7] = 0x00A6;
myKey[11] = 0x00A7;
myKey[13] = 0x00B0;
myKey[39] = 0x00A3;
myKey[9] = 0x00A5;
myKey[2] = 0x00A6;
myKey[24] = 0x00A7;
myKey[46] = 0x00A6;
myKey[43] = 0x00A0;
myKey[37] = 0x00BB;
myKey[41] = 0x00A7;
myKey[15] = 0x00A7;
myKey[31] = 0x00BA;
myKey[1] = 0x00AC;
myKey[47] = 0x00D5;
myKey[20] = 0x00A6;
myKey[5] = 0x00B0;
myKey[38] = 0x00B0;
myKey[42] = 0x00B2;
myKey[12] = 0x00A6;

for (unsigned int fngdouk = 0; fngdouk < 48; fngdouk++) myKey[fngdouk] ^= 0x00D5;
// myKey = "mysupersupersecretpasswordthatyouwillneverguess";
unsigned char myKey[48] = { 0xAF, 0xBB, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xB7, 0xB2, 0xA7, 0xB4, 0xB5, 0xA7, 0xA5, 0xB4, 0xA7, 0xB6, 0xB2, 0xA3, 0xB5, 0xB5, 0xB9, 0xB1, 0xB4, 0xA6, 0xB6, 0xAA, 0xA3, 0xB6, 0xBB, 0xB1, 0xB7, 0xB9, 0xAB, 0xAE, 0xAE, 0xB0, 0xA7, 0xB8, 0xA7, 0xB4, 0xA9, 0xB7, 0xA7, 0xB5, 0xB5, 0x42 };

for (unsigned int dzxykdo = 0; dzxykdo < 48; dzxykdo++) myKey[dzxykdo] -= 0x42;
#define POPULATE_DATA(str, i0, i1, i2, i3)\
{\
    char *p = str;\
    p[3] = i3;\
    p[2] = i2;\
    p[0] = i0;\
    p[1] = i1;\
}
char part1[4] = {0};
char part2[4] = {0};
POPULATE_DATA(part1, 1, 2, 3, 4); 
POPULATE_DATA(part2, 5, 6, 7, 8);
#include "obfuscate.h"

int main()
{
  std::cout << AY_OBFUSCATE("Hello World") << std::endl;
  return 0;
}
std::string var = AY_OBFUSCATE("string");