可恶,被 PHP-Mcrypt 的官方 Example 误导了

在看 php 的 mcrypt 加密,想使用对称算法,解决小块内容(比如 url、post)网上传输的安全性。即加密、解密用同一个密码。[官方文档](http://cn.php.net/manual/en/function.mcrypt-module-open.php)有个非常完整的演示功能的例子,大概顺序是:

  • 打开 module
  • 生成 IV
  • 得到 key/密钥/密码
  • 初始化(引擎?)
  • 进行加密操作
  • 关闭(引擎?)
  • 重新初始化(引擎?)
  • 进行解密操作
  • 关闭(引擎?)
  • 关闭 module

加密、解密放在了一个代码片段中,大概是想说,加、解密就那一句代码不同而已。

按照这个理解,为了使用方便,我把加、解密分解成了2个函数,内容都和例子差不多,不会有错。但一运行,不管用哪种加密算法,都会出现奇怪的解密后与原文不一致的错误。还不是完全不一致,后面大半段内容都是正确的,比如原文是包含 a-z 26个字母的字符串,运行结果如下:

$ ./mcrypt.php 
Encrypt:
M~<5¶¤Jw^TÝ×. ÃV¯
Decrypt:
Âò¹ÁIijklmnopqrstuvwxyz

好一通找原因,最后在[支持算法列表页面](http://cn.php.net/manual/en/mcrypt.ciphers.php)中找到这么一句:The IV must be unique and must be the same when decrypting/encrypting.加、解密时所使用的 IV 必须相同。

昏,例子代码中 IV 是使用随机数生成的,分成2个函数之后,加、解密操作生成的 IV 肯定不一样,这就是解密失败的原因。[mcrypt_create_iv() 函数文档页面](http://cn.php.net/manual/en/function.mcrypt-create-iv.php)的 user notes 中有位 Chris 还对 IV 纠正了一些错误观点。

综上,正确解密需要将 IV 与密文一同存储、传递。而我的需求比较简单,就没有必要这么作,反正 IV 也不需要保密,所以直接用 key 的 sha1 值的片断,比如前8位(与 git 版本号简写类似)作为 IV,对安全性影响不大,应该是可以接受的。

问题解决,收工,有和我一样吃过亏的同学么?

6 thoughts on “可恶,被 PHP-Mcrypt 的官方 Example 误导了”

  1. iv其实是干扰因素,即使你随机生成iv,但只要key一致,就可以正确解密。

    生成iv: $iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);

    初始化(注意key要和解密时的key一致): mcrypt_generic_init($td, $key, $iv);

    1. 没错,引入IV的目的是让同一个原文几次加密后的密文不同, 但根据加密算法不同,有些算法解密是必须要IV的, 不然就会出现上面我说的解密后和原文不同的情况。

Leave a Reply

Your email address will not be published. Required fields are marked *