什么是 openssl iv,为什么我需要密钥和 iv?
Posted
技术标签:
【中文标题】什么是 openssl iv,为什么我需要密钥和 iv?【英文标题】:What is an openssl iv, and why do I need a key and an iv? 【发布时间】:2017-01-17 16:11:24 【问题描述】:我即将使用以下脚本来加密和解密一些数据。我正在使用它,因为我当前的加密在我们的新服务器上不起作用。我们目前正在使用 mcrypt,所以我想更改为 openssl。
在我们的数据库中,我们使用 aes 加密,它使用 128 位密钥,所以我知道密钥是什么,但我不知道 openssl iv 是什么?为什么我需要钥匙和静脉注射。
我将要使用的代码是这个,因为我对加密不是很了解,所以我在一个网站上找到的。
显然我会修改它,以便将密钥保存在其他地方。
function encrypt_decrypt($action, $string)
$output = false;
$encrypt_method = "AES-256-CBC";
$secret_key = 'This is my secret key';
$secret_iv = 'This is my secret iv';
// hash
$key = hash('sha256', $secret_key);
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
if( $action == 'encrypt' )
$output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
$output = base64_encode($output);
else if( $action == 'decrypt' )
$output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
return $output;
$plain_txt = "This is my plain text";
echo "Plain Text = $plain_txt\n";
$encrypted_txt = encrypt_decrypt('encrypt', $plain_txt);
echo "Encrypted Text = $encrypted_txt\n";
$decrypted_txt = encrypt_decrypt('decrypt', $encrypted_txt);
echo "Decrypted Text = $decrypted_txt\n";
if( $plain_txt === $decrypted_txt ) echo "SUCCESS";
else echo "FAILED";
echo "\n";
【问题讨论】:
iv = 初始化向量。谨慎的做法是在尝试实施加密之前投入一些时间来了解加密。 我了解 mysql 加密是如何使用 AES_ENCRYPT 工作的,但这是针对 mysql 的。这仅适用于需要加密的 php 字符串 @ThomasWilliams 默认情况下 MySQL 的AES_ENCRYPT
使用 ECB 模式,而不是 CBC。使用 ECB 是 MySQL 不要求您对其进行 IV 的原因。
如果您不了解这些内容,那么您需要使用能够正确处理这些细节的更高级别的加密 API。
【参考方案1】:
初始化向量是使 CBC(密码块链接)模式下的 AES 工作的一部分 - IV 不是 OpenSSL 独有的。 CBC 通过将前一个块与当前块进行异或来工作。第一个块没有前一个块,因此 IV 用于此目的。
为什么这是必要的,需要对分组密码的工作原理有所了解。如果没有这种链接和 IV,我们就剩下一种称为 ECB 或电子密码本的 AES 模式。 ECB 存在允许选择明文攻击以及许多其他问题的弱点。
我建议花一点时间了解 CBC 初始化向量的最佳实践。错误地使用它们会削弱 AES 的整体安全性。简短的解释是:
IV 应该是随机的并由 CSPRNG 生成。 不应重复使用 IV。也就是说,不要用相同的IV加密明文“A”和明文“B”。每条记录都应该有自己的 IV。 IV 不像钥匙那样是秘密。它可以与密文一起以明文形式存储。另外请记住,此建议仅适用于 AES-CBC。如果您曾经研究过其他 AES 模式,例如 GCM,则不适用。
【讨论】:
一个小小的补充:与密文一起存储...有些人倾向于简单地将其放在密文前面而不将其标记为IV...有时值得一试只需将密文的第一个块大小视为刚刚存储的 IV 的候选... 我将使用它来加密 URL 的字符串,例如 www.somesite.com?a=mystring。如果 iv 是随机生成的,你将如何解密它。我同意我需要对此做更多的阅读,但我的谷歌搜索只是导致了更多的混乱。在问这个问题之前,我确实用谷歌搜索了很多。 然后使用www.somesite.com?a=encypyptedstring&iv=theiv
。
@ThomasWilliams 恕我直言,您不应该自己实现这个。您对该主题缺乏了解意味着您很可能会犯实施错误并在您的安全性中留下一个巨大的漏洞。只是我的两分钱。查找更高级别的库。
我已经搞定了。我缺乏关于openssl的知识。然而,我已经用 c++ 和 php 编程了很长时间。自从提出这个问题以来,我已经阅读了很多关于它的内容,并且我已经将它全部实施并工作了。我曾经用 C++ 编写过自己的加密算法,但最好使用经过尝试和测试的东西而不是自己的代码。【参考方案2】:
假设两个用户的密码为“princess”,而您使用密钥“some-key”对他们进行编码,他们将得到相同的加密结果:
| User | Encrypted password |
|------------|-----------------------|
| a | sN7vIFg= |
| b | sN7vIFg= |
这意味着如果有人用不同的方式计算出用户a的真实密码是“princess”并且他们的加密密码是“sN7vIFg=”,那么任何具有加密密码“sN7vIFg=”的用户都可以被认为拥有密码“公主”。
但是,如果您对每个 IV 使用随机 IV,那么如果您可以访问加密数据,则更难猜测底层密码。
| User | Encrypted password | IV |
|------------|-----------------------|----------------|
| a | sN7vIFg= | h²ÓIF8]h%L |
| b | BjZAzrA= | VÂøíiøÚØò▓ |
现在,即使有人可以访问上述数据,他们也无法确定用户 a 和 b 具有相同的密码。
另见Is “real salt” the same as “initialization vectors”? 。
【讨论】:
【参考方案3】:我认为您可能混淆了“散列密钥”和“iv”(天知道我在开始加密时做了什么)。散列键正是您所做的。对于 iv,每次使用相同的密钥进行加密时,您应该使用不同的随机数据。 (我的背景:我必须构建一个 pdo 安全会话处理程序来加密/解密会话数据,所以我最终使用 openssl 扩展实现了 AES-256-CBC)
如果有人来这里,只是一个小提示。
// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning
$iv = substr(hash('sha256', $secret_iv), 0, 16);
不是生成 iv + 不需要 secret_iv 的正确方法,因为 iv 必须尽可能随机。不要把它(或理解它)当作散列一样对待。
由于您可以访问 openssl 扩展,因此有一种更好/更安全的方式为所选密码生成 iv,openssl 还可以告诉您密码的 iv 的正确长度:
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('AES-256-CBC'));
它将是二进制格式,所以如果你需要它的十六进制格式,请使用 bin2hex($iv)。 如果您需要将生成的 iv 存储在 mysql 中,我将其存储为原始格式(字段类型 varbinary,二进制也可以)。
还有一件事。您在 openssl_encrypt 和 _decrypt 中都将 $options 标记设置为 0,这意味着“如果设置为 true 将作为原始输出数据返回,否则返回值为 base64 编码”。
【讨论】:
喜欢重新创建 $iv 的解释 将其作为文件中密码消息的前缀时,生成的IV应该是哪种格式?【参考方案4】:我通常是这样设置的:
// PHP Function to encrypt
function encrypt_AES_CBC ($plaintext)
$method = "aes-256-cbc";
$key = "DADA068D255130F7AB5965BD47692E359EE7B0CBC81D9DAD42665B71F7807A4E";
$bkey = hex2bin($key);
$iv = hex2bin(md5(microtime().rand()));
$data = openssl_encrypt($plaintext, $method, $bkey, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv.$data);
// PHP Function to decrypt
function decrypt_AES_CBC ($encryptedText)
$method = "aes-256-cbc";
$key = "DADA068D255130F7AB5965BD47692E359EE7B0CBC81D9DAD42665B71F7807A4E";
$bkey = hex2bin($key);
$decoded = base64_decode($encryptedText);
$iv = substr($decoded, 0, 16);
$data = substr($decoded, 16);
return openssl_decrypt( $data, $method, $bkey, OPENSSL_RAW_DATA, $iv );
我创建了一个 FileMaker 插件 (acfplugin),它可以为给定的语音键生成此示例代码。
【讨论】:
【参考方案5】:我想根据主题中的问题提供一个简单的解释 - 为什么您需要密钥和 IV?换句话说,为什么仅仅一个密钥是不够的呢? (一般回答,不指具体算法)
首先让我们描述分组密码中发生的事情-分组密码获取密钥和文本作为输入。然后它将文本分成相同大小的块并分别加密每个块。这种方法的问题是给定一个密钥K-相同的明文块生成相同的密文块。这显然是不可取的,因为它使攻击者更容易识别模式。
为了避免这些模式,一种解决方案是在加密当前块时使用先前的密文块并将其连接到当前块。这样就没有模式了。
但是,您将什么连接到第一个块? IV- 初始化向量来了。该服务器作为初始值,可用作连接到第一个明文块的丢失密文块。
【讨论】:
以上是关于什么是 openssl iv,为什么我需要密钥和 iv?的主要内容,如果未能解决你的问题,请参考以下文章