将SHA256从Java转换为C#

我有一个简单的问题。 我需要将一个sha256校验和方法从java重写为C#

所以我有这个Java鳕鱼可以使用:

Canonicalizer c14Canonicalizer = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS); byte[] byteArray = c14Canonicalizer.canonicalizeSubtree(doc); // At this point, the byteArray in Java and the data in C# matches up. // That is, after the java bytes are converted to unsigned bytes using // java.lang.Byte.toUnsignedInt() MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(byteArray); byte byteData[] = md.digest(); 

(byteArray是,你猜对了,一个字节数组:D)

根据我的发现,update()和digest()方法应该基本上替代相应的HashAlgorithm派生类(在本例中为SHA256)中的TransformBlock()和TransformFinalBlock()方法。

所以我在C#中尝试过类似的东西:

 var data = Encoding.UTF8.GetBytes(xmlString); // At this point, the byteArray in Java and the data in C# matches up. // That is, after the java bytes are converted to unsigned bytes using // java.lang.Byte.toUnsignedInt() using (var sha256 = SHA256.Create()) { byte[] shaBytes = new byte[data.Length]; data.CopyTo(shaBytes, 0); sha256.TransformBlock(shaBytes, 0, shaBytes.Length, shaBytes, 0); sha256.TransformFinalBlock(shaBytes, 0, shaBytes.Length); return sha256.Hash; } 

(再次,数据是一个字节数组)

但是,字节不匹配。 我在这里错过了什么吗?

(当然,我是,否则它会工作,对吧?:S)

UPDATE

为了给你提供更多信息,我在运行你看到的代码之前匹配了Java和C#代码之间的字节。 然后他们匹配。 但是,C#代码中的字节来自UTF8-Encoded字符串,而Java字节来自c14Canonicalizer.canonicalizeSubtree()方法。

我将更新上面的代码示例以包含它们的起源。

UPDATE

为了它的价值,Java md.digest()方法返回以下字节:

-86,44,95,84,3,50,7,-119,-36,46,39,32,-120,7,10,-86,-101,110,-93,-72,-13 ,-93,-42,111,0,59,-85,-63,-15,-98,-17,-52

转换后转换为

170,44,95,84,3,50,7,137,220,46,39,32,136,7,10,170,155,110,163,184,243,163,214,111,0,59,171,193,241,158,239,204

而C#代码返回

72,108,14,47,15,200,209,10,68,87,17,220,67,226,162,123,69,186,130,167,239,250,180,178,75,101,39,195,32,171,156,178

使用sha256.ComputeHash()

你尝试过ComputeHash方法吗?

即:

 var byteArray = Encoding.ASCII.GetBytes("hello"); var sha = SHA256.Create(); byte[] outputBytes = sha.ComputeHash(byteArray); var result = BitConverter.ToString(outputBytes).Replace("-", "").ToLower(); 

编辑

你能试试吗?

 XmlDocument doc = new XmlDocument(); doc.LoadXml("xmlString"); XmlDsigExcC14NWithCommentsTransform c14n = new XmlDsigExcC14NWithCommentsTransform(); c14n.LoadInnerXml(doc.ChildNodes); Stream s = (Stream)c14n.GetOutput(typeof(Stream)); var sha = SHA256.Create(); byte[] outputBytes = sha.ComputeHash(s); 

我发现了这个问题。 问题是xml-string中用于换行符的字符。 在我的xml \ r \ n中用于换行,需要做的是将其更改为\ n,这似乎是java使用的。

我找到了答案,Gerben Rampaart在不同的在线sha256计算器上注意到了同样的事情,ken2k知道差异是什么

一旦我完成了SHA256.TransformFinalBlock()就像一个魅力。

最终解决方案看起来像这样:

 public byte[] GetDocumentHash(XmlDocument doc) { string formattedXml; Transform canonicalTransform = new XmlDsigExcC14NWithCommentsTransform(); canonicalTransform.LoadInput(doc); using (Stream canonicalStream = (Stream)canonicalTransform.GetOutput(typeof(Stream))) using (var stringWriter = new EncodingStringWriter(Encoding.UTF8)) using (var xmlTextWriter = XmlWriter.Create(stringWriter, new XmlWriterSettings { NewLineChars = "\n", CloseOutput = false, Encoding = Encoding.UTF8, Indent = true, OmitXmlDeclaration = true })) { XmlDocument newDoc = new XmlDocument(); newDoc.Load(canonicalStream); newDoc.WriteTo(xmlTextWriter); xmlTextWriter.Flush(); formattedXml = stringWriter.GetStringBuilder().ToString(); } byte[] bytesToCalculate = Encoding.UTF8.GetBytes(formattedXml); using (var sha256 = SHA256.Create()) { byte[] shaBytes = new byte[bytesToCalculate.Length]; bytesToCalculate.CopyTo(shaBytes, 0); sha256.TransformFinalBlock(shaBytes, 0, shaBytes.Length); return sha256.Hash; } } 

可能需要进行大量的重构和精炼,但它可以完成工作。

非常感谢帮助我的所有人!

下面的示例可能会给出相同的结果。 因为你正在做同样的操作。 在您的代码中,您将从XmlDsigExcC14NWithCommentsTransform获取清理的xml,然后计算哈希值。 下面的例子直接计算。

 XmlDocument doc = new XmlDocument(); doc.LoadXml("mkysoft"); XmlDsigExcC14NWithCommentsTransform c14n = new XmlDsigExcC14NWithCommentsTransform(); c14n.LoadInput(doc); var digest = c14n.GetDigestedOutput(SHA256.Create());