diff --git a/addons/shopro/config/ccblife.php b/addons/shopro/config/ccblife.php index bdedf43..0741cdd 100644 --- a/addons/shopro/config/ccblife.php +++ b/addons/shopro/config/ccblife.php @@ -74,39 +74,7 @@ return [ * 📌 注意: 需要将此公钥提交给建行进行配置 * 📌 如果已上架建行生活并同步公钥,可以不再上送ENCPUB */ - 'merchant_public_key' => $envVars['merchant_public_key'] ?? ($envVars['public_key'] ?? ''), - - /** - * 建行平台API公钥 (建行生活平台提供的RSA公钥) - * 用途: - * - 加密API请求报文(A3341TP01/02/03/04等接口) - * - 只有建行用自己的私钥才能解密 - * 获取方式: 联系建行生活平台技术支持获取 - * 格式: BASE64格式(不含PEM头尾) 或 PEM格式(含头尾) - * - * ⚠️ 重要说明: - * 1. 如果未单独配置,将使用merchant_public_key(向下兼容) - * 2. 建行可能为每个商户分配统一密钥对,或要求使用建行平台公钥 - * 3. 请联系建行确认应使用哪个公钥进行API请求加密 - * - * 📋 RSA加密逻辑: - * - 商户用建行公钥加密请求 → 建行用建行私钥解密 - * - 商户用商户私钥签名 → 建行用商户公钥验签 - */ - 'ccb_platform_public_key' => $envVars['ccb_platform_public_key'] ?? ($envVars['public_key'] ?? ''), - - /** - * 建行生活支付验签公钥 (建行生活平台分配的) - * 用途: - * - 验证异步通知中的SIGN字段(NT_TYPE=YS时) - * 获取方式: 联系建行生活平台运营人员或技术支持 - * 格式: PEM格式RSA公钥(2048位) - * - * 📌 如果未配置此字段: - * - 异步通知验签会降级为POSID验证 - * - 安全性降低,建议尽快获取并配置 - */ - 'ccb_payment_verify_public_key' => $envVars['ccb_payment_verify_public_key'] ?? '', + 'merchant_public_key' => $envVars['merchant_public_key'] ?? '', // HTTP请求配置 'http' => [ diff --git a/addons/shopro/library/ccblife/CcbPaymentService.php b/addons/shopro/library/ccblife/CcbPaymentService.php index 3204447..016a8be 100644 --- a/addons/shopro/library/ccblife/CcbPaymentService.php +++ b/addons/shopro/library/ccblife/CcbPaymentService.php @@ -485,7 +485,12 @@ class CcbPaymentService /** * 格式化公钥为PEM格式 * - * @param string $publicKey BASE64或PEM格式的公钥 + * 支持三种输入格式: + * 1. PEM格式(已包含BEGIN/END标记) + * 2. BASE64格式(不含PEM头尾) + * 3. 十六进制格式(DER编码的十六进制字符串) + * + * @param string $publicKey 公钥(PEM/BASE64/HEX格式) * @return string PEM格式的公钥 */ private function formatPublicKeyToPem($publicKey) @@ -498,6 +503,16 @@ class CcbPaymentService return $publicKey; } + // ✅ 判断是否为十六进制格式(只包含0-9a-fA-F字符) + if (ctype_xdigit($publicKey)) { + // 十六进制格式 → 解码为二进制 → 转BASE64 + $binaryKey = hex2bin($publicKey); + if ($binaryKey === false) { + throw new \Exception('十六进制公钥解码失败'); + } + $publicKey = base64_encode($binaryKey); + } + // 转换为PEM格式 $pem = "-----BEGIN PUBLIC KEY-----\n"; $pem .= rtrim(chunk_split($publicKey, 64, "\n"), "\n") . "\n"; @@ -747,11 +762,11 @@ class CcbPaymentService } // 2. 检查是否配置了建行支付验签公钥 - $ccbVerifyPublicKey = $this->config['ccb_payment_verify_public_key'] ?? ''; + $ccbVerifyPublicKey = $this->config['public_key'] ?? ''; if (empty($ccbVerifyPublicKey)) { // 降级方案: 未配置验签公钥时,使用POSID验证 - Log::warning('[建行验签] 未配置ccb_payment_verify_public_key,使用降级验证方案'); + Log::warning('[建行验签] 未配置public_key,使用降级验证方案'); // 验证POSID是否匹配 if (($params['POSID'] ?? '') !== $this->config['pos_id']) { diff --git a/addons/shopro/library/ccblife/CcbRSA.php b/addons/shopro/library/ccblife/CcbRSA.php index a6c24a4..bf83389 100644 --- a/addons/shopro/library/ccblife/CcbRSA.php +++ b/addons/shopro/library/ccblife/CcbRSA.php @@ -46,7 +46,10 @@ class CcbRSA $encrypted .= $encryptedBlock; } - openssl_free_key($pubKey); + // PHP 8+ 资源自动释放 + if (PHP_VERSION_ID < 80000) { + openssl_free_key($pubKey); + } // 返回BASE64编码的结果 return base64_encode($encrypted); @@ -92,7 +95,10 @@ class CcbRSA $decrypted .= $decryptedBlock; } - openssl_free_key($priKey); + // PHP 8+ 资源自动释放 + if (PHP_VERSION_ID < 80000) { + openssl_free_key($priKey); + } return $decrypted; } @@ -272,7 +278,10 @@ class CcbRSA // 使用公钥验签(SHA256算法) $result = openssl_verify($data, $signatureBinary, $pubKey, OPENSSL_ALGO_SHA256); - openssl_free_key($pubKey); + // PHP 8+ 资源自动释放 + if (PHP_VERSION_ID < 80000) { + openssl_free_key($pubKey); + } if ($result === 1) { return true; // 验签成功