【问题标题】:What is the password parameter to openssl_encrypt?openssl_encrypt 的密码参数是什么?
【发布时间】:2014-03-17 07:45:58
【问题描述】:

openssl_encrypt 函数状态的 PHP 文档

string openssl_encrypt ( string $data , string $method , string $password [, int $options = 0 [, string $iv = "" ]])

谁能帮我理解名为$password 的参数是什么? 答案可能包括对这个想法的确认或拒绝,除了命名为$password 之外,该参数确实被用作加密的密钥。

openssl_encrypt 的密码参数是什么?它是密码字符串(仅包含可打印字符)还是密钥(包含不可打印字符和 ASCII-Z 终止符)?


说明

我被 PHP 的 openssl_encrypt 文档困住了。作为一个好人并尝试做“RTM”,我对恕我直言不满意的文档没有多大意义。

问题在于,对我来说,passwordkey 在加密方面是有区别的。密钥直接是用于加密的 参数,因此必须具有特定大小 - “密钥长度” - 即 128/256/512 位,具体取决于所需的密码和密钥长度。另一方面,password 是我理解的通过键盘输入的人类可读字符串,其长度可能不同,并且在用于加密之前首先转换为 key .

因此示意图上的区别:

  • 密码=>密钥=>加密
  • 密钥 => 加密

不幸的是,在 PHP openssl_encrypt documentation 中我找不到任何关于如何使用 key 的信息。唯一建议的是参数“密码”。

谁能给我一个胶水如何使用钥匙? 当然,我不想输入密钥作为密码参数,因为我希望在加密中使用特定的 key。我确实希望这个 key 被简单地误解为一个参数,并用作另一个从我的“被误认为密码的密钥”计算出来的密钥。

此外,谜团还在继续查看有关同一 openssl_encrypt 函数中的初始化向量参数的文档。它简单地说:

iv 非 NULL 初始化向量。 并且 iv 应该是一个字符串。鉴于 iv 通常是一定长度的二进制数据,例如一个以 \0 结尾的字符串(十六进制 0x00)可能会出现在里面,我很困惑需要什么格式。

本质上,我觉得自己很孤单,PHP 文档也声明了

警告此功能目前没有记录;只有它的论点 列表可用。

更新

我做了一些测试,并“尝试”以帮助我弄清楚 password 参数是什么。

使用此代码:

$pass="0123456789abcdefghijklmnob";
$iv="0123456789abcdef";
echo "using $pass results:\n";
echo openssl_encrypt("test secret string", 'aes-128-cbc',  $pass,NULL,$iv);

我得到这个结果:

using 0123456789abcdefghijklmnob results:
XjEeaLucY38Y6XEUceYMYKTebR4kOp3s727ipMl5KNc=

然后改变“密码”参数的长度:

$pass="0123456789abcdefg"; //hijklmnob";
$iv="0123456789abcdef";
echo "using $pass results:\n";
echo openssl_encrypt("test secret string", 'aes-128-cbc',  $pass,NULL,$iv);

我仍然得到相同的加密代码:

using 0123456789abcdefg results:
XjEeaLucY38Y6XEUceYMYKTebR4kOp3s727ipMl5KNc

似乎通过测试而不是通过被文档告知 密码确实只考虑到前 16 个字节,这似乎是密钥的 128 位。

让我害怕的是,在如此敏感的功能(用于加密)中,文档很糟糕,甚至没有警告过度输入一个记录不充分的参数。我也非常相信 password 应该被命名为 key 因为这 16 个字节似乎直接代表了密钥。

【问题讨论】:

  • @noloader 辱骂?真的吗?同意我不高兴 PHP 文档不够完美,但我是否使用了粗俗的语言?无论如何,感谢您提出突出问题的建议!
  • 确实,文档还有一些不足之处。您应该针对该项目提交一个文档错误,以便为未来的读者澄清它。

标签: php encryption parameters


【解决方案1】:

$password 参数确实是关键。密钥大小取决于您使用的 AES 模式(如您所知)。

