手机版

PHP7.1中用openssl替换mcrypt的详细说明

时间:2021-08-31 来源:互联网 编辑:宝哥软件园 浏览:

在php开发中,使用mcrypt相关函数可以轻松进行AES加解密,但在PHP7.1中放弃了mcrypt扩展,需要另寻实现。在迁移手册中,已经指出用openssl替换mcrypt,但是没有给出具体的例子。网上有很多例子,可以代替大部分场景,但细节没有说明。同样,在特定的代码场景中,简单地使用在线示例可能会导致代码替换前后的兼容性问题。我们来说说具体的代码和原因。

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

替代示例

该示例显示了使用mcrypt的两种方式,主要是因为填充不同(填充将在后面解释)。在整个加解密过程中,完整性较高的代码会独立实现填充和去填充,而完整性较简单的代码会直接忽略填充,但两种方式都能正常运行;在实际开发中(7.1版之前),建议添加填充。请参见以下具体示例:

Mcrypt不使用填充

Mcrypt加密:

$ key=' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ';$ iv=' aaaaaaaaaaaaaa ';$ data=' dataString$ cipher=MCRYPT _ module _ open(MCRYPT _ RIJNDAEL _ 128 ' ',MCRYPT _ MODE _ CBC ' ');mcrypt_generic_init($cipher,$key,$ iv);$ cipher text 256=MC rypt _ generic($ cipher,$ data);MC rypt _ generic _ definit($ cipher);返回bin2 hex($密文256);具有相同功能的Openssl加密代码:

$ key=' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ';$ iv=' aaaaaaaaaaaaaa ';$ data=' dataString$data=$data。str_repeat('\x00 ',16-(strlen($ data)% 16));//双引号可以解析ascii-ii代码\ x00 return bin2 hex(OpenSSL _ encrypt($ data,' AES-256-CBC ',$ key,OpenSSL _ raw _ data | OpenSSL _ zero _ padding,$ iv));Mcrypt使用填充

Mcrypt加密:

$ key=' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ';$ iv=' aaaaaaaaaaaaaa ';$ data=' dataString//Fill(改为移除填充)$ block=mcrypt _ get _ block _ size(mcrypt _ Rijndael _ 128,mcrypt _ mode _ CBC);$ pad=$ block-(strlen($ data)% $ block);if($ pad=$ block){ $ char=chr($ pad);$数据。=str_repeat($char,$ pad);} $ cipher=MCRYPT _ module _ open(MCRYPT _ RIJNDAEL _ 128 ' ',MCRYPT _ MODE _ CBC ' ');mcrypt_generic_init($cipher,$key,$ iv);$ cipher text 256=MC rypt _ generic($ cipher,$ data);MC rypt _ generic _ definit($ cipher);返回bin2 hex($密文256);具有相同功能的Openssl加密代码:

$ key=' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ';$ iv=' aaaaaaaaaaaaaa ';$ data=' dataString返回bin2hex(openssl_encrypt($data,' AES-256-CBC ',$key,OPENSSL _ RAW _ DATA | OPENSSL _ ZERO _ PADDING,$ iv));以上例子都能成功运行,第一个例子(没有使用填充,但是在openssl中填充)和第二个例子(使用填充,但是在openssl中没有使用填充)替换前后输出相同,不存在兼容性问题。您可以根据代码的不同填充方法选择不同的替代方案,但有三个细节需要说明

为什么要有填充物?

为什么用openssl替换后算法的名字不一样?接下来,将详细分析填充和算法。

填充物

为什么有填充从加密算法开始。因为在AES-128-CBC算法中,待加密的字符串会每隔16个字节进行分段并逐级计算,导致填充的段数少于16个字节。因此,给出了两种示例:一种是使用默认填充,另一种是独立填充。在用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自填充

填充算法需要以下算法:

添加填充

/* * * $ block=MCRYPT _ get _ block _ size(MCRYPT _ RIJNDAEL _ 128,MCRYPT _ MODE _ CBC);$ pad=$ block-(strlen($ source)% $ block);if($ pad=$ block){ $ char=chr($ pad);$来源。=str_repeat($char,$ pad);}返回$ source}添加填充后,字符串实际上采用以下形式:

移除填充

/* * *移除填充算法* @ param string $ source * @ return string */function strip KSC 7 padding($ source){ $ source=trim($ source);$char=substr($source,-1);$ num=order($ char);if ($num==62)返回$ source$source=substr($source,0,-$ num);返回$ source}openssl默认填充

其默认模式与标准的mcrypt自填充模式一致,所以在第二个例子中,使用上述填充算法后,可以直接使用openssl_encrypt来代替,不会出现兼容性问题。填充后的加密字符串的形式如下:

需要注意的是,填充和移除填充内置在openssl_encrypt和openssl_decrypt中,所以可以直接使用,除非需要独立实现,否则不需要填充。

Openssl自填充

Openssl_encrypt提供了支持自填充的选项参数,但是:的正确用法只能通过查阅php源代码中Openssl的测试用例代码才能找到

//如果我们想管理自己的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替代?对此我也找不到合理的解释。查了一会源代码也找不到原因(能力有限~),不过我已经通过以下信息完成了功能

openssl解密加密AES数据的不兼容性

将mcrypt_generic转换为openssl_encrypt询问问题

如果有同学发现原因,请给我留言,谢谢。

摘要

对于mcrypt AES加密的部分,如果替换过程中出现问题,可以从算法替换或者填充两个方面考虑。同时,必须满足的一个条件是根据不同的填充方式进行选择。更换最重要的是考虑兼容性,确保更换后不会发生变化。虽然只有细微的区别——末尾几个字符串的区别,但是在多个平台同时修改比较麻烦,但是改动越少风险越小。

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

以上是边肖介绍的PHP7.1中用openssl替换mcrypt的例子的详细说明。希望对大家有帮助。如果你有任何问题,请给我留言,边肖会及时回复你。非常感谢您对我们网站的支持!

版权声明:PHP7.1中用openssl替换mcrypt的详细说明是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。