准备在 PHP 7.2 中删除 Mcrypt
Preparing for removal of Mcrypt in PHP 7.2
所以随着时间的推移,mcrypt 将进入 PHP 7.2。
当然还有一个替代方案:openssl.
我发现很难从 mcrypt 切换到 openssl,使用 AES 256 CBC 并保留 IV。我对密码学有点陌生,所以我并不是真的什么都懂,但我了解基础知识。
假设我有以下代码
function encrypt($masterPassword, $data)
{
$keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$key = mb_substr(hash('SHA256', $masterPassword), 0, $keySize);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv . $encrypted);
}
function decrypt($masterPassword, $base64)
{
$keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$key = mb_substr(hash('SHA256', $masterPassword), 0, $keySize);
$data = base64_decode($base64);
$iv = substr($data, 0, $ivSize);
$encrypted = substr($data, $ivSize, strlen($data));
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
return trim($decrypted);
}
我如何"convert"此代码使用 openssl insted of mcrypt?
您无法转换它,因为 Rijndael-256 不是 AES-256,并且 OpenSSL 扩展不附带 Rijndael-256 支持。
AES-256 是带有 256 位(32 字节)密钥的 Rijndael-128。
很遗憾,您必须重新加密所有数据。
编辑:另外,您当前使用的方案存在一些问题:
- 它缺少身份验证(HMAC 是 PHP 中最简单的方法)
- 它缺少适当的填充(mcrypt 填充零字节;您需要类似 PKCS#5 的填充),这是块模式加密安全所必需的。
- 它不是字节安全的(您正在使用
mb_substr()
)
好消息是 OpenSSL 会自动为您执行 PKCS#5 填充,但您应该更进一步并使用可靠的加密库,例如 defuse/php-encryption。
所以随着时间的推移,mcrypt 将进入 PHP 7.2。 当然还有一个替代方案:openssl.
我发现很难从 mcrypt 切换到 openssl,使用 AES 256 CBC 并保留 IV。我对密码学有点陌生,所以我并不是真的什么都懂,但我了解基础知识。
假设我有以下代码
function encrypt($masterPassword, $data)
{
$keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_URANDOM);
$key = mb_substr(hash('SHA256', $masterPassword), 0, $keySize);
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $data, MCRYPT_MODE_CBC, $iv);
return base64_encode($iv . $encrypted);
}
function decrypt($masterPassword, $base64)
{
$keySize = mcrypt_get_key_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$key = mb_substr(hash('SHA256', $masterPassword), 0, $keySize);
$data = base64_decode($base64);
$iv = substr($data, 0, $ivSize);
$encrypted = substr($data, $ivSize, strlen($data));
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, MCRYPT_MODE_CBC, $iv);
return trim($decrypted);
}
我如何"convert"此代码使用 openssl insted of mcrypt?
您无法转换它,因为 Rijndael-256 不是 AES-256,并且 OpenSSL 扩展不附带 Rijndael-256 支持。
AES-256 是带有 256 位(32 字节)密钥的 Rijndael-128。
很遗憾,您必须重新加密所有数据。
编辑:另外,您当前使用的方案存在一些问题:
- 它缺少身份验证(HMAC 是 PHP 中最简单的方法)
- 它缺少适当的填充(mcrypt 填充零字节;您需要类似 PKCS#5 的填充),这是块模式加密安全所必需的。
- 它不是字节安全的(您正在使用
mb_substr()
)
好消息是 OpenSSL 会自动为您执行 PKCS#5 填充,但您应该更进一步并使用可靠的加密库,例如 defuse/php-encryption。