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

PHP加密及hash_hmac('sha512')代码转C#实现求助

解决PHP到C#的HMAC-SHA512签名转换问题

我帮你梳理下PHP转C#签名代码里的问题,以及对应的修正方案——你的代码有几个关键细节和PHP的逻辑没对齐,导致签名结果不一致:

核心问题分析

  1. SHA256哈希输出格式错误:PHP中hash('sha256', $nonce . $postdata, true)返回的是原始二进制字节,但你的C#ComputeSha256Hash返回的是十六进制字符串,这直接改变了哈希的内容,后续HMAC计算必然出错。
  2. $hash的构造逻辑错误:PHP里的$hash是'/' + $method + 二进制SHA256结果的字节拼接,而你的代码是直接拼接路径字符串和十六进制哈希,完全偏离了原逻辑。
  3. 密钥处理错误:PHP用base64_decode($this->secret)得到二进制密钥,而你用Encoding.ASCII.GetBytes(client_secret)直接把base64字符串转成字节,这相当于把密钥的base64编码当作了明文密钥,和原逻辑不符。

修正后的完整C#代码

// 替换成你实际的base64格式密钥(对应PHP的$this->secret)
private readonly string _clientSecret = "你的Base64SecretHere";
// 替换成你实际的接口方法(对应PHP的$method)
private readonly string _method = "auth/register";

public string CalculateSignature(string nonce, string postData)
{
    // 1. 计算nonce + postData的SHA256原始二进制哈希
    byte[] sha256Bytes = ComputeSha256HashBytes(nonce + postData);
    
    // 2. 构造完整的hash字节序列:"/" + method + SHA256二进制结果
    string hashPrefix = "/" + _method;
    byte[] prefixBytes = Encoding.UTF8.GetBytes(hashPrefix);
    byte[] hashBytes = new byte[prefixBytes.Length + sha256Bytes.Length];
    
    // 拼接前缀字节和SHA256字节
    Buffer.BlockCopy(prefixBytes, 0, hashBytes, 0, prefixBytes.Length);
    Buffer.BlockCopy(sha256Bytes, 0, hashBytes, prefixBytes.Length, sha256Bytes.Length);
    
    // 3. 解码Base64格式的密钥(和PHP的base64_decode对齐)
    byte[] secretBytes = Convert.FromBase64String(_clientSecret);
    
    // 4. 计算HMAC-SHA512并Base64编码(和PHP逻辑完全一致)
    using (HMACSHA512 hmac = new HMACSHA512(secretBytes))
    {
        byte[] hmacBytes = hmac.ComputeHash(hashBytes);
        return Convert.ToBase64String(hmacBytes);
    }
}

// 返回SHA256的原始二进制字节,而非十六进制字符串
private static byte[] ComputeSha256HashBytes(string rawData)
{
    using (SHA256 sha256Hash = SHA256.Create())
    {
        return sha256Hash.ComputeHash(Encoding.UTF8.GetBytes(rawData));
    }
}

使用示例(匹配你提供的PHP示例数据)

string nonce = "123456789";
// 对应PHP中http_build_query($param, '', '&')的输出结果
string postData = "email=test@test.com&password=Password1234&customerId=1234";

string signature = CalculateSignature(nonce, postData);

关键修正说明

  • SHA256输出对齐:新的ComputeSha256HashBytes直接返回二进制字节,和PHP的hash(..., true)行为完全一致。
  • Hash字节拼接:不再拼接字符串,而是直接操作字节数组,确保和PHP中'/' . $method . 二进制哈希的字节序列完全相同。
  • 密钥解码正确:用Convert.FromBase64String解码密钥,和PHP的base64_decode逻辑一致,避免了ASCII编码的错误转换。
  • 编码一致性:全程使用UTF-8编码处理字符串转字节,和PHP的字符串字节流默认行为对齐(PHP字符串是字节序列,只要原始输入是UTF-8,就和C#的处理结果一致)。

你可以用相同的输入参数对比PHP和C#的签名结果,应该能得到完全一致的输出。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 10:12:48