生成支付串

This commit is contained in:
Billy 2025-10-27 14:20:37 +08:00
parent 1b725587e8
commit 80f2cdd84a
3 changed files with 31 additions and 39 deletions

View File

@ -74,39 +74,7 @@ return [
* 📌 注意: 需要将此公钥提交给建行进行配置 * 📌 注意: 需要将此公钥提交给建行进行配置
* 📌 如果已上架建行生活并同步公钥可以不再上送ENCPUB * 📌 如果已上架建行生活并同步公钥可以不再上送ENCPUB
*/ */
'merchant_public_key' => $envVars['merchant_public_key'] ?? ($envVars['public_key'] ?? ''), 'merchant_public_key' => $envVars['merchant_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'] ?? '',
// HTTP请求配置 // HTTP请求配置
'http' => [ 'http' => [

View File

@ -485,7 +485,12 @@ class CcbPaymentService
/** /**
* 格式化公钥为PEM格式 * 格式化公钥为PEM格式
* *
* @param string $publicKey BASE64或PEM格式的公钥 * 支持三种输入格式:
* 1. PEM格式已包含BEGIN/END标记
* 2. BASE64格式不含PEM头尾
* 3. 十六进制格式DER编码的十六进制字符串
*
* @param string $publicKey 公钥PEM/BASE64/HEX格式
* @return string PEM格式的公钥 * @return string PEM格式的公钥
*/ */
private function formatPublicKeyToPem($publicKey) private function formatPublicKeyToPem($publicKey)
@ -498,6 +503,16 @@ class CcbPaymentService
return $publicKey; 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格式
$pem = "-----BEGIN PUBLIC KEY-----\n"; $pem = "-----BEGIN PUBLIC KEY-----\n";
$pem .= rtrim(chunk_split($publicKey, 64, "\n"), "\n") . "\n"; $pem .= rtrim(chunk_split($publicKey, 64, "\n"), "\n") . "\n";
@ -747,11 +762,11 @@ class CcbPaymentService
} }
// 2. 检查是否配置了建行支付验签公钥 // 2. 检查是否配置了建行支付验签公钥
$ccbVerifyPublicKey = $this->config['ccb_payment_verify_public_key'] ?? ''; $ccbVerifyPublicKey = $this->config['public_key'] ?? '';
if (empty($ccbVerifyPublicKey)) { if (empty($ccbVerifyPublicKey)) {
// 降级方案: 未配置验签公钥时,使用POSID验证 // 降级方案: 未配置验签公钥时,使用POSID验证
Log::warning('[建行验签] 未配置ccb_payment_verify_public_key,使用降级验证方案'); Log::warning('[建行验签] 未配置public_key,使用降级验证方案');
// 验证POSID是否匹配 // 验证POSID是否匹配
if (($params['POSID'] ?? '') !== $this->config['pos_id']) { if (($params['POSID'] ?? '') !== $this->config['pos_id']) {

View File

@ -46,7 +46,10 @@ class CcbRSA
$encrypted .= $encryptedBlock; $encrypted .= $encryptedBlock;
} }
openssl_free_key($pubKey); // PHP 8+ 资源自动释放
if (PHP_VERSION_ID < 80000) {
openssl_free_key($pubKey);
}
// 返回BASE64编码的结果 // 返回BASE64编码的结果
return base64_encode($encrypted); return base64_encode($encrypted);
@ -92,7 +95,10 @@ class CcbRSA
$decrypted .= $decryptedBlock; $decrypted .= $decryptedBlock;
} }
openssl_free_key($priKey); // PHP 8+ 资源自动释放
if (PHP_VERSION_ID < 80000) {
openssl_free_key($priKey);
}
return $decrypted; return $decrypted;
} }
@ -272,7 +278,10 @@ class CcbRSA
// 使用公钥验签SHA256算法 // 使用公钥验签SHA256算法
$result = openssl_verify($data, $signatureBinary, $pubKey, OPENSSL_ALGO_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) { if ($result === 1) {
return true; // 验签成功 return true; // 验签成功