php:aes加密使用mcrypt_decrypt能解开,openssl_decrypt却解不开,what?

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/panjiapengfly/article/details/102756825

小编前几天在做一个数据加密的时候,发现php中的openssl_decrypt竟然解不开密文, 此景之下只好寻找答案,并总结下结果。

场景:

使用python加密的一个数据,方法如下:


#AES加密
def aes_encrypt(text, key, mode, iv):
	import base64
	cryptor = AES.new(key, mode, iv)
	length = 16
	count = len(text)
	if (count % length) != 0:
		add = length - (count % length)
	else:
		add = 0
	text = text + ('\0' * add)
	ciphertext = cryptor.encrypt(text)
	return base64.b64encode(ciphertext)


#AES解密
def aes_decrypt(text, key, mode, iv):
	cryptor = AES.new(key, mode, iv)
	plain_text = cryptor.decrypt(text)
	return plain_text.rstrip('\0').strip()


#测试
aes_key = '123456ABCD!@#$%^'
aes_iv  = '123456ABCD!@#$%^'
content = '0123456789123456'
aes_encrypt(content,aes_key, AES.MODE_CBC, aes_iv)#输出FSaxaPsYOrt063lkbocFnQ==

然后交给php使用openssl_decrypt解密,一直返回false,但是python解密是没问题的。苦恼之下,小编使用了php已经废弃的函数mcrypt_decrypt进行解密,发现可行,代码如下:

<?php

$aes_key = '123456ABCD!@#$%^';
$aes_iv  = '123456ABCD!@#$%^';
$content = "FSaxaPsYOrt063lkbocFnQ==";
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $aes_key, base64_decode($content), MCRYPT_MODE_CBC, $aes_iv);
echo rtrim($decrypted, "\0")."\n";//成功

$decrypted1 = openssl_decrypt($content, 'AES-128-CBC', $aes_key,0, $aes_iv);
echo rtrim($decrypted1, "\0")."\n";//失败

为什么mcrypt_decrypt能解开,openssl_decrypt却解不开?

后来小编研究了下,明白了,也顺便回答了下这位仁兄的问题(https://segmentfault.com/q/1010000012199406)。

其实归根结底是openssl_decrypt解密方式不对,options参数使用OPENSSL_ZERO_PADDING或者是2,就能解开。

<?php
$aes_key = '123456ABCD!@#$%^';
$aes_iv  = '123456ABCD!@#$%^';
$content = "FSaxaPsYOrt063lkbocFnQ==";
$decrypted1 = openssl_decrypt($content, 'AES-128-CBC', $aes_key,2, $aes_iv);
echo rtrim($decrypted1, "\0")."\n";//bingo

为什么呢?

因为在python加密的时候小编采用的是补0方式进行填充加密,但是在openssl_decrypt中options参数0和1都是默认采用PKCS7方式去填充的,所以解密失败,而参数为2时,则是采用去0方式解密的,刚好对应。

相关知识

openssl_encrypt($data, $method, $key, $options = 0, $iv = '') : 以指定方式 method 和密钥 key 加密 data, 返回 false 或加密后的数据.

  • data : 明文
  • method : 加密算法
  • key : 密钥
  • options :
    •  0 : 自动对明文进行 padding, 返回的数据经过 base64 编码.(默认PKCS7填充方式)
    • 1 : OPENSSL_RAW_DATA, 自动对明文进行 padding, 但返回的结果未经过 base64 编码.(默认PKCS7填充方式)
    • 2 : OPENSSL_ZERO_PADDING, 自动对明文进行 0 填充, 返回的结果经过 base64 编码. 但是, openssl 不推荐 0 填充的方式, 即使选择此项也不会自动进行 padding, 仍需手动 padding.
  • iv : 非空的初始化向量, 不使用此项会抛出一个警告. 如果未进行手动填充, 则返回加密失败.

参考文章:

三种填充模式的区别(PKCS7Padding/PKCS5Padding/ZeroPadding):

https://blog.csdn.net/panjiapengfly/article/details/102757763

PHP由mcrypt扩展加密改为openssl扩展加密:

https://www.xxling.com/blog/article/3114.aspx

https://www.cnblogs.com/z1298703836/p/9252612.html

猜你喜欢

转载自blog.csdn.net/panjiapengfly/article/details/102756825