C#与Python实现HMACSHA256签名结果不一致问题求助
我在对接客户API时遇到了HMAC签名不匹配的问题:客户提供C#授权示例,我方用Python开发。已确认密钥字节数组和消息字节两端完全一致(Python的base64.b64decode(secretKey)与C#的Convert.FromBase64String(secretKey)结果相同),但签名计算结果却不一样。
C# 签名代码片段:
using (HMACSHA256 sha = new HMACSHA256(secretKeyByteArray)) { // Sign the request byte[] signatureBytes = sha.ComputeHash(signature); }
Python 签名代码片段:
signature_hmac = hmac.new( base64.b64decode(secretKey), bytes(message, "utf8"), digestmod=hashlib.sha256, )
可能的原因及排查方向
消息编码不匹配
Python中用bytes(message, "utf8")转换消息,但如果C#端的signature变量是通过Encoding.Unicode.GetBytes(message)(UTF-16编码)生成的字节数组,两端的消息字节会完全不同,直接导致签名差异。优先确认C#端消息的编码方式。消息内容的隐性差异
检查C#的signature参数是否经过额外处理:比如是否是URL编码后的字符串、是否包含隐藏的换行/空格、或是已经经过Base64编码的字节数组,而非原始消息的字节。这些细节都会让两端的输入消息本质不同。签名结果的取值/处理差异
Python的signature_hmac.digest()返回原始字节数组,和C#sha.ComputeHash()的返回值是直接对应的。但如果C#后续对签名做了Base64编码(比如Convert.ToBase64String(signatureBytes)),而你用Python的原始字节去对比,自然会不匹配;反之如果Python用了hexdigest(),也会和C#的原始字节不一致。极端情况:密钥的隐性处理
虽然你确认了Base64解码后的字节一致,但可以再验证一次:分别打印两端密钥字节的十六进制字符串(C#用BitConverter.ToString(secretKeyByteArray).Replace("-", ""),Python用base64.b64decode(secretKey).hex()),确保完全一致。
快速验证方法
找一段固定的测试消息和密钥,分别打印两端的消息字节和签名字节的十六进制字符串直接对比:
- C#获取消息十六进制:
BitConverter.ToString(signature).Replace("-", "") - Python获取消息十六进制:
message.encode('utf-8').hex() - 签名十六进制对比同理,C#用
BitConverter.ToString(signatureBytes).Replace("-", ""),Python用signature_hmac.digest().hex()
这样能快速定位是消息输入的问题,还是签名计算的问题。
内容的提问来源于stack exchange,提问作者Rohit

