PHP7.2下Sagepay示例代码mcrypt转openssl的问题与解决
解决Sagepay PHP示例代码从mcrypt迁移到openssl的问题
我之前留意到Sagepay的官方PHP示例依赖已经被废弃的mcrypt扩展(PHP7.2及以上版本不再支持),在没收到官方回复的情况下,自己尝试把mcrypt调用替换成openssl,踩了不少坑后终于成功适配,分享一下过程和最终实现:
原mcrypt加密代码
Sagepay原本的加密逻辑是这样的:
$strIV = $strEncryptionPassword; //** add PKCS5 padding to the text to be encypted $strIn = addPKCS5Padding($strIn); //** perform encryption with PHP's MCRYPT module $strCrypt = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $strEncryptionPassword, $strIn, MCRYPT_MODE_CBC, $strIV);
踩坑的尝试过程
我一开始直接替换成openssl调用,但不管是启用OPENSSL_NO_PADDING,还是切换AES_192_CBC/AES_256_CBC模式,生成的加密串都和mcrypt版本的不一致(原mcrypt版本是通过Sagepay验证过的):
$strIV = $strEncryptionPassword; $strCrypt = openssl_encrypt($strIn,'AES-128-CBC',$strIV,$options=OPENSSL_RAW_DATA); //** perform hex encoding and return return "@" . bin2hex($strCrypt);
成功的openssl替代实现
经过反复调试,我找到了和原逻辑完全兼容的参数组合,以下是替换后的加密和解密函数:
加密函数:NEWencryptAndEncode
define('SESS_CIPHER','AES-128-CBC'); function NEWencryptAndEncode($strIn) { global $strEncryptionType ,$strEncryptionPassword; if ($strEncryptionType=="XOR") { //** XOR encryption with Base64 encoding ** return base64Encode(simpleXor($strIn,$strEncryptionPassword)); } else { //** AES encryption, CBC blocking with PKCS5 padding then HEX encoding - DEFAULT ** //** use initialization vector (IV) set from $strEncryptionPassword $strIV = $strEncryptionPassword; //** add PKCS5 padding to the text to be encypted $strIn = addPKCS5Padding($strIn); //** perform encryption with PHP's Openssl module $strCrypt = openssl_encrypt($strIn, SESS_CIPHER,$strIV,$options=OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,$strIV); //** perform hex encoding and return return "@" . bin2hex($strCrypt); } }
解密函数:NEWdecodeAndDecrypt
function NEWdecodeAndDecrypt($strIn) { global $strEncryptionPassword; if (substr($strIn,0,1)=="@") { //** HEX decoding then AES decryption, CBC blocking with PKCS5 padding - DEFAULT ** //** use initialization vector (IV) set from $strEncryptionPassword $strIV = $strEncryptionPassword; //** remove the first char which is @ to flag this is AES encrypted $strIn = substr($strIn,1); //** HEX decoding $strIn = pack('H*', $strIn); //** perform decryption with PHP's Openssl module return openssl_decrypt($strIn, SESS_CIPHER,$strIV,$options=OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING,$strIV); } else { //** Base 64 decoding plus XOR decryption ** return simpleXor(base64Decode($strIn),$strEncryptionPassword); } }
关键适配要点
- 保留原逻辑的PKCS5 padding预处理,同时在openssl调用时指定
OPENSSL_ZERO_PADDING,避免openssl自动添加其他格式的padding导致结果不一致 - 加密和解密都显式传入IV参数(和原mcrypt逻辑一致,使用加密密码作为IV)
- 启用
OPENSSL_RAW_DATA确保输出为原始二进制数据,再进行hex编码,和原流程完全对齐
内容的提问来源于stack exchange,提问作者brian read
相关产品推荐
相关产品推荐

