在PHP中确定性地从密码派生32字节密钥

Rya*_*yan 5 php encryption hash aes laravel

今天我了解到"密码"倾向于表示任意数量字符的可记忆字符串,而"密钥"表示高度随机的字符串(基于所使用的加密算法的特定长度).

所以今天我第一次听说了Key推导函数的概念.

我对如何从任意长度的密码(在PHP中)派生32字节密钥感到困惑.

以下方法有效但忽略 "[盐]应随机生成"的说明(也是如此):

$salt = 'this salt remains constant';
$iterations = 10;
$length = 32;
$aesKey = hash_pbkdf2('sha256', $somePasswordOfArbitraryLength, $salt, $iterations, $length, false);
Run Code Online (Sandbox Code Playgroud)

以下方法也有效,但也不是很正确:

$hash = password_hash($somePasswordOfArbitraryLength, PASSWORD_BCRYPT, ['cost' => $iterations]);
$aesKey = substr($hash, -$length);//this smells weird
Run Code Online (Sandbox Code Playgroud)

通过我的所有搜索,我很惊讶我没有在PHP中找到一种"官方"方式来确定性地从密码中获取32字节密钥.

我该怎么办?

PS我在PHP中使用Laravel并希望使用AES-256-CBC加密,如下所示:

$encrypter = new \Illuminate\Encryption\Encrypter($aesKey, 'AES-256-CBC');
$encryptedText = $encrypter->encrypt($text);
Run Code Online (Sandbox Code Playgroud)

Laravel的加密助手(例如Crypt::encryptString('Hello world.'))似乎不符合我的要求,因为我希望每个用户的数据根据​​每个人的密码单独加密.

无论我使用哪种密钥派生函数,每次都会产生相同的密钥,因为我将使用对称加密来解密用户使用该密钥加密的字符串.

PPS由于问题1,2,和3用于引入某些概念我.

Dev*_*von 2

如果您希望每次解密或加密存储的字符串时都让他们重新发送密码,则必须使用一致的密码哈希并将盐和迭代存储在某处。

如果您使用password_hash函数,由于随机生成的盐,您永远不会得到相同的值。

>>> password_hash('abc', PASSWORD_BCRYPT)
=> "$2y$10$xR8tZQd0ljF5Ks3QrQt7i.vAbv.xVUc97uh.fX4w0mi/A647HlEWS"
>>> password_hash('abc', PASSWORD_BCRYPT)
=> "$2y$10$KzZWeg.o/4TyJVryWrz/oeWQ6VGj0JnPDW.d.Cp0svu8k6qKBcbWu"
Run Code Online (Sandbox Code Playgroud)

您可以通过选项传递盐,但这通过password_hash已被弃用,因此我建议您坚持使用第一个解决方案。

您不需要为每个人使用相同的盐,您可以生成随机盐并将其存储在某个地方,例如用户表。

请记住,使用这种类型的密钥派生,您需要在用户每次更改密码时重新加密所有值。