在php开发中,使用mcrypt相关函数可以很方便地进行AES加、解密操作,但是PHP7.1中废弃了mcrypt扩展,所以必需寻找另一种实现。在迁移手册中已经指出了用openssl代替mcrypt,但未给出具体示例。网上有很多示例,可以替换大部分场景,但对于其中细节却并未说明。同样,简单地使用网上示例在某种代码场景下有可能导致代码替换前后的兼容问题,以下则来谈谈具体代码及原因。

首先我们直接给出替换的代码,再从代码中分析问题。(本文中分析的算法是AES-128-CBC)

替换示例

示例会展示两种mcrypt的使用方式,主要在于填充不同(在下文会解释填充)。在整个加、解密过程中,完整程度高一点代码则会自主实现填充、移除填充,简单一点代码会直接忽略填充,但两种方式均可正常运行;在实际开发中(7.1之前版本),建议加上填充。请看如下具体示例:

mcrypt未使用填充

mcrypt加密:

$key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

$iv = 'aaaaaaaaaaaaaaaa';

$data = 'dataString';

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

mcrypt_generic_init($cipher, $key, $iv);

$cipherText256 = mcrypt_generic($cipher, $data);

mcrypt_generic_deinit($cipher);

return bin2hex($cipherText256);

相同功能的openssl加密代码:

$key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

$iv = 'aaaaaaaaaaaaaaaa';

$data = 'dataString';

$data = $data . str_repeat("\x00", 16 - (strlen($data) % 16)); // 双引号可以解析asc-ii码\x00

return bin2hex(openssl_encrypt($data, "AES-256-CBC", $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv));

mcrypt使用填充

mcrypt加密:

$key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

$iv = 'aaaaaaaaaaaaaaaa';

$data = 'dataString';

// 填充(移除填充反着移除即可)

$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

$pad = $block - (strlen($data) % $block);

if ($pad <= $block) {

$char = chr($pad);

$data .= str_repeat($char, $pad);

}

$cipher = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_CBC, '');

mcrypt_generic_init($cipher, $key, $iv);

$cipherText256 = mcrypt_generic($cipher, $data);

mcrypt_generic_deinit($cipher);

return bin2hex($cipherText256);

相同功能的openssl加密代码:

$key = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

$iv = 'aaaaaaaaaaaaaaaa';

$data = 'dataString';

return bin2hex(openssl_encrypt($data, 'AES-256-CBC', $key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $iv));

以上示例均可成功运行,其中第一个示例(未使用填充,但在openssl中进行了填充)和第二个示例(使用填充,在openssl中未使用填充)在替换前后输出相同,并无兼容问题。大家可以根据代码不同的填充方式来选择不同的替换方案,但其中有三个细节需要说明

为什么要有填充?

用openssl替换后算法的名称为何不同?

接下来会则会具体分析 填充 、算法。

填充

为什么有填充则要从加密的算法说起。因为在AES-128-CBC算法中,会把要加密的字符串以每16个byte的长度进行分段,逐步计算,由此导致不足16byte的段则会进行填充。所以给出的示例中会有两种:一种是使用默认的填充,另一种是自主填充。在与openssl的替换中,如何选择填充方案,则需要对mcrypt与openssl针对默认与自主填充有所了解。

mcrypt默认填充

在php的源码中,可以看出默认会以\x00进行填充,事实上,并非是以\x00进行填充,从源码中可以发现,首先申请了一个16位的空字符串,所以初始化时每位字节均为\x00, 实际上可以说其中并没有填充,只是它本来就是\x00 ,使用默认填充得到的加密字符串会是如下形式:

mcrypt默认填充

所以解密时则要移除多余的\x00。当然也可以懒一点,不移除\x00。 因为在php中字符串"string\x00"与字符串"string"除了长度不一样外,其他表现均一致,所以看起来并无区别,如下代码:

// 尾部包含若干个`\x00` 均可功输出true

if ("string\x00" == "string") { // 用双引号可解析\x00

echo true;

}

\x00填充后的示例:(请注意字符串的长度,由此可见用\x00填充会影响长度)

