初始化向量在openssl_encrypt

2022-08-30 08:08:58

我看了一下这个问题,想自己做。当我运行此代码时(直接取自此答案):

$textToEncrypt = "My super secret information.";
$encryptionMethod = "AES-256-CBC";  // AES is used by the U.S. gov't to encrypt top secret documents.
$secretHash = "25c6c7ff35b9979b151f2136cd13b0ff";

//To encrypt
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, '1234567812345678');

//To Decrypt
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash);

//Result
echo "Encrypted: $encryptedMessage <br>Decrypted: $decryptedMessage";

但是我收到警告

openssl_encrypt(): Using an empty Initialization Vector (iv) is potentially insecure and not recommended

所以我去看了一下文档,但“没有文档”。我发现了这个评论,但仍然没有提到初始化向量应该是什么以及我应该如何使用它。任何人都可以启发我吗?

我知道我本可以做更多的Google,但是Stackoverflow在如此多的搜索结果中排名第一,我认为这个问题可能对其他遇到这个问题的人有用。


答案 1

IV通常是一个随机数,用于保证加密文本是唯一的。

为了解释为什么需要它,让我们假设我们有一个用密钥“secret”加密的人名数据库,没有IV。

1 John dsfa9p8y098hasdf
2 Paul po43pokdfgpo3k4y
3 John dsfa9p8y098hasdf

如果约翰 1 知道他的密码文本 (dsfa9p8y098hasdf) 并可以访问其他密码文本,他可以很容易地找到其他名叫约翰的人。

现在实际上,需要IV的加密模式将始终使用IV。如果未指定 IV,则会自动将其设置为一堆空字节。想象一下第一个示例,但具有常量 IV (00000000)。

1 John dsfa9p8y098hasdf 00000000
2 Paul po43pokdfgpo3k4y 00000000
3 John dsfa9p8y098hasdf 00000000

为了防止重复的密文,我们可以使用相同的“秘密”密钥和随机IV对名称进行加密:

1 John sdf875n90mh28458 86714561
2 Paul fg9087n5b60987nf 13541814
3 John gjhn0m89456vnler 44189122

如您所见,两个“约翰”密码文本现在不同了。每个IV都是唯一的,并且影响了加密过程,使最终结果也是唯一的。约翰一世现在不知道用户3的名字是什么。

解密当然需要使用与文本加密相同的IV,这就是为什么它必须与加密数据一起存储的原因。对于解密,IV是无用的‡,没有密钥,因此与加密文本一起传输或存储它无关紧要。

这是一个过于简单化的例子,但事实是,不使用IV具有严重的安全后果,这就是IV首先存在的原因。毫无疑问,无数的无IV加密实现已被利用。

‡ 随着我的安全知识的进步,我了解到,对于各种块密码模式和串联技术(与下面描述的串联方法没有特别关系),有一些更复杂的漏洞利用,可以利用IV来获取密钥。利用 RC4 数据流来确定密钥并解密 WEPWPA 等旧技术 Wi-Fi 流量的值得注意的示例:


现在,您的代码似乎正在设置 IV(1234567812345678),但在解密时未使用它。这肯定会失败。

您可能还想利用 PHP 的一些 IV 生成函数。我认为这应该对你有用:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encryptedMessage = openssl_encrypt($textToEncrypt, $encryptionMethod, $secretHash, 0, $iv);
$decryptedMessage = openssl_decrypt($encryptedMessage, $encryptionMethod, $secretHash, 0, $iv);

对于存储/传输,一种选择是简单地连接 IV 和密文,如下所示:

$data = $iv.$encryptedMessage;

然后在检索时,将IV拉出进行解密:

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
$iv = substr($data, 0, $iv_size);
$decryptedMessage = openssl_decrypt(substr($data, $iv_size), $encryptionMethod, $secretHash, 0, $iv);

例如,如果要将 IV 存储在数据库中,则还可以将 IV 存储在相邻列中以简化提取过程。


有关更多信息,请查看 PHP 的 Mcrypt 库。它功能非常齐全,并且有大量的示例,其中许多可以帮助您实现opensh加密实现。http://php.net/manual/en/function.mcrypt-encrypt.php


强制性安全免责声明:我的话以最简单的方式描述了最简单的概念。在我的知识范围和深度上,我是一个绝对的新手。即使是最好的安全研究人员和专家也一直在引入加密漏洞。即便如此,你自己写的越少,你的用户、客户、家人和朋友就会越好。没有冒犯!虽然学习加密理论很有趣,很有趣,甚至很实用,特别是在像PHP这样可访问的东西中应用于计算机科学,但保持最新的最佳实践并使用最新的可信库将为99.9999999%的人提供最安全的系统。没有什么是完美的,但最好站在巨人的肩膀上。正如一个智者可能会说的那样,“你学得越多,你就越意识到你知道的是多么的少。


答案 2

推荐