C#生成XML的SHA256 HMAC与PHP验证结果不一致求助
问题排查与解决方案
哈希不一致的核心原因是C#和PHP处理的XML原始内容不匹配,以下是具体排查点和解决办法:
核心差异点分析
XML内容输出不一致
C#中XDocument.ToString()与document.Save()的输出存在本质区别:ToString()默认不输出XML声明(如<?xml version="1.0" encoding="utf-8"?>),且输出的是无缩进的紧凑格式Save()默认会输出XML声明,同时自动格式化XML(添加缩进、换行符)
而PHP读取的是Save()写入的文件内容,和C#哈希用的ToString()内容完全不同。
编码与BOM问题
XDocument.Save()默认使用带BOM的UTF-8编码写入文件,PHP读取时会包含BOM字节(EF BB BF)- C#中
Encoding.UTF8.GetBytes()生成的是无BOM的字节数组,哈希时不会包含BOM内容
解决方案
方案一:C#使用文件内容计算哈希
直接读取保存后的文件内容进行哈希,确保和PHP读取的是同一份数据:
// 先保存XML文件 document.Save(this.XMLFile); // 读取保存后的文件内容(指定UTF-8编码兼容带BOM的情况) string xmlContent = File.ReadAllText(this.XMLFile, Encoding.UTF8); // 计算HMACSHA256哈希 StringBuilder sha256_Sb = new StringBuilder(); var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes("SERVERHASH-SHA256")); byte[] hashBytes = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(xmlContent)); foreach(byte hash256 in hashBytes) { sha256_Sb.Append(hash256.ToString("x2")); } MessageBox.Show(sha256_Sb.ToString());
方案二:让C#生成与Save一致的XML字符串
如果不想读取文件,可配置XmlWriterSettings让ToString()输出和Save()完全一致的内容:
XmlWriterSettings settings = new XmlWriterSettings { OmitXmlDeclaration = false, // 强制输出XML声明 Indent = true, // 开启缩进匹配Save的格式化 Encoding = Encoding.UTF8 }; StringWriter sw = new StringWriter(); using (XmlWriter writer = XmlWriter.Create(sw, settings)) { document.WriteTo(writer); } string xmlContent = sw.ToString(); // 计算哈希(逻辑同方案一) StringBuilder sha256_Sb = new StringBuilder(); var hmacsha256 = new HMACSHA256(Encoding.UTF8.GetBytes("SERVERHASH-SHA256")); byte[] hashBytes = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(xmlContent)); foreach(byte hash256 in hashBytes) { sha256_Sb.Append(hash256.ToString("x2")); } MessageBox.Show(sha256_Sb.ToString());
PHP端简化调整
无需额外转码,直接读取原始文件内容即可:
$xml = file_get_contents('../files/workorders/y50onuv1_1702700056.xml'); $hash = hash_hmac("SHA256", $xml, "SERVERHASH-SHA256"); echo $hash;
验证步骤
- 分别在C#和PHP端输出处理内容的字节长度,确认长度一致
- 输出内容的十六进制表示,逐字节对比找到差异位置(若仍不一致)
内容的提问来源于stack exchange,提问作者Kyle
相关产品推荐
相关产品推荐

