我需要储存敏感信息(对称加密钥匙,我想保持私人)在我的C++应用程序。简单的方法是可以做到这一点:

std::string myKey = "mysupersupersecretpasswordthatyouwillneverguess";

然而,运行的应用程序通过 strings 法(或者任何其他提取串从二进制的应用程序)将揭示的上述串。

什么样的技术应被用来掩盖这类敏感数据?

编辑:

好,所以几乎所有你所说的 "你可执行的,可以反向工程" -当然!这是一个忌讳,因此我要强调一点:

为什么99%(确定,所以,也许我夸张了一点)的所有与安全相关的问题上这个网站是回答了洪流"没有任何可能的方式创造一个完美的安全程序"-这是不是一个有用的答案!安全是一个滑动的规模之间完美的可用性和不安全的一端,和完善的安全,而没有可用性。

你拿起你的位置在那滑动的规模取决于什么你想要做到与环境中,你的软件运行。 我不是写一个程序,对于一个军事设施,我编写的应用程序为一家电脑.我需要密数据跨越不信任的网络与一个预知的加密钥匙。在这些情况下,"安全通过默默无闻"可能是好的够了!肯定有人有足够的时间、能源和技术人员可以反向工程处的二进制并找到密码的,但是你猜怎么着?我不关心:

所需的时间我实现一个顶尖的安全系统是更昂贵的销售损失,由于破解的版本(不,我实际上销售这个,但你得到我的点)。这个蓝色的天空的"允许做绝对是最好的方式可能"的趋势,在编程之间的新程序是愚蠢的至少可以这样说。

谢谢你抽出时间来回答这个问题-他们最有帮助的。不幸的是我只能接受一种回答,但我已经上投票的所有有用的答案。

有帮助吗?

解决方案

基本上,任何人都有权访问你的程序和一个调试器 可以 找到关键的应用程序,如果他们想要的。

但是,如果你只是想要确定的关键并不显示了在运行 strings 在你的二进制的,你可以例如确保关键不在印刷的范围。

模糊的关键用XOR

例如,可以使用异或分裂的关键成两个字阵列:

key = key1 XOR key2

如果创建键1用相同的字节的长度 key 你可以使用(完)随机的字节的数值,然后计算 key2:

key1[n] = crypto_grade_random_number(0..255)
key2[n] = key[n] XOR key1[n]

你可以这样做在你的生成环境,然后仅存 key1key2 在你的申请。

保护你的二进制

另一种办法是使用一种工具来保护你的二进制的。例如,有几个安全的工具,可以确保你的二进制是模糊处理的,并开始一个虚拟机运行。这使得它很难(er)调试,也是convential方式的许多商品级的安全应用程序(还有,可惜的是,恶意软件)受到保护。

首屈一指的是工具 Themida, ,这真棒工作的保护你的二进制文件。这是经常使用的众所周知的程序,例如音乐,以防止反向工程。它具有的功能,以防止在调试程序,如OllyDbg和开发协会。

还有一个更大的清单,也许有些过时, 工具来保护你的二进制.
他们中的一些是免费的。

密码配对

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

如果你需要存储的关键匹配它对某种类型的用户提交了密码,你应该使用单向散列函数,最好通过合用户名、口令和盐。这个问题,虽然,这是你的应用已经知道的盐能够做的一样,并比较所得的散列。因此你仍然需要储存的盐某处在应用程序。但是,如@爱德华指出,在下面的意见,这将有效地保护对一个典攻击使用,e。g、彩虹表。

最后,可以结合使用所有的技术上。

其他提示

首先,意识到,没有什么是你可以做,这将阻止一个充分确定,并有大量的那些。保护每一个游戏和控制台的周围是破裂的最终,所以这只是一个临时的解决办法。

有4个你可以做的事情,将会增加你的机会隐藏住一段时间。

1)隐藏的因素的串在一些方式--一些东西很明显喜欢异或(^运算符)串的另一串将足够的使串不可能搜索。

2)分串到条--分割你的串和弹位的到奇怪的命名方法在奇怪的模块。不要让它轻易通过搜索和查找的方法与串。当然有些方法将必须呼吁所有这些位,但它仍然使得它有点困难。

3)不要建立在存储器--最黑客使用的工具,让他们看到的字符串中的存储器之后你有的编码。如果可能,避免这种情况。例如,如果你们发送的关键一个服务器发送一个字一个字的,因此整个串是从周围。当然,如果您使用的是它的东西喜欢RSA编码,然后这是棘手。

4)一个特设算法--在这一切之上,增加独特的扭曲或二。也许只是增加1你的一切生产,或做任何加两倍,或者添加一个糖。这只是使得它有点困难的黑客人已经知道要找什么时候有人使用,例如,香草md5哈希或RSA密。

综上所述,确保它不太重要(并将它的时候如果你申请成为受欢迎的足够的)关键是发现!