mcrypt自主填充

填充算法需以如下算法进行:

加入填充

/**

* 填充算法

* @param string $source

* @return string

*/

function addPKCS7Padding($source)

{

$source = trim($source);

$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);

$pad = $block - (strlen($source) % $block);

if ($pad <= $block) {

$char = chr($pad);

$source .= str_repeat($char, $pad);

}

return $source;

}

加入填充后字符串实际上如下形式:

移除填充

/**

* 移去填充算法

* @param string $source

* @return string

*/

function stripPKSC7Padding($source)

{

$source = trim($source);

$char = substr($source, -1);

$num = ord($char);

if ($num == 62) return $source;

$source = substr($source, 0, -$num);

return $source;

}

openssl默认填充

其默认方式与标准的mcrypt的自主填充方式一致,所以在第二个示例中,对于使用了如上的填充算法后, 可直接使用openssl_encrypt替换,不会产生兼容问题。填充后的加密字符串如下形式:

需注意的是在openssl_encrypt与openssl_decrypt中内置了填充与移除填充,所以直接使用即可,除非需自主实现填充,否则不需要考虑填充

openssl自主填充

openssl_encrypt提供了option参数以支持自主填充,但在查阅php源码中openssl的测试用例代码才找到正确用法:

// if we want to manage our own padding

$padded_data = $data . str_repeat(' ', 16 - (strlen($data) % 16));

$encrypted = openssl_encrypt($padded_data, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);

$output = openssl_decrypt($encrypted, $method, $password, OPENSSL_RAW_DATA|OPENSSL_ZERO_PADDING, $iv);

var_dump(rtrim($output));

(备注:如上,OPENSSL_ZERO_PADDING 并非是为0填充的意思)

由此,我们就可以解释,在第一个示例中openssl_encrypt之前加入了自主点充\x00的代码原因了

从以上的加、解密针对填充逻辑不同,针对上文中的示例可以很好地解释:

示例1:

mcrypt加密时未使用填充,故以\x00进行了填充,所以在替换成openssl,需要自主实现\x00填充。

示例2:

mcrypt加密时使用了标准的填充,同时openssl的填充方式也为标准填充,故直接使用即可。

分析到这,可以发现,无论是何种填充策略都需注意在加密时加入填充,在解密时则必须要移除填充。至此,上文中示例中的填充相关则分析完成了,接下来我们再看看如何选择替换后的算法。

选择算法

在以上的示例中,有一个问题在于,mcrypt中的AES-128-CBC算法,在openssl中怎么替换成了AES_256?

关于这一点, 我也未找到合理的解释,查看源码一时半会也没找到原因(能力有限~),但通过以下资料,还是完成了功能

若是有同学找到原因,欢迎给我留言,谢谢。

总结

对于使用mcrypt AES 进行加密密的部分,若是在替换过程中问题, 可以从算法替换或填充这两方面着手考虑下。同时还是一必须满足的条件是根据不同的填充方式选择, 替换最重要的就要考虑兼容问题,保证替换后不发生任何改变。 虽然只是只是有细微的差别----尾部几个字符串的不同,但若是在多平台中同时进行修改也是一件麻烦事,但变动越少风险越小。

本文只是针对AES算法进行了简单说明,对于其他算法是否适用还有待研究。

以上所述是小编给大家介绍的PHP7.1中使用openssl替换mcrypt的实例详解,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

