不使用mcrypt进行加密/解密
最后更新于
最后更新于
在一般的 PHP 社区成员中,一个鲜为人知的事实是,作为大多数基于 PHP 的加密的核心的 mcrypt
扩展被认为是安全的,但它并不安全。从安全的角度来看,最大的问题之一是 mcrypt
扩展需要高级的密码学知识才能成功运行,而很少有程序员具备这些知识。这就导致了严重的误操作,最终导致数据损坏的几率为256分之一等问题。这可不是什么好机会。此外,开发人员对libmcrypt
的支持,即mcrypt
扩展所基于的核心库,已于2007年被放弃,这意味着代码库已经过时,错误百出,并且没有应用补丁的机制。因此,了解如何在不使用mcrypt
的情况下进行强加密/解密是非常重要的。
1.之前提出的问题的解决方案,如果你想知道,就是使用openssl
。这个扩展维护得很好,并且具有现代的、非常强大的加密/解密功能。
为了使用任何openssl*
函数,openssl PHP扩展必须被编译并启用!此外,你需要在你的Web服务器上安装最新的OpenSSL
包。
2. 首先,你需要确定你的安装中哪些密码方法是可用的。为此,您可以使用 openssl_get_cipher_methods()
命令。例子包括基于高级加密标准(AES)、BlowFish(BF)、CAMELLIA、CAST5、数据加密标准(DES)、Rivest密码(RC)(也被亲切地称为Ron's Code)和SEED的算法。你会注意到,这个方法显示的密码方法是大写和小写重复的。
3. 接下来,你需要弄清楚哪种方法最适合你的需求。下面是一个表格,对各种方法进行了快速的总结。
4. 另一个考虑因素是你喜欢的块密码操作模式是什么。常见的选择总结在这个表中。
5. 在选择加密方法和模式之前,你还需要确定加密的内容是否需要在你的PHP应用之外解密。例如,如果你是将数据库凭证加密存储到一个独立的文本文件中,你是否需要具备从命令行解密的能力?如果是这样,请确保你选择的加密方法和操作模式是目标操作系统所支持的。
6. 为IV提供的字节数根据选择的密码方法而变化。为了得到最好的结果,可以使用 random_bytes()
(PHP 7 中新增),它返回一个真正的 CSPRNG 字节序列。IV的长度有很大的不同。试着从16开始。如果产生警告,将显示该算法所需提供的正确字节数,因此要相应调整大小。
7. 要执行加密,使用openssl_encrypt()
。以下是需要传递的参数。
8. 举个例子,假设你想选择AES加密方式,密钥大小为256,XTS模式。下面是用于加密的代码。
9. 要解密,对$key
和$iv
使用相同的值,以及openssl_decrypt()
函数。
为了查看可用的密码方法,创建一个名为chap_12_openssl_encryption.php
的PHP脚本,然后运行这个命令。
输出应该是这样的。
接下来,可以为要加密的纯文本、方法、密钥和IV添加值。举个例子,试试使用XTS操作模式下的AES,密钥大小为256。
要加密,你可以使用openssl_encrypt()
,指定之前配置的参数。
你可能还想对结果进行base64编码,以使其更加可用。
解密时,使用相同的$key
和$iv
值。不要忘了先解密base64值。
这里的输出显示的是base64编码的密码文本,然后是解密后的明文。
如果你为IV提供的字节数不正确,对于所选择的密码方法,将显示一条警告信息。
在 PHP 7 中,当使用 open_ssl_encrypt()
和 open_ssl_decrypt()
以及所支持的认证数据加密 (AEAD) 模式时出现了一个问题——GCM 和 CCM。因此,在 PHP 7.1 中,这些函数增加了三个额外的参数,如下所示。
更多信息,您可以参考https://wiki.php.net/rfc/openssl_aead。
关于为什么在 PHP 7.1 中取消 mcrypt 扩展的优秀讨论,请参考 https://wiki.php.net/rfc/mcrypt-viking-funeral 的文章。关于构成各种加密方法基础的块加密的良好描述,请参考 https://en.wikipedia.org/wiki/Block_cipher 的文章。关于AES的优秀描述,请参考https://en.wikipedia.org/wiki/Advanced_Encryption_Standard。关于描述加密操作模式的优秀文章,可以参考https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation。
对于一些较新的模式,如果要加密的数据小于块大小,openssl_decrypt()
将不返回任何值。如果你把数据填充到至少是块大小,问题就会消失。大多数的模式都实现了内部填充,所以这不是问题。对于一些较新的模式(即xts),你可能会看到这个问题。在将你的代码投入生产之前,一定要对小于8个字符的短数据串进行测试。
方法
发布时间
密钥大小(bits)
密钥块大小 (bytes)
备注
camellia
2000
128, 192, 256
16
由三菱和NTT共同开发
aes
1998
128, 192, 256
16
由Joan Daemen和Vincent Rijmen开发。最初以Rijndael的名义提交
seed
1998
128
16
由韩国信息安全局开发
cast5
1996
40-128
8
由Carlisle Adams和Stafford Tavares开发
bf
1993
1 - 448
8
由Bruce Schneier设计
rc2
1987
8 - 1,024
默认 64
8
由Ron Rivest(RSA的核心创始人之一)设计
des
1977
56 (+8 奇偶校验位)
8
由IBM开发,基于Horst Feistel的工作
模式
代表
备注
ECB
Electronic Code Book
不需要初始化向量(IV);加密和解密都支持并行化;简单快速;不隐藏数据模式;不推荐!!!
CBC
Cipher Block Chaining
需要IV;后续的块,即使是相同的,也会与前一个块进行XOR编辑,从而获得更好的整体加密效果;如果IV是可预测的,第一个块可以被解密,剩下的信息就会暴露出来;信息必须被填充到密码块大小的倍数;只支持解密的并行化
CFB
Cipher Feedback
CBC的近亲,只是加密方式是反向的
OFB
Output Feedback
非常对称:加密和解密相同;完全不支持并行化
CTR
Counter
与OFB的操作类似;支持加密和解密的并行化
CCM
Counter with CBC-MAC
CTR的衍生物;仅设计为128位的块长;提供认证和保密性;CBC-MAC代表密码块链-信息认证码
GCM
Galois/Counter Mode
基于CTR模式;应该对每个流使用不同的IV进行加密;特别高的吞吐量(与其他模式相比);支持加密和解密的并行化
XTS
XEX-based Tweaked-codebook mode with ciphertext Stealing
相对较新(2010年)且速度较快;使用两把钥匙;增加了可作为一个区块安全加密的数据量
参数
备注
Data
纯文本你需要加密的内容
Method
你用openssl_get_cipher_methods()
确定的一个方法,确定如下。 方法 - key_size - cipher_mode 所以,举例来说,如果你想采用AES的方法,密钥大小为256,并采用GCM模式,你可以输入aes-256-gcm
。
Password
虽然这个参数被记录为密码,但它可以被看作是一个密钥。使用random_bytes()
来生成一个与所需密钥大小相匹配的字节数的密钥。
Options
在你获得更多openssl
加密经验之前,建议你坚持使用默认值0。
IV
使用random_bytes()
来生成一个具有与密码方法相匹配的字节数的IV。
参数
备注
$tag
通过引用传递的认证标签;如果认证失败,变量值保持不变。
$aad
额外的认证数据
$tag_length
GCM模式为4-16;CCM模式无限制;仅适用于open_ssl_encrypt()