将SHA256从Java转换为C# [英] Converting SHA256 from Java to C#
问题描述
我有一个简单的问题.我需要将java的sha256校验和方法重写为C#
I have a simple question. I need to rewrite a sha256 checksum method from java to C#
所以我有这个Java鳕鱼可以使用:
So I have this Java cod to work with :
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()方法.
From what I can find, the update() and digest() method should basicly be substitutet for the TransformBlock() and TransformFinalBlock() methods in the respective HashAlgorithm derived class (in this case SHA256).
所以我在C#中尝试了类似的东西:
So I've tried with something similar to this in 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;
}
(同样,数据是字节数组)
但是,字节不匹配.我在这里想念东西吗?
However, the bytes do not match up. Am I missing something here?
(当然我是,否则它会起作用,对吧?:S)
更新
为了给您更多的信息,在运行上面看到的代码之前,我已经将Java和C#代码之间的字节进行了匹配.然后他们匹配.但是,C#代码中的字节来自UTF8编码的字符串,而Java字节来自c14Canonicalizer.canonicalizeSubtree()方法.
To give you some more info to go on, I have matched the bytes between the Java and C# code before running the code you see above. And then they do match. However, the bytes in the C# code comes from a UTF8-Encoded string while the Java bytes comes from a c14Canonicalizer.canonicalizeSubtree() method.
我将更新上面的代码示例以包括其起源.
I'll update the above code examples to include their origins.
更新
对于它的价值,Java md.digest()方法返回以下字节:
For what it's worth, the Java md.digest() method returns the following bytes:
-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
-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
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,32,171,156,178
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()
推荐答案
我发现了问题.问题是xml字符串中用于换行符的字符.在我的xml \ r \ n用于换行符中,需要做的就是将其更改为\ n,这似乎是java所使用的.
I found the issue. The problem was the characters used for linebreaks in the xml-string. in my xml \r\n is used for linebreaks, what needed to be done was to change it to \n which seems to be what java uses.
我在此处找到了答案,其中Gerben Rampaart在不同的在线sha256计算器上注意到了同一件事,而ken2k知道了什么区别是
I found the answer here where Gerben Rampaart had noticed the same thing on different online sha256-calculators and ken2k knew what the difference was
一旦完成该操作, SHA256.TransformFinalBlock()
就会像魅力一样发挥作用.
Once I had done that SHA256.TransformFinalBlock()
worked like a charm.
最终的解决方案如下所示:
The final solution looks something like this:
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;
}
}
可能需要进行大量的重构和优化,但这可以完成工作.
There's probably a lot of refactoring and refining needed, but it gets the job done.
非常感谢所有帮助过我的人!
A big thank you to all of you who helped me!
这篇关于将SHA256从Java转换为C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!