2025-10-17 17:18:15 +08:00

227 lines
6.4 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace addons\shopro\library\ccblife;
/**
* 建行生活URL参数解密类
* 处理ccbParamSJ参数的DES解密
*/
class CcbUrlDecrypt
{
/**
* 解密建行URL参数ccbParamSJ
* 流程双层BASE64解码 -> DES解密
*
* @param string $ccbParamSJ 加密的参数字符串
* @param string $serviceId 服务ID用于生成DES密钥
* @return array|false 解密后的参数数组失败返回false
*/
public static function decrypt($ccbParamSJ, $serviceId)
{
try {
// 第一次BASE64解码
$firstDecode = base64_decode($ccbParamSJ);
if ($firstDecode === false) {
throw new \Exception('第一次BASE64解码失败');
}
// 第二次BASE64解码
$secondDecode = base64_decode($firstDecode);
if ($secondDecode === false) {
throw new \Exception('第二次BASE64解码失败');
}
// 获取DES密钥服务ID前8位
$desKey = substr($serviceId, 0, 8);
// DES解密
$decrypted = self::desDecrypt($secondDecode, $desKey);
if ($decrypted === false) {
throw new \Exception('DES解密失败');
}
// 解析参数字符串为数组
parse_str($decrypted, $params);
return $params;
} catch (\Exception $e) {
// 记录错误日志
trace('建行URL参数解密失败: ' . $e->getMessage(), 'error');
return false;
}
}
/**
* DES解密
* 使用ECB模式PKCS5Padding填充
*
* @param string $encryptedData 加密的数据
* @param string $key 密钥8字节
* @return string|false 解密后的数据失败返回false
*/
private static function desDecrypt($encryptedData, $key)
{
// 确保密钥长度为8字节
if (strlen($key) !== 8) {
return false;
}
// 使用openssl进行DES解密
$decrypted = openssl_decrypt(
$encryptedData,
'DES-ECB',
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
);
if ($decrypted === false) {
return false;
}
// 移除PKCS5填充
$decrypted = self::removePKCS5Padding($decrypted);
return $decrypted;
}
/**
* DES加密用于测试
* 使用ECB模式PKCS5Padding填充
*
* @param string $data 待加密的数据
* @param string $key 密钥8字节
* @return string|false 加密后的数据失败返回false
*/
public static function desEncrypt($data, $key)
{
// 确保密钥长度为8字节
if (strlen($key) !== 8) {
return false;
}
// 添加PKCS5填充
$data = self::addPKCS5Padding($data, 8);
// 使用openssl进行DES加密
$encrypted = openssl_encrypt(
$data,
'DES-ECB',
$key,
OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING
);
return $encrypted;
}
/**
* 生成建行URL参数ccbParamSJ用于测试
*
* @param array $params 参数数组
* @param string $serviceId 服务ID
* @return string 加密后的ccbParamSJ参数
*/
public static function encrypt($params, $serviceId)
{
// 将参数数组转换为查询字符串
$queryString = http_build_query($params);
// 获取DES密钥服务ID前8位
$desKey = substr($serviceId, 0, 8);
// DES加密
$encrypted = self::desEncrypt($queryString, $desKey);
// 双层BASE64编码
$firstEncode = base64_encode($encrypted);
$secondEncode = base64_encode($firstEncode);
return $secondEncode;
}
/**
* 添加PKCS5填充
*
* @param string $text 待填充的文本
* @param int $blocksize 块大小
* @return string 填充后的文本
*/
private static function addPKCS5Padding($text, $blocksize)
{
$pad = $blocksize - (strlen($text) % $blocksize);
return $text . str_repeat(chr($pad), $pad);
}
/**
* 移除PKCS5填充
*
* @param string $text 已填充的文本
* @return string 移除填充后的文本
*/
private static function removePKCS5Padding($text)
{
$pad = ord($text[strlen($text) - 1]);
if ($pad > strlen($text)) {
return false;
}
if (strspn($text, chr($pad), strlen($text) - $pad) != $pad) {
return false;
}
return substr($text, 0, -1 * $pad);
}
/**
* 解析建行跳转URL中的所有参数
* 处理URL中的ccbParamSJ和其他参数
*
* @param string $url 完整的URL或查询字符串
* @param string $serviceId 服务ID
* @return array 包含所有参数的数组
*/
public static function parseUrl($url, $serviceId)
{
// 解析URL获取查询参数
$urlParts = parse_url($url);
$queryString = isset($urlParts['query']) ? $urlParts['query'] : $url;
// 解析查询字符串
parse_str($queryString, $params);
// 如果存在ccbParamSJ参数进行解密
if (isset($params['ccbParamSJ']) && !empty($params['ccbParamSJ'])) {
$decryptedParams = self::decrypt($params['ccbParamSJ'], $serviceId);
if ($decryptedParams !== false) {
// 合并解密后的参数
$params = array_merge($params, $decryptedParams);
}
}
return $params;
}
/**
* 生成测试URL
* 用于生成包含加密参数的完整URL
*
* @param string $baseUrl 基础URL
* @param array $encryptedParams 需要加密的参数
* @param array $plainParams 明文参数
* @param string $serviceId 服务ID
* @return string 完整的URL
*/
public static function generateUrl($baseUrl, $encryptedParams, $plainParams, $serviceId)
{
// 加密参数
$ccbParamSJ = self::encrypt($encryptedParams, $serviceId);
// 合并所有参数
$allParams = array_merge($plainParams, ['ccbParamSJ' => $ccbParamSJ]);
// 构建查询字符串
$queryString = http_build_query($allParams);
// 拼接URL
$separator = strpos($baseUrl, '?') === false ? '?' : '&';
return $baseUrl . $separator . $queryString;
}
}