最新消息:修改中。。。

PHP用openssl_encrypt代替mcrypt_encrypt

PHP BlueTea 296浏览 0评论

每个人都应该已经停止使用PHP Mcrypt扩展程序进行新的工作,并且应该计划将其现有的应用程序关闭,因为libmcrypt在2003年被放弃,并且不被保护。
我认为最好的选择是OpenSSL。近年来热度很高,但我认为对称块加密是一个很好的选择。 (我可能会解释为什么我这么想呢)
PHP中的 openssl_encrypt()openssl_decrypt()的文档有点缺乏。本文旨在填补一些空白。这是两者的签名。

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

我们将始终使用一个初始化向量,结果是$options有很大的不同,所以我们可以简化:

string openssl_encrypt ( string $data , string $method , string $password , int $options, string $iv )
string openssl_decrypt ( string $data , string $method , string $password , int $options, string $iv )

其中$opention将是OPENSSL_RAW_DATAOPENSSL_ZERO_PADDING

## $password参数是加密密钥

$password参数名称非常误导。它不是密码,它是一个加密密钥。openssl enc命令行实用程序将接受密码或密钥将执行密钥导出和盐析,如果你想要的。但这些PHP函数希望$password成为加密密钥。

它们还需要为您使用的密码算法准备好密钥。我只使用密钥大小为16字节的AES-128。如果您通过openssl_en/decrypt()一个密钥(在$ password参数中)长于密码的本质密钥大小,则会将该余数丢弃。如果通过一个短于预期的键,则填充为零,即\x00字节。

所以你需要仔细准备你的钥匙。如果用户提供密码,请使用类似PBKDF2的特殊盐。如果您有输入加密密钥,则可以使用HKDF导出openssl_en/decrypt()的密钥。

所以让我们再简化一下:

string openssl_encrypt ( string $data , string $method , string $key , int $options, string $iv )
string openssl_decrypt ( string $data , string $method , string $key , int $options, string $iv )

如果您正在生成密钥,而不是从用户输入密钥或密码中导出密钥,则应使用从加密安全伪随机数生成器或CSPRNG中提取的随机字节的二进制字符串.(我也许会博客介绍如何在PHP中获取这样的字符串,实际上并不像调用openssl_random_pseudo_bytes()一样简单。)

初始化向量 $iv

初始化向量$ iv的要求类似于$password的要求。它应该是与密码块大小相同长度的二进制字符串。过多的字节被丢弃,并且太短的$ iv被填充到零字节的块大小。

初始化向量应该是来自CSPRNG的随机字节的二进制串。不要重复使用IV。

密码规范 $method

$method允许值由PHP平台上的openssl_get_cipher_methods()函数列出,并在openssl enc文档中更详细地列出。
我不打算讨论这些的相对优点。我唯一使用的是CBC模式的AES。除了RC5(由RAS获得专利但未被广泛使用)外,OpenSSL提供的所有其他对称块密码都具有64位或更小的块。
我总是使用AES-128,它有一个16字节的键。所以这意味着我会选择“AES-128-CBC”。我想你可以安全地选择’AES-192-CBC’或’AES-256-CBC’,但是我不会被引用到最好的论点。
在任何情况下,$method都必须是openssl_get_cipher_methods()返回的字符串之一,您必须使用适当长度的$ iv和$ key才能使用该密码。

编码、填充和OPENSSL_RAW_DATA与OPENSSL_ZERO_PADDING

Mcrypt中,加密和解密的输入和输出编码是原始的二进制字符串。 Paintextciphertext都是二进制字符串。

CBCECB模式下使用块密码加密之前,Mcrypt会自动将零字节填充添加到明文中,并在解密之后返回零字节填充的明文(即,Mcrypt在解密之后不删除填充)。

注意:以下是错误,请参阅下面My1的注释。选项表示两个标志:将OPENSSL_RAW_DATA位设置为使用二进制字符串,并将其设置为base64。设置OPENSSL_ZERO_PADDING位来进行自己的填充或取消设置,openssl_en/decrypt()做PKCS7填充。

OpenSSL有两种模式:
$options = OPENSSL_RAW_DATA
openssl_encrypt()openssl_decrypt()的输入和输出编码都是二进制字符串,即plaintextcipertext都是二进制字符串。
openssl_encrypt()在CBC或ECB模式下使用块密码加密之前,将PKCS7填充添加到明文中。
openssl_decrypt()解密之后剥离填充。
– 如果$ options = OPENSSL_ZERO_PADDING则
openssl_encrypt()的输入编码和openssl_decrypt()的输出编码是原始的二进制字符串,即明文是原始的二进制字符串。
– 输出编码fron openssl_encrypt()和对openssl_decrypt()的输入编码是base64,即密文是base64编码的。
openssl_encrypt()的输入大小必须是块大小的整数倍,否则返回错误代码。
openssl_encrypt()不添加填充,或者由openssl_decrypt()删除,

可以做任何工作,但我更喜欢OPENSSL_RAW_DATA。如果我需要密文的特定编码,那我宁愿自己做。而PKCS7将是我的填充选择,实际上这是我用于Mcrypt的。

总结

已经弄清了这两个功能的所有这些未记录的功能,结果是我打算使用OpenSSL进行对称加密的唯一方法是这样的:

$ciphertext = openssl_encrypt($plaintext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
$plaintext = openssl_decrypt($ciphertext, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);

其中:
$plaintext是任何字符串,任何长度。
$key是16字节长的二进制字符串形式的加密密钥(因为AES-128的密钥大小为16字节)
$iv是一个16位字节长的加密安全随机二进制字符串(因为AES具有16个字节的块大小),我将只使用一次
$ciphertext是一个比$plaintext长1到16个字节之间的二进制字符串(因为PKCS7填充到16字节块大小)

并记住加密密钥必须从输入密钥材料或密码中正确派生或由CSPRNG生成。

结语

记住,如果您需要加密数据,那么您几乎肯定也需要进行身份验证。为此,您可以使用HMAC签名。使用SHA-2算法之一。 还要记住最后签名并进行认证,即HMAC需要覆盖包含加密数据的整个消息

 

原文 http://thefsb.tumblr.com/post/110749271235/using-opensslendecrypt-in-php-instead-of

转载请注明:码农生活-田伟博客 » PHP用openssl_encrypt代替mcrypt_encrypt

发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址