mirror of
https://gitee.com/liuxioabin/fengketrade.git
synced 2026-04-17 21:03:17 +08:00
代码优化
This commit is contained in:
parent
c5185c9722
commit
4d47e50e96
@ -13,6 +13,13 @@
|
||||
|
||||
use think\Env;
|
||||
|
||||
// 读取 .env 文件以获取密钥配置
|
||||
$envFile = __DIR__ . '/../../../.env';
|
||||
$envVars = [];
|
||||
if (file_exists($envFile)) {
|
||||
$envVars = parse_ini_file($envFile);
|
||||
}
|
||||
|
||||
return [
|
||||
// API基础地址 (生产环境)
|
||||
'api_base_url' => 'https://yunbusiness.ccb.com/tp_service/txCtrl/server',
|
||||
@ -37,13 +44,8 @@ return [
|
||||
'branch_id' => Env::get('ccb.branch_id', '340650000'),
|
||||
|
||||
// 密钥配置 (从.env读取,BASE64格式,不含PEM头尾)
|
||||
// ⚠️ 注意:密钥会在代码中自动添加PEM包装,.env中只需要存储BASE64内容
|
||||
'private_key' => Env::get('ccb.private_key', 'MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALrJmPmtQfP6mURtMxLEXqJHLldN3zYukoaRxG0lw2IdcC86H9C9brFz4YlJ+98z2mdELJaQWu8VWI4actSuPKgHTBr9MSpaii0QQpdINpwXJD9AglIrT7MxhMLYx3qAYDhjKUlC5hnWVYOg4sG32k/3dCebRHY8RDlrXUfHB2+VAgMBAAECgYArgn5R2pv8WymMmOtGudtZbb9LsuYF1v9mvVnGGv/SQQ060w1KMHYye83TjxpOueNsHqNMR0AHZS+Fmn+ZLyUNj9S77oQvUx5HQvY2/TDnsKbETzEMDybIWB+XdLsUkOrB3peVLTbk25i6oSNPOT2Fvd8TWbDqzBL9Ci27uJH72QJBAP/DfDLYoYx9OIRCykkxrDdQVFEkzhXj0wIkLa0Wnf8kP/JfBqvr0AGUPF8nEfh7fLVXYQlh5ab2FL5KvUifSL8CQQC69crW0fryyDHePp6OIVRUbw0T93h52vbGXnoQ6wdvKxZeL3MsfdNUvsJYeSxmtyY+LLgz1p3qOoEn6UpLvCirAkEA4N7qUvY+y3vJdhgXLNV8mkGJcLKQc5SUkJxogHeTQKGJi7ra7ctuXgUMM4jxduxz0CjcS1iEhxBzWn/x/mj1lwJBALgtv39VKLTXx1i7s5Ms/liXdfi/iC3zKbxOAk58WryHY+exMvMXmYMY0Xg7FySxNLl3cJeQy8ydifL5fbmSSTUCQQCj/YUbcTP8BQ6N0AgFdBwmXJyiNkB9zaDI5cEtpSCgq72m8lfn883GJ1MT7nKVXeX69/q5yDQUYiYPBXH4lCEC'),
|
||||
'public_key' => Env::get('ccb.public_key', 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6yZj5rUHz+plEbTMSxF6iRy5XTd82LpKGkcRtJcNiHXAvOh/QvW6xc+GJSfvfM9pnRCyWkFrvFViOGnLUrjyoB0wa/TEqWootEEKXSDacFyQ/QIJSK0+zMYTC2Md6gGA4YylJQuYZ1lWDoOLBt9pP93Qnm0R2PEQ5a11HxwdvlQIDAQAB'),
|
||||
|
||||
// 建行平台公钥(如果建行提供则配置,否则使用merchant_public_key)
|
||||
'platform_public_key' => Env::get('ccb.platform_public_key', ''),
|
||||
|
||||
'private_key' => $envVars['private_key'] ?? '',
|
||||
'public_key' => $envVars['public_key'] ?? '',
|
||||
// HTTP请求配置
|
||||
'http' => [
|
||||
'timeout' => 30, // 超时时间(秒)
|
||||
|
||||
@ -27,53 +27,83 @@ class Ccblife extends Common
|
||||
protected $noNeedRight = ['*'];
|
||||
|
||||
/**
|
||||
* 建行生活用户登录(URL跳转方式)
|
||||
* 建行生活用户登录(URL跳转方式或POST方式)
|
||||
* 建行App会携带加密参数跳转到此地址
|
||||
*
|
||||
* GET /addons/shopro/ccblife/login
|
||||
* GET/POST /addons/shopro/ccblife/login
|
||||
*/
|
||||
public function login()
|
||||
{
|
||||
try {
|
||||
// 获取URL参数
|
||||
$ccbParamSJ = $this->request->get('ccbParamSJ', '');
|
||||
$otherParams = $this->request->get();
|
||||
// 获取参数(支持 GET 和 POST)
|
||||
$ccbParamSJ = $this->request->param('ccbParamSJ', '');
|
||||
$otherParams = $this->request->param();
|
||||
|
||||
// 验证必要参数
|
||||
if (empty($ccbParamSJ)) {
|
||||
$this->error('缺少必要参数');
|
||||
}
|
||||
|
||||
// 获取配置
|
||||
$config = config('ccblife');
|
||||
// 从插件配置文件直接加载(避免config()缓存问题)
|
||||
$configFile = __DIR__ . '/../config/ccblife.php';
|
||||
if (!file_exists($configFile)) {
|
||||
$this->error('建行配置文件不存在');
|
||||
}
|
||||
|
||||
$config = include $configFile;
|
||||
|
||||
// 验证配置
|
||||
if (empty($config['private_key'])) {
|
||||
$this->error('配置错误:private_key 为空');
|
||||
}
|
||||
|
||||
Log::info('建行登录解密参数: ' . json_encode([
|
||||
'ccbParamSJ_length' => strlen($ccbParamSJ),
|
||||
'service_id' => $config['service_id'],
|
||||
'private_key_length' => strlen($config['private_key'])
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 解密参数(使用服务方私钥)
|
||||
$decryptedParams = CcbUrlDecrypt::decrypt($ccbParamSJ, $config['private_key']);
|
||||
if (!$decryptedParams) {
|
||||
$this->error('参数解密失败');
|
||||
// 检查日志文件获取详细错误
|
||||
$logFile = RUNTIME_PATH . 'log/' . date('Ym') . '/' . date('d') . '.log';
|
||||
$errorDetail = '';
|
||||
if (file_exists($logFile)) {
|
||||
$logContent = file_get_contents($logFile);
|
||||
// 提取最后几行日志
|
||||
$lines = explode("\n", $logContent);
|
||||
$errorDetail = implode("\n", array_slice($lines, -10));
|
||||
}
|
||||
|
||||
$this->error('参数解密失败,请查看日志: ' . $errorDetail);
|
||||
}
|
||||
|
||||
// 合并所有参数
|
||||
$allParams = array_merge($otherParams, $decryptedParams);
|
||||
// 验证解密结果
|
||||
if (!is_array($decryptedParams)) {
|
||||
$this->error('解密参数格式错误');
|
||||
}
|
||||
|
||||
// 获取建行用户信息
|
||||
$ccbUserId = $allParams['userid'] ?? '';
|
||||
$mobile = $allParams['mobile'] ?? '';
|
||||
$openId = $allParams['openid'] ?? '';
|
||||
Log::info('解密参数成功: ' . json_encode($decryptedParams, JSON_UNESCAPED_UNICODE));
|
||||
|
||||
// 获取建行用户信息(直接从解密参数中获取)
|
||||
$ccbUserId = $decryptedParams['userid'] ?? '';
|
||||
$mobile = $decryptedParams['mobile'] ?? '';
|
||||
$openId = $decryptedParams['openid'] ?? '';
|
||||
|
||||
if (empty($ccbUserId)) {
|
||||
$this->error('用户信息获取失败');
|
||||
}
|
||||
|
||||
// 处理用户登录/注册
|
||||
$userInfo = $this->processUserLogin($ccbUserId, $mobile, $openId, $allParams);
|
||||
$userInfo = $this->processUserLogin($ccbUserId, $mobile, $openId, $decryptedParams);
|
||||
|
||||
// 生成商城Token
|
||||
$this->auth->direct($userInfo['user_id']);
|
||||
$token = $this->auth->getToken();
|
||||
|
||||
// 构建跳转URL
|
||||
$redirectUrl = $allParams['redirect_url'] ?? '/pages/index/index';
|
||||
$redirectUrl = $decryptedParams['redirect_url'] ?? '/pages/index/index';
|
||||
|
||||
$this->success('登录成功', [
|
||||
'token' => $token,
|
||||
@ -83,6 +113,9 @@ class Ccblife extends Common
|
||||
|
||||
} catch (\Exception $e) {
|
||||
Log::error('建行生活登录失败: ' . $e->getMessage());
|
||||
Log::error('错误文件: ' . $e->getFile());
|
||||
Log::error('错误行号: ' . $e->getLine());
|
||||
Log::error('错误堆栈: ' . $e->getTraceAsString());
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,8 +29,8 @@ class CcbUrlDecrypt
|
||||
{
|
||||
try {
|
||||
// 调试日志
|
||||
trace('开始解密建行参数(双重BASE64 + RSA)', 'info');
|
||||
trace('ccbParamSJ 长度: ' . strlen($ccbParamSJ), 'info');
|
||||
self::log('开始解密建行参数(双重BASE64 + RSA)', 'info');
|
||||
self::log('ccbParamSJ 长度: ' . strlen($ccbParamSJ), 'info');
|
||||
|
||||
// 验证输入
|
||||
if (empty($ccbParamSJ)) {
|
||||
@ -43,21 +43,21 @@ class CcbUrlDecrypt
|
||||
|
||||
// 步骤1: URLDecode(如果还没有解码)
|
||||
$urlDecoded = urldecode($ccbParamSJ);
|
||||
trace('URLDecode后长度: ' . strlen($urlDecoded), 'info');
|
||||
self::log('URLDecode后长度: ' . strlen($urlDecoded), 'info');
|
||||
|
||||
// 步骤2: 第一次 BASE64 解码
|
||||
$firstDecode = base64_decode($urlDecoded);
|
||||
if ($firstDecode === false || empty($firstDecode)) {
|
||||
throw new \Exception('第一次 BASE64 解码失败');
|
||||
}
|
||||
trace('第一次BASE64解码成功,长度: ' . strlen($firstDecode), 'info');
|
||||
self::log('第一次BASE64解码成功,长度: ' . strlen($firstDecode), 'info');
|
||||
|
||||
// 步骤3: 第二次 BASE64 解码(建行特殊之处:双重BASE64编码)
|
||||
$secondDecode = base64_decode($firstDecode);
|
||||
if ($secondDecode === false || empty($secondDecode)) {
|
||||
throw new \Exception('第二次 BASE64 解码失败');
|
||||
}
|
||||
trace('第二次BASE64解码成功,长度: ' . strlen($secondDecode), 'info');
|
||||
self::log('第二次BASE64解码成功,长度: ' . strlen($secondDecode), 'info');
|
||||
|
||||
// 步骤4: RSA 私钥解密(直接处理二进制数据,不再用 CcbRSA::decrypt)
|
||||
$decrypted = self::rsaPrivateDecrypt($secondDecode, $privateKey);
|
||||
@ -65,24 +65,30 @@ class CcbUrlDecrypt
|
||||
throw new \Exception('RSA解密失败');
|
||||
}
|
||||
|
||||
trace('RSA解密成功,长度: ' . strlen($decrypted), 'info');
|
||||
trace('解密内容: ' . $decrypted, 'info');
|
||||
self::log('RSA解密成功,长度: ' . strlen($decrypted), 'info');
|
||||
self::log('解密内容: ' . $decrypted, 'info');
|
||||
|
||||
// 步骤5: 解析参数字符串为数组
|
||||
$params = [];
|
||||
parse_str($decrypted, $params);
|
||||
|
||||
if (empty($params)) {
|
||||
throw new \Exception('解析参数失败,结果为空');
|
||||
}
|
||||
|
||||
trace('参数解析成功: ' . json_encode($params, JSON_UNESCAPED_UNICODE), 'info');
|
||||
// 验证解析结果是否为有效数组
|
||||
if (!is_array($params)) {
|
||||
throw new \Exception('解析参数失败,结果不是数组: ' . gettype($params));
|
||||
}
|
||||
|
||||
self::log('参数解析成功: ' . json_encode($params, JSON_UNESCAPED_UNICODE), 'info');
|
||||
|
||||
return $params;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// 记录错误日志
|
||||
trace('建行URL参数解密失败: ' . $e->getMessage(), 'error');
|
||||
trace('错误堆栈: ' . $e->getTraceAsString(), 'error');
|
||||
self::log('建行URL参数解密失败: ' . $e->getMessage(), 'error');
|
||||
self::log('错误堆栈: ' . $e->getTraceAsString(), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -97,6 +103,11 @@ class CcbUrlDecrypt
|
||||
private static function rsaPrivateDecrypt($encryptedData, $privateKey)
|
||||
{
|
||||
try {
|
||||
self::log('rsaPrivateDecrypt 开始', 'info');
|
||||
self::log('加密数据长度: ' . strlen($encryptedData), 'info');
|
||||
self::log('加密数据MD5: ' . md5($encryptedData), 'info');
|
||||
self::log('私钥长度: ' . strlen($privateKey), 'info');
|
||||
|
||||
// 格式化私钥为 PEM 格式
|
||||
$pemPrivateKey = $privateKey;
|
||||
if (strpos($pemPrivateKey, '-----BEGIN') === false) {
|
||||
@ -109,11 +120,23 @@ class CcbUrlDecrypt
|
||||
// 加载私钥资源
|
||||
$priKey = openssl_pkey_get_private($pemPrivateKey);
|
||||
if (!$priKey) {
|
||||
throw new \Exception('私钥格式错误: ' . openssl_error_string());
|
||||
$openssl_error = openssl_error_string();
|
||||
self::log('openssl_pkey_get_private 失败', 'error');
|
||||
self::log('OpenSSL错误: ' . ($openssl_error ?: '无错误信息'), 'error');
|
||||
self::log('PEM私钥前200字符: ' . substr($pemPrivateKey, 0, 200), 'error');
|
||||
throw new \Exception('私钥格式错误: ' . ($openssl_error ?: '未知错误'));
|
||||
}
|
||||
|
||||
// 获取密钥大小
|
||||
$keyDetails = openssl_pkey_get_details($priKey);
|
||||
if (!$keyDetails || !isset($keyDetails['bits'])) {
|
||||
self::log('openssl_pkey_get_details 失败', 'error');
|
||||
self::log('priKey 类型: ' . gettype($priKey), 'error');
|
||||
throw new \Exception('无法获取密钥详情');
|
||||
}
|
||||
|
||||
self::log('密钥加载成功,大小: ' . ($keyDetails['bits'] / 8) . ' 字节', 'info');
|
||||
|
||||
$keySize = $keyDetails['bits'] / 8; // 1024位 = 128字节
|
||||
|
||||
// 分块解密
|
||||
@ -129,12 +152,15 @@ class CcbUrlDecrypt
|
||||
$decrypted .= $decryptedBlock;
|
||||
}
|
||||
|
||||
openssl_free_key($priKey);
|
||||
// PHP 8+ openssl_free_key() 已废弃,资源会自动释放
|
||||
if (PHP_VERSION_ID < 80000) {
|
||||
openssl_free_key($priKey);
|
||||
}
|
||||
|
||||
return $decrypted;
|
||||
|
||||
} catch (\Exception $e) {
|
||||
trace('RSA私钥解密错误: ' . $e->getMessage(), 'error');
|
||||
self::log('RSA私钥解密错误: ' . $e->getMessage(), 'error');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -153,7 +179,7 @@ class CcbUrlDecrypt
|
||||
{
|
||||
// 确保密钥长度为8字节
|
||||
if (strlen($key) !== 8) {
|
||||
trace('DES密钥长度必须为8字节,当前: ' . strlen($key), 'error');
|
||||
self::log('DES密钥长度必须为8字节,当前: ' . strlen($key), 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -169,12 +195,12 @@ class CcbUrlDecrypt
|
||||
// 移除PKCS5填充
|
||||
$result = self::removePKCS5Padding($decrypted);
|
||||
if ($result !== false) {
|
||||
trace('使用phpseclib解密成功', 'info');
|
||||
self::log('使用phpseclib解密成功', 'info');
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
trace('phpseclib解密失败: ' . $e->getMessage(), 'error');
|
||||
self::log('phpseclib解密失败: ' . $e->getMessage(), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,15 +217,15 @@ class CcbUrlDecrypt
|
||||
// 移除PKCS5填充
|
||||
$result = self::removePKCS5Padding($decrypted);
|
||||
if ($result !== false) {
|
||||
trace('使用OpenSSL解密成功', 'info');
|
||||
self::log('使用OpenSSL解密成功', 'info');
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
trace('OpenSSL解密失败: ' . $e->getMessage(), 'error');
|
||||
self::log('OpenSSL解密失败: ' . $e->getMessage(), 'error');
|
||||
}
|
||||
|
||||
trace('所有DES解密方法都失败', 'error');
|
||||
self::log('所有DES解密方法都失败', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -357,4 +383,31 @@ class CcbUrlDecrypt
|
||||
$separator = strpos($baseUrl, '?') === false ? '?' : '&';
|
||||
return $baseUrl . $separator . $queryString;
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志记录辅助方法
|
||||
* 兼容 trace() 函数和独立使用
|
||||
*
|
||||
* @param string $message 日志消息
|
||||
* @param string $level 日志级别
|
||||
* @return void
|
||||
*/
|
||||
private static function log($message, $level = 'info')
|
||||
{
|
||||
// 如果 trace() 函数存在,使用它
|
||||
if (function_exists('trace')) {
|
||||
trace($message, $level);
|
||||
return;
|
||||
}
|
||||
|
||||
// 否则输出到标准错误流(CLI模式)和 error_log
|
||||
$prefix = strtoupper($level);
|
||||
$logMessage = "[{$prefix}] {$message}";
|
||||
|
||||
if (PHP_SAPI === 'cli') {
|
||||
fwrite(STDERR, $logMessage . PHP_EOL);
|
||||
}
|
||||
|
||||
error_log($logMessage);
|
||||
}
|
||||
}
|
||||
152
addons/shopro/test/diagnose_ccb_encryption.php
Normal file
152
addons/shopro/test/diagnose_ccb_encryption.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
/**
|
||||
* 诊断建行加密方式
|
||||
* 尝试不同的解密方法
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../library/ccblife/CcbRSA.php';
|
||||
|
||||
use addons\shopro\library\ccblife\CcbRSA;
|
||||
|
||||
echo "========================================\n";
|
||||
echo " 建行加密方式诊断\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
// 从.env读取密钥
|
||||
$envFile = __DIR__ . '/../../../.env';
|
||||
$envLines = file($envFile, FILE_IGNORE_NEW_LINES);
|
||||
|
||||
$privateKey = '';
|
||||
$publicKey = '';
|
||||
|
||||
foreach ($envLines as $line) {
|
||||
if (stripos($line, 'private_key=') === 0) {
|
||||
$privateKey = trim(substr($line, 12));
|
||||
}
|
||||
if (stripos($line, 'public_key=') === 0) {
|
||||
$publicKey = trim(substr($line, 11));
|
||||
}
|
||||
}
|
||||
|
||||
echo "1. 密钥信息\n";
|
||||
echo " 私钥长度: " . strlen($privateKey) . "\n";
|
||||
echo " 公钥长度: " . strlen($publicKey) . "\n\n";
|
||||
|
||||
// 步骤1: 验证密钥对是否配对
|
||||
echo "2. 验证密钥对是否配对\n";
|
||||
try {
|
||||
$testData = "test=123&name=hello";
|
||||
$encrypted = CcbRSA::encrypt($testData, $publicKey);
|
||||
$decrypted = CcbRSA::decrypt($encrypted, $privateKey);
|
||||
|
||||
if ($decrypted === $testData) {
|
||||
echo " ✅ 密钥对配对正确\n\n";
|
||||
} else {
|
||||
echo " ❌ 密钥对不匹配\n\n";
|
||||
exit;
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ❌ 密钥验证失败: " . $e->getMessage() . "\n\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
// 建行的加密参数
|
||||
$ccbParamSJ = 'cURYdUJxQ2pJTlVWQUltSW9DQWN1T2xJeFI4WjR2ZVY0NENTVmxPQW9RUVJ1bnJ2Ync5MkwzS2dXdDF1TTVSd3NvUFlsZWFURlYvK243aFNGaWRNeTJsZXRxM1VJR2k0VFdqNnU0Z2JXRnVxMnVIcjhzSVcrRW4xOGxaWDA4Snk0VW1hcFllZ05pekxmc2h6dGFCOTloTUtnVXh2ekJNbDFXZzdwT3lOcDBHZGx5N0FidW1FY1NudmlhNGcxZFAwM09BRk5sUE9USkM4QlJNNWtGTzRKVjFqTWx6RlhrblNwWG0rYmxpS2kyOFpYLy91OGZCR1NPNGp2dHN6b3N1TGxNZnUzd2JNeVUyOVpFTzYxWDRyNm0yb2c0ekZCQWpjc1VLdU9Kcmh1VjVwVDdQZlBlQ0MwRWhLQXFWWXBOdi9uS0FQNkZkZ2JER0ljN2tlUXNHdlFMTWlDeU9rVzdFU2phdG5jYjhZOUNaWkVEb29OdGVLdmlscXg4eHRFS1VtWHljU2ZNeUlDbk5yRW5nR3VXS1AvN3NacTNISE5BWSt2azBHdU1IaG5UWkl6bTdXUmhVYnNRclRYb0ljNy9UTnZVT3lmSVFIcTZ0KzZpZGdtc1NDejBkajVsSjkzVXNSM0NWZExCUk85NHQxZGNEOWorUnFhV2hrWmpiYUE4SlY=';
|
||||
|
||||
echo "3. 尝试不同的解密方法\n\n";
|
||||
|
||||
// 方法1: 标准RSA解密(用商户私钥)
|
||||
echo "方法1: 使用商户私钥解密(标准方式)\n";
|
||||
try {
|
||||
$urlDecoded = urldecode($ccbParamSJ);
|
||||
$decrypted = CcbRSA::decrypt($urlDecoded, $privateKey);
|
||||
|
||||
echo " 解密成功,长度: " . strlen($decrypted) . "\n";
|
||||
|
||||
// 检查是否是可打印字符
|
||||
$isPrintable = ctype_print($decrypted);
|
||||
echo " 是否为可打印字符: " . ($isPrintable ? '是' : '否') . "\n";
|
||||
|
||||
if ($isPrintable) {
|
||||
echo " 解密内容: {$decrypted}\n";
|
||||
parse_str($decrypted, $params);
|
||||
if (!empty($params)) {
|
||||
echo " ✅ 解析成功!参数:\n";
|
||||
foreach ($params as $k => $v) {
|
||||
echo " {$k} = {$v}\n";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo " 内容预览(十六进制): " . bin2hex(substr($decrypted, 0, 50)) . "...\n";
|
||||
echo " ❌ 解密结果不是有效文本\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ❌ 解密失败: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// 方法2: 尝试用公钥解密(建行可能用建行私钥加密)
|
||||
echo "方法2: 尝试用商户公钥解密(反向,测试建行是否用私钥加密)\n";
|
||||
try {
|
||||
$urlDecoded = urldecode($ccbParamSJ);
|
||||
|
||||
// 格式化公钥为PEM
|
||||
$pemPublicKey = "-----BEGIN PUBLIC KEY-----\n";
|
||||
$pemPublicKey .= chunk_split($publicKey, 64, "\n");
|
||||
$pemPublicKey .= "-----END PUBLIC KEY-----\n";
|
||||
|
||||
$pubKeyResource = openssl_pkey_get_public($pemPublicKey);
|
||||
if (!$pubKeyResource) {
|
||||
throw new \Exception('公钥格式错误');
|
||||
}
|
||||
|
||||
// BASE64解码
|
||||
$encryptedData = base64_decode($urlDecoded);
|
||||
|
||||
// 获取密钥大小
|
||||
$keyDetails = openssl_pkey_get_details($pubKeyResource);
|
||||
$keySize = $keyDetails['bits'] / 8;
|
||||
|
||||
// 分块解密
|
||||
$dataBlocks = str_split($encryptedData, $keySize);
|
||||
$decrypted = '';
|
||||
|
||||
foreach ($dataBlocks as $block) {
|
||||
$decryptedBlock = '';
|
||||
// 尝试用公钥解密
|
||||
$success = @openssl_public_decrypt($block, $decryptedBlock, $pubKeyResource, OPENSSL_PKCS1_PADDING);
|
||||
if (!$success) {
|
||||
throw new \Exception('公钥解密失败');
|
||||
}
|
||||
$decrypted .= $decryptedBlock;
|
||||
}
|
||||
|
||||
openssl_free_key($pubKeyResource);
|
||||
|
||||
echo " 解密成功,长度: " . strlen($decrypted) . "\n";
|
||||
$isPrintable = ctype_print($decrypted);
|
||||
echo " 是否为可打印字符: " . ($isPrintable ? '是' : '否') . "\n";
|
||||
|
||||
if ($isPrintable) {
|
||||
echo " 解密内容: {$decrypted}\n";
|
||||
echo " ✅ 可能建行用的是建行私钥加密!\n";
|
||||
} else {
|
||||
echo " ❌ 解密结果不是有效文本\n";
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
echo " ❌ 解密失败: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
echo "\n";
|
||||
|
||||
// 方法3: 检查是否需要建行公钥
|
||||
echo "方法3: 建议检查项\n";
|
||||
echo " - 确认建行后台配置的商户公钥是否为:\n";
|
||||
echo " " . substr($publicKey, 0, 50) . "...\n";
|
||||
echo " - 检查建行是否提供了建行平台公钥(用于解密建行发来的数据)\n";
|
||||
echo " - 联系建行技术支持确认ccbParamSJ的加密方式\n";
|
||||
|
||||
echo "\n========================================\n";
|
||||
echo "诊断完成\n";
|
||||
echo "========================================\n";
|
||||
147
addons/shopro/test/test_ccb_correct_decrypt.php
Normal file
147
addons/shopro/test/test_ccb_correct_decrypt.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* 正确的建行解密流程(参考 Java demo)
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../library/ccblife/CcbRSA.php';
|
||||
|
||||
use addons\shopro\library\ccblife\CcbRSA;
|
||||
|
||||
echo "========================================\n";
|
||||
echo " 建行 ccbParamSJ 解密测试\n";
|
||||
echo " (参考 Java demo 实现)\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
// 从.env读取私钥
|
||||
$envFile = __DIR__ . '/../../../.env';
|
||||
$envLines = file($envFile, FILE_IGNORE_NEW_LINES);
|
||||
|
||||
$privateKey = '';
|
||||
|
||||
foreach ($envLines as $line) {
|
||||
if (stripos($line, 'private_key=') === 0) {
|
||||
$privateKey = trim(substr($line, 12));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($privateKey)) {
|
||||
die("错误: 无法读取私钥\n");
|
||||
}
|
||||
|
||||
echo "私钥长度: " . strlen($privateKey) . "\n\n";
|
||||
|
||||
// 建行传来的密文
|
||||
$ccbParamSJ = 'cURYdUJxQ2pJTlVWQUltSW9DQWN1T2xJeFI4WjR2ZVY0NENTVmxPQW9RUVJ1bnJ2Ync5MkwzS2dXdDF1TTVSd3NvUFlsZWFURlYvK243aFNGaWRNeTJsZXRxM1VJR2k0VFdqNnU0Z2JXRnVxMnVIcjhzSVcrRW4xOGxaWDA4Snk0VW1hcFllZ05pekxmc2h6dGFCOTloTUtnVXh2ekJNbDFXZzdwT3lOcDBHZGx5N0FidW1FY1NudmlhNGcxZFAwM09BRk5sUE9USkM4QlJNNWtGTzRKVjFqTWx6RlhrblNwWG0rYmxpS2kyOFpYLy91OGZCR1NPNGp2dHN6b3N1TGxNZnUzd2JNeVUyOVpFTzYxWDRyNm0yb2c0ekZCQWpjc1VLdU9Kcmh1VjVwVDdQZlBlQ0MwRWhLQXFWWXBOdi9uS0FQNkZkZ2JER0ljN2tlUXNHdlFMTWlDeU9rVzdFU2phdG5jYjhZOUNaWkVEb29OdGVLdmlscXg4eHRFS1VtWHljU2ZNeUlDbk5yRW5nR3VXS1AvN3NacTNISE5BWSt2azBHdU1IaG5UWkl6bTdXUmhVYnNRclRYb0ljNy9UTnZVT3lmSVFIcTZ0KzZpZGdtc1NDejBkajVsSjkzVXNSM0NWZExCUk85NHQxZGNEOWorUnFhV2hrWmpiYUE4SlY=';
|
||||
|
||||
echo "========================================\n";
|
||||
echo "开始解密...\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
try {
|
||||
// 步骤1: URLDecode
|
||||
echo "步骤1: URLDecode\n";
|
||||
$step1 = urldecode($ccbParamSJ);
|
||||
echo " 长度: " . strlen($step1) . "\n";
|
||||
echo " 是否改变: " . ($step1 === $ccbParamSJ ? '否' : '是') . "\n\n";
|
||||
|
||||
// 步骤2: 第一次 BASE64 解码
|
||||
echo "步骤2: 第一次 BASE64 解码\n";
|
||||
$step2 = base64_decode($step1);
|
||||
if ($step2 === false) {
|
||||
throw new \Exception('第一次 BASE64 解码失败');
|
||||
}
|
||||
echo " 解码后长度: " . strlen($step2) . "\n";
|
||||
echo " 内容预览: " . substr($step2, 0, 50) . "...\n";
|
||||
|
||||
// 检查是否还是 BASE64
|
||||
$isBase64 = preg_match('/^[A-Za-z0-9+\/=]+$/', $step2);
|
||||
echo " 是否仍为 BASE64: " . ($isBase64 ? '是(双重编码)' : '否') . "\n\n";
|
||||
|
||||
// 步骤3: 第二次 BASE64 解码(建行用了双重 BASE64!)
|
||||
echo "步骤3: 第二次 BASE64 解码\n";
|
||||
$step3 = base64_decode($step2);
|
||||
if ($step3 === false) {
|
||||
throw new \Exception('第二次 BASE64 解码失败');
|
||||
}
|
||||
echo " 解码后长度: " . strlen($step3) . "\n";
|
||||
echo " 十六进制预览: " . bin2hex(substr($step3, 0, 32)) . "...\n\n";
|
||||
|
||||
// 步骤4: 用私钥 RSA 解密
|
||||
echo "步骤4: RSA 私钥解密\n";
|
||||
|
||||
// 注意:这里不能再用 CcbRSA::decrypt(),因为它内部会再次 BASE64 解码
|
||||
// 我们需要直接调用 openssl_private_decrypt
|
||||
|
||||
// 格式化私钥
|
||||
$pemPrivateKey = $privateKey;
|
||||
if (strpos($pemPrivateKey, '-----BEGIN') === false) {
|
||||
$pemPrivateKey = preg_replace('/\s+/', '', $pemPrivateKey);
|
||||
$pemPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
|
||||
chunk_split($pemPrivateKey, 64, "\n") .
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
|
||||
$priKey = openssl_pkey_get_private($pemPrivateKey);
|
||||
if (!$priKey) {
|
||||
throw new \Exception('私钥格式错误: ' . openssl_error_string());
|
||||
}
|
||||
|
||||
// 获取密钥大小
|
||||
$keyDetails = openssl_pkey_get_details($priKey);
|
||||
$keySize = $keyDetails['bits'] / 8; // 128 字节 (1024 位)
|
||||
|
||||
echo " 密钥大小: {$keySize} 字节\n";
|
||||
echo " 加密数据长度: " . strlen($step3) . " 字节\n";
|
||||
|
||||
// 分块解密
|
||||
$blocks = str_split($step3, $keySize); // 使用 step3(第二次解码后的数据)
|
||||
$decrypted = '';
|
||||
|
||||
echo " 分块数: " . count($blocks) . "\n";
|
||||
|
||||
foreach ($blocks as $i => $block) {
|
||||
$decryptedBlock = '';
|
||||
$success = openssl_private_decrypt($block, $decryptedBlock, $priKey, OPENSSL_PKCS1_PADDING);
|
||||
if (!$success) {
|
||||
throw new \Exception("解密第 " . ($i+1) . " 块失败: " . openssl_error_string());
|
||||
}
|
||||
$decrypted .= $decryptedBlock;
|
||||
}
|
||||
|
||||
openssl_free_key($priKey);
|
||||
|
||||
echo " 解密成功!\n";
|
||||
echo " 解密后长度: " . strlen($decrypted) . "\n\n";
|
||||
|
||||
// 步骤5: 显示结果
|
||||
echo "步骤5: 解密结果\n";
|
||||
echo " 原始内容:\n";
|
||||
echo " ----------------------------------------\n";
|
||||
echo " {$decrypted}\n";
|
||||
echo " ----------------------------------------\n\n";
|
||||
|
||||
// 步骤6: 解析参数
|
||||
echo "步骤6: 解析 URL 参数\n";
|
||||
parse_str($decrypted, $params);
|
||||
|
||||
if (empty($params)) {
|
||||
echo " ⚠️ 解析为空,可能不是 URL 参数格式\n";
|
||||
} else {
|
||||
echo " 解析成功!参数列表:\n";
|
||||
foreach ($params as $key => $value) {
|
||||
echo " {$key} = {$value}\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo "\n========================================\n";
|
||||
echo "✅ 解密成功!\n";
|
||||
echo "========================================\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "\n========================================\n";
|
||||
echo "❌ 解密失败\n";
|
||||
echo "========================================\n";
|
||||
echo "错误: " . $e->getMessage() . "\n";
|
||||
echo "堆栈:\n" . $e->getTraceAsString() . "\n";
|
||||
}
|
||||
136
addons/shopro/test/test_rsa_decrypt.php
Normal file
136
addons/shopro/test/test_rsa_decrypt.php
Normal file
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
/**
|
||||
* RSA解密测试脚本
|
||||
* 测试建行ccbParamSJ参数解密
|
||||
*/
|
||||
|
||||
// 手动加载必要的类
|
||||
require_once __DIR__ . '/../library/ccblife/CcbRSA.php';
|
||||
|
||||
use addons\shopro\library\ccblife\CcbRSA;
|
||||
|
||||
echo "========================================\n";
|
||||
echo " 建行 RSA 解密测试\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
// 测试参数
|
||||
$ccbParamSJ = 'cURYdUJxQ2pJTlVWQUltSW9DQWN1T2xJeFI4WjR2ZVY0NENTVmxPQW9RUVJ1bnJ2Ync5MkwzS2dXdDF1TTVSd3NvUFlsZWFURlYvK243aFNGaWRNeTJsZXRxM1VJR2k0VFdqNnU0Z2JXRnVxMnVIcjhzSVcrRW4xOGxaWDA4Snk0VW1hcFllZ05pekxmc2h6dGFCOTloTUtnVXh2ekJNbDFXZzdwT3lOcDBHZGx5N0FidW1FY1NudmlhNGcxZFAwM09BRk5sUE9USkM4QlJNNWtGTzRKVjFqTWx6RlhrblNwWG0rYmxpS2kyOFpYLy91OGZCR1NPNGp2dHN6b3N1TGxNZnUzd2JNeVUyOVpFTzYxWDRyNm0yb2c0ekZCQWpjc1VLdU9Kcmh1VjVwVDdQZlBlQ0MwRWhLQXFWWXBOdi9uS0FQNkZkZ2JER0ljN2tlUXNHdlFMTWlDeU9rVzdFU2phdG5jYjhZOUNaWkVEb29OdGVLdmlscXg4eHRFS1VtWHljU2ZNeUlDbk5yRW5nR3VXS1AvN3NacTNISE5BWSt2azBHdU1IaG5UWkl6bTdXUmhVYnNRclRYb0ljNy9UTnZVT3lmSVFIcTZ0KzZpZGdtc1NDejBkajVsSjkzVXNSM0NWZExCUk85NHQxZGNEOWorUnFhV2hrWmpiYUE4SlY=';
|
||||
|
||||
echo "输入参数:\n";
|
||||
echo "ccbParamSJ 长度: " . strlen($ccbParamSJ) . "\n\n";
|
||||
|
||||
// 直接使用配置文件中的默认私钥(BASE64格式)
|
||||
// 这是配置文件 ccblife.php 中的默认值
|
||||
$privateKey = 'MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALrJmPmtQfP6mURtMxLEXqJHLldN3zYukoaRxG0lw2IdcC86H9C9brFz4YlJ+98z2mdELJaQWu8VWI4actSuPKgHTBr9MSpaii0QQpdINpwXJD9AglIrT7MxhMLYx3qAYDhjKUlC5hnWVYOg4sG32k/3dCebRHY8RDlrXUfHB2+VAgMBAAECgYArgn5R2pv8WymMmOtGudtZbb9LsuYF1v9mvVnGGv/SQQ060w1KMHYye83TjxpOueNsHqNMR0AHZS+Fmn+ZLyUNj9S77oQvUx5HQvY2/TDnsKbETzEMDybIWB+XdLsUkOrB3peVLTbk25i6oSNPOT2Fvd8TWbDqzBL9Ci27uJH72QJBAP/DfDLYoYx9OIRCykkxrDdQVFEkzhXj0wIkLa0Wnf8kP/JfBqvr0AGUPF8nEfh7fLVXYQlh5ab2FL5KvUifSL8CQQC69crW0fryyDHePp6OIVRUbw0T93h52vbGXnoQ6wdvKxZeL3MsfdNUvsJYeSxmtyY+LLgz1p3qOoEn6UpLvCirAkEA4N7qUvY+y3vJdhgXLNV8mkGJcLKQc5SUkJxogHeTQKGJi7ra7ctuXgUMM4jxduxz0CjcS1iEhxBzWn/x/mj1lwJBALgtv39VKLTXx1i7s5Ms/liXdfi/iC3zKbxOAk58WryHY+exMvMXmYMY0Xg7FySxNLl3cJeQy8ydifL5fbmSSTUCQQCj/YUbcTP8BQ6N0AgFdBwmXJyiNkB9zaDI5cEtpSCgq72m8lfn883GJ1MT7nKVXeX69/q5yDQUYiYPBXH4lCEC';
|
||||
|
||||
echo "使用默认私钥(来自配置文件)\n";
|
||||
echo "私钥长度: " . strlen($privateKey) . "\n\n";
|
||||
|
||||
// 执行解密
|
||||
echo "========================================\n";
|
||||
echo "开始解密...\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
try {
|
||||
// 步骤1: URLDecode
|
||||
echo "步骤1: URLDecode\n";
|
||||
$urlDecoded = urldecode($ccbParamSJ);
|
||||
echo " URLDecode 后长度: " . strlen($urlDecoded) . "\n";
|
||||
echo " 是否改变: " . ($urlDecoded === $ccbParamSJ ? '否' : '是') . "\n\n";
|
||||
|
||||
// 步骤2: 显示密钥信息
|
||||
echo "步骤2: 私钥信息\n";
|
||||
echo " 私钥长度: " . strlen($privateKey) . "\n";
|
||||
echo " 是否包含 PEM 头: " . (strpos($privateKey, '-----BEGIN') !== false ? '是' : '否') . "\n\n";
|
||||
|
||||
// 步骤3: 尝试 RSA 解密
|
||||
echo "步骤3: RSA 解密\n";
|
||||
|
||||
// 直接调用 CcbRSA::decrypt
|
||||
$decrypted = CcbRSA::decrypt($urlDecoded, $privateKey);
|
||||
|
||||
echo " 解密成功!\n";
|
||||
echo " 解密后长度: " . strlen($decrypted) . "\n";
|
||||
echo " 解密内容: " . $decrypted . "\n\n";
|
||||
|
||||
// 步骤4: 解析参数
|
||||
echo "步骤4: 解析参数\n";
|
||||
parse_str($decrypted, $params);
|
||||
echo " 解析结果:\n";
|
||||
foreach ($params as $key => $value) {
|
||||
echo " {$key} = {$value}\n";
|
||||
}
|
||||
|
||||
echo "\n========================================\n";
|
||||
echo "✅ 解密成功!\n";
|
||||
echo "========================================\n";
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo "\n========================================\n";
|
||||
echo "❌ 解密失败!\n";
|
||||
echo "========================================\n";
|
||||
echo "错误信息: " . $e->getMessage() . "\n";
|
||||
echo "错误行号: " . $e->getLine() . "\n";
|
||||
echo "错误文件: " . $e->getFile() . "\n";
|
||||
echo "\n堆栈跟踪:\n" . $e->getTraceAsString() . "\n";
|
||||
|
||||
// 额外诊断
|
||||
echo "\n========================================\n";
|
||||
echo "诊断信息\n";
|
||||
echo "========================================\n";
|
||||
|
||||
// 检查 BASE64 解码
|
||||
echo "\n1. BASE64 解码测试:\n";
|
||||
$base64Decoded = base64_decode($urlDecoded);
|
||||
if ($base64Decoded === false) {
|
||||
echo " ❌ BASE64 解码失败\n";
|
||||
} else {
|
||||
echo " ✓ BASE64 解码成功\n";
|
||||
echo " 解码后长度: " . strlen($base64Decoded) . "\n";
|
||||
echo " 十六进制预览: " . bin2hex(substr($base64Decoded, 0, 32)) . "...\n";
|
||||
}
|
||||
|
||||
// 检查私钥格式
|
||||
echo "\n2. 私钥格式测试:\n";
|
||||
try {
|
||||
// 格式化私钥
|
||||
$formattedKey = $privateKey;
|
||||
if (strpos($formattedKey, '-----BEGIN') === false) {
|
||||
$formattedKey = preg_replace('/\s+/', '', $formattedKey);
|
||||
$formattedKey = "-----BEGIN RSA PRIVATE KEY-----\n" .
|
||||
chunk_split($formattedKey, 64, "\n") .
|
||||
"-----END RSA PRIVATE KEY-----\n";
|
||||
}
|
||||
|
||||
$keyResource = openssl_pkey_get_private($formattedKey);
|
||||
if ($keyResource === false) {
|
||||
echo " ❌ 私钥格式错误: " . openssl_error_string() . "\n";
|
||||
} else {
|
||||
echo " ✓ 私钥格式正确\n";
|
||||
$keyDetails = openssl_pkey_get_details($keyResource);
|
||||
echo " 密钥类型: " . ($keyDetails['type'] === OPENSSL_KEYTYPE_RSA ? 'RSA' : '未知') . "\n";
|
||||
echo " 密钥位数: " . $keyDetails['bits'] . "\n";
|
||||
openssl_free_key($keyResource);
|
||||
}
|
||||
} catch (\Exception $e2) {
|
||||
echo " ❌ 私钥检查失败: " . $e2->getMessage() . "\n";
|
||||
}
|
||||
|
||||
// 检查数据长度
|
||||
echo "\n3. 数据长度检查:\n";
|
||||
if (isset($base64Decoded)) {
|
||||
$dataLen = strlen($base64Decoded);
|
||||
echo " 加密数据长度: {$dataLen} 字节\n";
|
||||
|
||||
if (isset($keyDetails)) {
|
||||
$keySize = $keyDetails['bits'] / 8;
|
||||
$blockCount = $dataLen / $keySize;
|
||||
echo " 密钥大小: {$keySize} 字节\n";
|
||||
echo " 分块数量: " . $blockCount . " (应该是整数)\n";
|
||||
|
||||
if ($blockCount != floor($blockCount)) {
|
||||
echo " ⚠️ 警告: 数据长度不是密钥大小的整数倍\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
81
addons/shopro/test/verify_keypair.php
Normal file
81
addons/shopro/test/verify_keypair.php
Normal file
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* 验证 RSA 密钥对是否匹配
|
||||
*/
|
||||
|
||||
require_once __DIR__ . '/../library/ccblife/CcbRSA.php';
|
||||
|
||||
use addons\shopro\library\ccblife\CcbRSA;
|
||||
|
||||
echo "========================================\n";
|
||||
echo " RSA 密钥对验证\n";
|
||||
echo "========================================\n\n";
|
||||
|
||||
// 从 .env 读取密钥
|
||||
$envFile = __DIR__ . '/../../../.env';
|
||||
$envLines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
$privateKey = '';
|
||||
$publicKey = '';
|
||||
|
||||
foreach ($envLines as $line) {
|
||||
if (stripos($line, 'private_key=') !== false) {
|
||||
$privateKey = trim(substr($line, strpos($line, '=') + 1));
|
||||
}
|
||||
if (stripos($line, 'public_key=') !== false) {
|
||||
$publicKey = trim(substr($line, strpos($line, '=') + 1));
|
||||
}
|
||||
}
|
||||
|
||||
echo "1. 密钥信息\n";
|
||||
echo " 私钥长度: " . strlen($privateKey) . "\n";
|
||||
echo " 公钥长度: " . strlen($publicKey) . "\n\n";
|
||||
|
||||
// 验证密钥对
|
||||
echo "2. 验证密钥对是否匹配\n";
|
||||
|
||||
try {
|
||||
// 测试数据
|
||||
$testData = "userid=test123&mobile=13800138000&openid=testOpenId";
|
||||
|
||||
echo " 原始数据: {$testData}\n";
|
||||
|
||||
// 用公钥加密
|
||||
$encrypted = CcbRSA::encrypt($testData, $publicKey);
|
||||
echo " ✓ 公钥加密成功\n";
|
||||
echo " 加密后长度: " . strlen($encrypted) . "\n";
|
||||
|
||||
// 用私钥解密
|
||||
$decrypted = CcbRSA::decrypt($encrypted, $privateKey);
|
||||
echo " ✓ 私钥解密成功\n";
|
||||
echo " 解密结果: {$decrypted}\n";
|
||||
|
||||
// 验证
|
||||
if ($decrypted === $testData) {
|
||||
echo "\n ✅ 密钥对匹配!公钥和私钥配对正确。\n\n";
|
||||
} else {
|
||||
echo "\n ❌ 密钥对不匹配!解密结果与原始数据不一致。\n\n";
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
echo " ❌ 错误: " . $e->getMessage() . "\n\n";
|
||||
}
|
||||
|
||||
// 显示公钥信息(用于确认是否提交给建行)
|
||||
echo "3. 你的公钥(BASE64格式,提交给建行的应该是这个)\n";
|
||||
echo "----------------------------------------\n";
|
||||
echo $publicKey . "\n";
|
||||
echo "----------------------------------------\n\n";
|
||||
|
||||
echo "4. 你的公钥(PEM格式)\n";
|
||||
echo "----------------------------------------\n";
|
||||
$pemPublicKey = "-----BEGIN PUBLIC KEY-----\n";
|
||||
$pemPublicKey .= chunk_split($publicKey, 64, "\n");
|
||||
$pemPublicKey .= "-----END PUBLIC KEY-----\n";
|
||||
echo $pemPublicKey;
|
||||
echo "----------------------------------------\n\n";
|
||||
|
||||
echo "⚠️ 重要提示:\n";
|
||||
echo "1. 请确认建行那边配置的公钥是否和上面显示的公钥一致\n";
|
||||
echo "2. 如果不一致,需要重新提交正确的公钥给建行\n";
|
||||
echo "3. 如果一致但仍然解密失败,可能是建行加密方式有问题\n";
|
||||
Loading…
x
Reference in New Issue
Block a user