一项战略,我已在过去使用的是创建一系列的看似随机的字符。你最初插入,然后找到你的特殊字符用代数过程中每一步骤从0到N将产生一个号码 < 尺寸阵列,其中包含的下一个焦在你的模糊字符串。(这个答案是的感觉的模糊!)

例如:

鉴于一系列的字符的(数字和破折号是仅供参考)

0123456789
----------
ALFHNFELKD
LKFKFLEHGT
FLKRKLFRFK
FJFJJFJ!JL

和一个方程式,其第六个结果是:3, 6, 7, 10, 21, 47

会产生一词的"你好!"从阵列以上。

我同意@跳棋,你可执行的,可以反向设计。

一个好一点的方法是创建它的动态,例如:

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

我已经创建了一个简单的加密工具,用于串,可以自动生成密串的和有几个额外的选项,做到这一点,一些例子:

串作为一个全球性的变量:

// 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;

为unicode串密循环:

// 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;

当然,存放的私人数据的软件,该软件是运送到用户总是有风险的。任何充分的教育(和专用)的工程师可以反向工程数据。

这就是说,你可以经常做的事情够安全通过提高障其人民需要克服,以显示你的私人数据。这通常是一个很好的妥协。

在你的情况,你可以弄乱你的串不可打印的数据,然后解,在运行时使用一个简单辅助功能,像这样:

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;
    // ...
}

有些依赖于什么你是想保护作为joshperry点。从经验看,我要说的是,如果这是一部分的一些授权的方案来保护你的软件,然后不要打扰。他们将eventially反向工程。只是使用一个简单的密码就像ROT-13,以保护它从简单的攻击(线运行的串通过)。如果它是确保用户敏感的数据,我将问是否有保护的数据与一个私钥储存在本地是明智之举。它再次下来你正在尝试保护。

编辑:如果你要做到这一点,然后结合的技术,克里斯指出将远远好于rot13.

如前所述,有没有办法完全保护你的串。但有的方式来保护它wis一个合理的安全。

当我不得不这样做,我没有把一些无辜的看串入代码(版权为例,或某些伪造的用户提示或其他任何东西,将不会改变一个人的固定无关的代码),密的,使用本身作为关键,哈,(增加了一些盐),并用于作为结果一个密钥进行加密是什么我确实想要加密。

当然这可能是黑客攻击,但它不会采取一个确定的黑客这样做。

而不是储存私人钥匙在你可执行的,你可能想要请求它从用户和存储它借助于外部 密码管理, 类似于Mac OS X钥匙链接。

如果你是在窗户DPAPI, http://msdn.microsoft.com/en-us/library/ms995355.aspx

作为一个前后说如果你是在mac使用钥匙链。

基本上所有的这些可爱的想法如何储存你的私人钥匙在你的二进制是充分的穷人从安全的角度看,你不应该这样做。任何人得到你的私人钥匙是一个大问题,不要让它在你的节目。这取决于如何进你的程序是可以保持你的私人钥匙在智能卡上,在一个偏远的计算机代码的谈话或者你可以做大多数人做些什么,并保持它在一个很安全的地方在当地的计算机(在"储存",这是一种像一个奇怪的安全的注册),是保护的权限和所有的力量的操作系统。

这是一个解决问题和答案是不要保持关键的内部程序:)

尝试 .源代码的解释了如何进行加密和解密的飞行的所有串在一定Visual Studio c++的项目。

一个方法我最近想是:

  1. 采取的散列(SHA256)的私人数据和填充它在代码 part1
  2. 采取异或私人数据和其散列和填充它在代码 part2
  3. 填充数据:不保存它作为char str[],但是填入运行时使用分配的说明(如宏下面)
  4. 现在,产生的私人数据在运行时采取的XOR part1part2
  5. 额外的步骤:计算的散列所产生的数据和比较 part1.它将验证的完整性的私人数据。

宏来填充数据:

假定,私人数据的4个字节。我们确定一个宏观的保存数据与分配的指示在一些随机的订单。

#define POPULATE_DATA(str, i0, i1, i2, i3)\
{\
    char *p = str;\
    p[3] = i3;\
    p[2] = i2;\
    p[0] = i0;\
    p[1] = i1;\
}

现在,使用这个宏代码中你需要保存 part1part2, 如下:

char part1[4] = {0};
char part2[4] = {0};
POPULATE_DATA(part1, 1, 2, 3, 4); 
POPULATE_DATA(part2, 5, 6, 7, 8);

下文依赖,但你只能储存 哈希 关键的加一个 (恒串,容易掩盖).

然后当(如果)用户进入的关键,你加入 , 计算 哈希 和比较。

可能是不必要的,在这种情况下,就停止暴力破解的字典如果攻击的散列可以分离(a谷歌搜索,也已经知道到工作)。

一个黑客仍然只有插入一个jmp指令的某个地方来绕过很多,但这是相当复杂得多,一个简单文本搜索。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top