正如您在更新中所述,对于 AES-128,只有前 16 个字符/字节才算作密钥。对于 AES-256,它将是前 32 个字符。

当使用openssl_encrypt()openssl_decrypt() 函数时,只需为$password/key 参数传递一个32 个字符的人类可读密码。

例如,我输入的密码参数可能是$password = "This is 32 characters long......";

大多数人不喜欢编写固定长度的明文密码,因此他们可能会计算哈希并将其截断为正确的长度。他们会使用这个哈希作为他们的加密密钥/密码。

例如,我可以计算任意长度的密码/短语的 MD5 哈希值,然后将其用作我的 AES 密码/密钥:

$plaintextPass = 'This is my password. This password is not exactly 32 bytes, but that is okay because I am hashing this.';
$password = hash('md5', $plaintextPass); /* the encryption key */

有了它,无论我使用什么明文密码,我都可以将有效的 32 个字符/字节字符串作为我的加密密钥/密码。但是,这确实降低了加密密钥/密码的熵,因为普通的 32 个字符的字符串比 MD5 哈希输出具有更大的密钥空间(每字节 256 种可能性与每字节 16 种可能性);但是,16^32 仍然肯定超出了蛮力的范围。

题外话:在我的一些个人程序中,我一直致力于使用 32 个随机生成的字节,其值在 0-255 之间。这将使加密密钥的熵为 256^32,这对于暴力破解是不可行的。这也可以抵抗字典攻击,因为 32 字节是使用 cryptographically secure pseudo-random number generator (CSPRNG) 随机生成的。

所以,总而言之,是的,$password 参数确实是用于加密的密钥。我同意你的观点,在文档中应该写成$key,但是哦,好吧。只要满足散列密钥的长度要求,您选择用于加密的密码/密钥就可以人工读取。为了满足这些长度要求,可以散列一个人类可读/明文密码并使用该密码的散列作为密钥($password 参数),但人类可读密码仍然应该是长且唯一的。

文档不是很清楚,但是openssl_encrypt() PHP 文档页面上的this comment 在我尝试理解该函数时确实帮助了我。该评论提供了一个示例以及有用的信息。直接引用评论作者:

因为这里记录的密码参数不是密码。 ... 这是关键! [评论略有编辑]

【讨论】:

  • 您可以使用$password = hex2bin(hash('md5', $plaintextPass)) 将哈希的十六进制输出转换为纯二进制。这样你实际上可以使用每个字节的所有 256 种可能性(只是不要指望密码是人类可读的)...... 16^32 仍然很大,但是,这样做很简单,而且不会造成伤害!跨度>
  • @Jojodmo,好点子,事实上,我相信你可以通过更少的方法调用来使用$password = hash('md5', $plainPass, true) 来获得相同的结果,因为这会将hash function's $raw_output 参数设置为真的。话虽这么说,如果我现在正在实施一个解决方案(比我六年前所知道的要多一点),我会考虑更改这个实施以使用基于密码的密钥派生函数,例如 PHP 的 hash_pbkdf2 function,原始输出。
  • 任何人都知道当您在 AES-256 模式下使用长度小于 32 字节的密码时会发生什么?它似乎有效,但我想知道该函数如何获取完整的 32 字节密钥。
  • @Peter,我可能会误解代码,但粗略一看,OpenSSL 似乎会对您的密码进行零填充。 (请参阅PHP's OpenSSL extension code。)看起来当密码长度小于密钥大小时,库分配一个零填充缓冲区,然后复制提供的任何密码字符。不过,我只是粗略地看了一眼。
  • @SpencerD 实际上上面的答案为我指明了正确的方向。从我的代码中,我认为我分配了一个长度较短的密钥,但是我将字母字符与十六进制混淆了,因此我有一个 60 个字符长的字符串密钥,它被截断为前 32 个字符(幸运的是):-D
猜你喜欢
  • 2016-02-06
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 2021-12-24
  • 1970-01-01
  • 2016-12-05
  • 2016-07-24
  • 1970-01-01
相关资源
最近更新 更多