You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP实现AES-256-CBC PKCS7对接.NET服务端加密失败排查

问题根因

你的PHP实现和官方JS示例存在多处逻辑不一致,是导致服务端返回公钥错误、加密校验失败的直接原因,核心问题如下:

  • DH公钥生成阶段使用base_convert转超大素数存在浮点数精度丢失,生成的本地公钥本身不符合规范
  • 共享密钥计算时存在变量名笔误,且GMP输出结果未补全前导零,导致共享密钥长度不足、内容错位
  • IV、AES密钥的截取长度、偏移完全不符合JS逻辑
  • 传入openssl的密钥、IV未做十六进制转二进制处理,和CryptoJS的解析逻辑不匹配
  • 传给服务端的本地公钥未做前导零补全,格式不符合服务端解析要求
逻辑对照(和官方JS实现对齐)

官方JS的加密参数规则:

  1. 计算得到DH共享密钥后,取前96个十六进制字符作为加密用的密钥基串
  2. IV取密钥基串前32个十六进制字符(对应16字节,符合AES-CBC的IV长度要求)
  3. AES密钥取密钥基串第32位开始的64个十六进制字符(对应32字节,符合AES-256的密钥长度要求)
  4. IV、密钥均为十六进制解析后的原始二进制字节,不是普通字符串
修正后可运行代码

常量定义与本地密钥对生成

// DH固定协议参数
private const DH_PRIME = 'F488FD584E49DBCD20B49DE49107366B336C380D451D0F7C88B31C7C5B2D8EF6F3C923C043F0A55B188D8EBB558CB85D38D334FD7C175743A31D186CDE33212CB52AFF3CE1B1294018118D7C84A70A72D686C40319C807297ACA950CD9969FABD00A509B0246D3083D66A45D419F9C7CBD894B221926BAABA25EC355E92F78C7';
private const DH_GENERATOR = '02';
private const DH_KEY_BYTE_LENGTH = 192; // DH素数对应的字节长度

// 初始化GMP参数
$prime = gmp_init(self::DH_PRIME, 16);
$generator = gmp_init(self::DH_GENERATOR, 16);

// 生成本地私钥(增加随机熵避免私钥重复)
$privateKey = gmp_init(uniqid(mt_rand(), true), 32);
// 计算本地公钥
$localPublicKey = gmp_powm($generator, $privateKey, $prime);
// 公钥补前导零到固定长度,转base64后传给服务端
$localPublicKeyBin = gmp_export($localPublicKey);
$localPublicKeyBin = str_pad($localPublicKeyBin, self::DH_KEY_BYTE_LENGTH, "\0", STR_PAD_LEFT);
$localPublicKeyBase64 = base64_encode($localPublicKeyBin);

共享密钥计算

// 解码服务端返回的base64格式公钥
$serverPublicKeyBin = base64_decode($apiResponse['response']['Command']['OutputParams']['Param']['7']['@attributes']['Value']);
$serverPublicKey = gmp_import($serverPublicKeyBin);

// 计算DH共享密钥
$sharedKey = gmp_powm($serverPublicKey, $privateKey, $prime);
// 共享密钥补前导零到固定长度,转十六进制字符串
$sharedKeyBin = gmp_export($sharedKey);
$sharedKeyBin = str_pad($sharedKeyBin, self::DH_KEY_BYTE_LENGTH, "\0", STR_PAD_LEFT);
$sharedKeyHex = bin2hex($sharedKeyBin);

加密参数提取与数据加密

// 对齐JS规则截取IV和密钥
$secretString = substr($sharedKeyHex, 0, 96);
$iv = hex2bin(substr($secretString, 0, 32));
$key = hex2bin(substr($secretString, 32, 64));

// AES-256-CBC加密,openssl默认使用PKCS7填充,无需额外配置
$cipher = 'AES-256-CBC';
$encryptedUsername = base64_encode(openssl_encrypt($username, $cipher, $key, OPENSSL_RAW_DATA, $iv));
$encryptedPassword = base64_encode(openssl_encrypt($password, $cipher, $key, OPENSSL_RAW_DATA, $iv));
注意事项
  • 不要使用base_convert转换超大整数,会因为浮点数精度丢失导致计算结果完全错误,所有DH大数运算直接通过GMP函数处理
  • 所有DH公钥、共享密钥转二进制后必须在左侧补\0到固定192字节长度,否则会因为前导零丢失导致密钥错位
  • 传给服务端的本地公钥必须是补零后二进制转base64的格式,不要直接传十六进制字符串

内容的提问来源于stack exchange,提问作者dual

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 20:57:13