您想避免自己实现加密算法的原因是因为侧信道攻击。
什么是边信道?
当您与服务器通信时,消息的内容是通信的“主要”渠道。但是,您可以通过其他几种方式从您的沟通伙伴那里获取信息,这些信息不直接涉及他们告诉您的事情。
这些包括但不限于:
- 回复你的时间
- 服务器处理您的请求所消耗的能量
- 服务器访问缓存以响应您的频率。
什么是侧信道攻击?
简而言之,边信道攻击是对涉及这些边信道之一的系统的任何攻击。以下面的代码为例:
public bool IsCorrectPasswordForUser(string currentPassword, string inputPassword)
{
// If both strings don't have the same length, they're not equal.
if (currentPassword.length != inputPassword.length)
return false;
// If the content of the strings differs at any point, stop and return they're not equal.
for(int i = 0; i < currentPassword.length; i++)
{
if (currentPassword[i] != inputPassword[i])
return false;
}
// If the strings were of equal length and never had any differences, they must be equal.
return true;
}
这段代码在功能上似乎是正确的,如果我没有打错任何字,那么它可能会做它应该做的事情。你还能发现侧信道攻击向量吗?这是一个演示它的示例:
假设用户的当前密码是Bdd3hHzj
(8 个字符)并且攻击者正试图破解它。如果攻击者输入一个相同长度的密码,则if
检查和循环的至少一次迭代都for
将被执行;但如果输入的密码短于或长于 8 个字符,则只会if
执行 。前一种情况做的工作更多,因此比后者需要更多的时间来完成;比较检查 1-char、2-char、3-char 等密码所需的时间很简单,并注意 8 个字符是唯一显着不同的字符,因此可能是正确的长度密码。
有了这些知识,攻击者就可以改进他们的输入。首先他们尝试aaaaaaaa
通过aaaaaaaZ
,每个都只执行一次循环迭代for
。但是当它们来到 时Baaaaaaa
,会发生两次循环迭代,这再次比以任何其他字符开头的输入需要更多的时间来运行。这告诉攻击者用户密码的第一个字符是字母B
,他们现在可以重复此步骤来确定剩余的字符。
这与我的加密代码有何关系?
加密代码看起来与“常规”代码非常不同。查看上面的示例时,它似乎没有任何明显的错误。因此,在您自己实现事物时,可能并不明显的是,执行它应该做的代码只是引入了一个严重的缺陷。
我能想到的另一个问题是程序员不是密码学家。他们倾向于以不同的方式看待世界,并且经常做出可能很危险的假设。例如,看下面的单元测试:
public void TestEncryptDecryptSuccess()
{
string message = "This is a test";
KeyPair keys = MyNeatCryptoClass.GenerateKeyPair();
byte[] cipher = MyNeatCryptoClass.Encrypt(message, keys.Public);
string decryptedMessage = MyNeatCryptoClass.Decrypt(cipher, keys.Private);
Assert.Equals(message, decryptedMessage);
}
你能猜出是怎么回事吗?我不得不承认,这不是一个公平的问题。MyNeatCryptoClass
实现 RSA,如果没有明确给出指数,则在内部设置为使用默认指数 1。
是的,如果您使用 1 的公共指数,RSA 就可以正常工作。它不会真正“加密”任何东西,因为“x 1 ”仍然是“x”。
您可能会问自己,谁在他们的正常头脑中会这样做,但确实有这种情况发生。
实施错误
实现自己的代码可能出错的另一个原因是实现错误。正如用户Bakuridu在评论中指出的那样,与其他错误相比,加密代码中的错误是致命的。这里有一些例子:
心脏出血
当涉及到密码学时, Heartbleed可能是最著名的实现错误之一。虽然不直接涉及加密代码的实现,但它仍然说明了一个相对“小”的错误会发生多么可怕的错误。
虽然链接的 Wikipedia 文章对这个问题有更深入的了解,但我想让 Randall Munroe 比以往任何时候都更简洁地解释这个问题:
https://xkcd.com/1354/ - 图像在 CC 2.5 BY-NC 下获得许可
Debian 弱 PRNG 错误
早在 2008 年, Debian中就有一个 bug,它影响了所有进一步使用的密钥材料的随机性。Bruce Schneier 解释了 Debian 团队所做的更改以及为什么会出现问题。
基本要点是检查 C 代码中可能存在的问题的工具抱怨使用未初始化的变量。虽然通常这是一个问题,但用本质上随机的数据播种 PRNG 也不错。然而,由于没有人喜欢盯着警告并且被训练忽略警告可能会导致它自己的问题,因此“违规”代码在某个时候被删除,从而导致 OpenSSL 使用的熵减少。
概括
总而言之,除非它旨在成为一种学习体验,否则不要实施您自己的 Crypto!使用经过审查的加密库,旨在使正确操作变得容易,错误操作变得困难。因为 Crypto 很容易出错。