PHP实现C# RSA SHA1签名功能求助(银行支付场景)
银行支付场景下C# RSA SHA1签名转PHP实现问题解决
原C#签名代码(ASCII编码RSA SHA1)
ASCIIEncoding ByteConverter = new ASCIIEncoding(); string dataString = "Data to Sign"; byte[] originalData = ByteConverter.GetBytes(dataString); byte[] signedData; RSACryptoServiceProvider RSAalg = new RSACryptoServiceProvider(); String PrivateKey= File.ReadAllText(Application.StartupPath + "\\PrivateKey.xml"); RSAalg.FromXmlString(PrivateKey); signedData = RSAalg.SignData(originalData,SHA1.Create()); // 注:原代码中Key应为RSAalg String base64String = Convert.ToBase64String(signedData, 0, signedData.Length);
尝试的PHP代码(签名失败)
$baseString = "Data to Sign"; $signedData = null; $privateKey = file_get_contents(config_path("PrivateKey.pem")); $privateKeyResource = openssl_pkey_get_private($privateKey); $signature = null; if (openssl_sign($baseString, $signedData, $privateKeyResource, OPENSSL_ALGO_SHA1)) $signature = base64_encode($signedData);
问题分析与修正方案
1. 密钥格式不匹配
C#使用XML格式私钥,而PHP的openssl扩展仅支持PEM格式密钥,这是核心问题之一。需先将XML私钥转换为PEM格式:
- 方法1:通过C#代码导出PEM私钥
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(); rsa.FromXmlString("你的XML私钥内容"); // 导出PKCS#1格式的PEM私钥 string pemPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\n" + Convert.ToBase64String(rsa.ExportRSAPrivateKey(), Base64FormattingOptions.InsertLineBreaks) + "\n-----END RSA PRIVATE KEY-----"; File.WriteAllText("PrivateKey.pem", pemPrivateKey); - 方法2:使用OpenSSL工具或离线转换工具完成格式转换
2. 数据编码不一致
C#用ASCIIEncoding.GetBytes()将字符串转成ASCII编码字节,PHP默认字符串编码多为UTF-8,需手动转换为ASCII确保字节一致:
$asciiData = mb_convert_encoding($baseString, 'ASCII');
3. 修正后的PHP代码
$originalData = "Data to Sign"; // 转换为ASCII编码,和C#逻辑对齐 $asciiData = mb_convert_encoding($originalData, 'ASCII'); // 读取转换后的PEM格式私钥 $privateKeyPath = config_path("PrivateKey.pem"); $privateKey = file_get_contents($privateKeyPath); // 若私钥设置了密码,需添加第二个参数:openssl_pkey_get_private($privateKey, "你的密码") $privateKeyResource = openssl_pkey_get_private($privateKey); $signedData = ''; $signature = ''; // 使用SHA1签名,默认PKCS#1 v1.5填充(与C# RSACryptoServiceProvider默认填充一致) if (openssl_sign($asciiData, $signedData, $privateKeyResource, OPENSSL_ALGO_SHA1)) { $signature = base64_encode($signedData); } else { // 打印错误信息用于排查 error_log(openssl_error_string()); } // 输出最终签名 echo $signature;
额外排查点
- 检查私钥是否完整,PEM格式的首尾标记(
-----BEGIN RSA PRIVATE KEY-----和-----END RSA PRIVATE KEY-----)是否正确 - 确认PHP环境已启用
openssl扩展 - 若签名仍失败,可通过
openssl_error_string()获取具体错误信息定位问题
内容的提问来源于stack exchange,提问作者masood jooibar
相关产品推荐
相关产品推荐