mcrypt cbc php7,PHP7.1中使用openssl替换mcrypt的实例详解相关推荐

  1. php7.1.9 mcrypt,PHP7.1中使用openssl替换mcrypt

    PHP7.1中使用openssl替换mcrypt 在php开发中,使用mcrypt相关函数可以很方便地进行AES加.解密操作,但是PHP7.1中废弃了mcrypt扩展,所以必需寻找另一种实现.在迁移手 ...

  2. python中if语句的实例_对python中if语句的真假判断实例详解

    说明 在python中,if作为条件语句,当if后面的条件参数为真时,则执行后面的语句块,反之跳过,为了深入理解if语句,我们需要知道if语句的真假判断方式. 示例 在python交互器中,经过测试发 ...

  3. python中类的构成_Python中类型关系和继承关系实例详解

    本文详细介绍了Python中类型关系和继承关系.分享给大家供大家参考.具体分析如下: 如果一个对象A持有另一个对象B的ID,那么检索到A之后就可以检索到B,我们就说存在一个A到B的导航.这种导航关系使 ...

  4. java web初始化实例_Struts2中实现web应用的初始化实例详解

    Struts2中实现web应用的初始化实例详解 在JavsSE中,main方法为应用提供了入口,而在Android中,我们可以使用Application对于整个应用的生命周期进行管理,那么在基于Str ...

  5. props传递对象_vue组件中使用props传递数据的实例详解

    在 Vue 中,父子组件的关系可以总结为 props向下传递,事件向上传递.父组件通过 props 给子组件下发数据,子组件通过事件给父组件发送消息.看看它们是怎么工作的. 一.基本用法 组件不仅仅是 ...

  6. C#中WPF ListView绑定数据的实例详解

    C#中WPF ListView绑定数据的实例详解 发布时间: 2019-03-09 19:29:46 来源: 互联网 作者: 晨曦888 栏目: C#教程 点击: 298 这篇文章主要介绍了C#中WP ...

  7. Python中Print()函数的用法___实例详解(二)(全,例多)

    Python中Print()函数的用法___实例详解(二)(全,例多) 目录 十一.Print()小例子 十二.Print()中文输入显示乱码问题 十三.Print()写入文件 十四.print()在 ...

  8. mysql添加新的实例_MySQL中添加新用户权限的实例详解

    有2个不同的方法增加用户:通过使用GRANT语句或通过直接操作MySQL授权表.比较好的方法是使用GRANT语句,因为他们是更简明并且好像错误少些. 下面的例子显示出如何使用MySQL客户安装新用户. ...

  9. php request对象,PHP 中TP5 Request 请求对象的实例详解

    PHP 中TP5 Request 请求对象 public/index.php app\index\controller\Index.php <?php namespace app\index\c ...

最新文章

  1. Vmware 下安装Arch Linux
  2. C中常用字符串处理函数
  3. 如何画透明位图(转)
  4. SAP-SAP预制凭证相关的表
  5. show slave status\G中的Read_Master_Log_Pos和Relay_Log_Pos的(大小)关系
  6. python是面向过程的吗_Python开发是面向过程、函数还是对象?
  7. java jna调用dll文件_关于java jna调用dll的问题
  8. 【CODEVS2577】医院设置
  9. JAVA写的文件分割与文件合并程序
  10. Python入门学习笔记(5)
  11. fftw3 嵌入式linux安装,Ubuntu18.04下快速的安装UHD与GnuRadio并连接USRP设备
  12. linux内核配置选项
  13. 计算机插u盘的接口通常是,在计算机上插u盘的接口是什么标准接口
  14. 数据库——求候选键的方法
  15. 力扣LeetCode刷题8 机器人大冒险
  16. d3.js使用svg制作图标
  17. (二)Easyexcel 的使用(读取数据到map集合中)
  18. 010 | 古村楹联在道德教育及文学素养培养中的价值及启示 | 大学生创新训练项目申请书 | 极致技术工厂
  19. k、K、kb、kB、Kb、KB、GB、MB之间的关系
  20. 一目了然的 Node.js Windows10 安装篇

热门文章

  1. php 尾递归,又见尾递归
  2. linux声卡驱动arm,AM335x(TQ335x)学习笔记——WM8960声卡驱动移植
  3. 日语助词て的所有的语法点,请牢记
  4. Virgo与Maven整合开发环境搭建(四)
  5. Microsoft SQL Server 2008 R2 官方简体中文正式版下载(附激活序列号密钥)
  6. 软件工程复试——五、总体设计
  7. 第一章(简述数据清洗的基本流程)
  8. win10系统想下载win7系统自带的游戏——分享游戏压缩包
  9. 对一段信号用对称分量法matlab,《数字信号处理》课程设计题目
  10. Vive controller vibration