简体   繁体   English

将SHA256从Java转换为C#

[英]Converting SHA256 from Java to C#

I have a simple question. 我有一个简单的问题。 I need to rewrite a sha256 checksum method from java to C# 我需要将sha256校验和方法从Java重写为C#

So I have this Java cod to work with : 所以我有这个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 is, you guessed it, a byte array :D) (您猜中,byteArray是一个字节数组:D)

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). 从我的发现中,在相应的HashAlgorithm派生类(在本例中为SHA256)中,update()和摘要()方法基本上应该替代TransformBlock()和TransformFinalBlock()方法。

So I've tried with something similar to this in C#: 所以我在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;
}

(and again, data is a byte array) (同样,数据是字节数组)

However, the bytes do not match up. 但是,字节不匹配。 Am I missing something here? 我在这里想念什么吗?

(well of course I am, otherwise it would work, right? :S ) (我当然是这样,否则它将起作用,对吗?:S)

UPDATE 更新

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. 为了给您更多的信息,在运行上面看到的代码之前,我已经在Java和C#代码之间匹配了字节。 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. 但是,C#代码中的字节来自UTF8编码的字符串,而Java字节来自c14Canonicalizer.canonicalizeSubtree()方法。

I'll update the above code examples to include their origins. 我将更新上面的代码示例以包括其起源。

UPDATE 更新

For what it's worth, the Java md.digest() method returns the following bytes: 对于它的价值,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 -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

when converted that translates to 转换后转化为

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

while the C# code returns 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 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

when using sha256.ComputeHash() 使用sha256.ComputeHash()

Did you try the ComputeHash method ? 您尝试过ComputeHash方法吗?

ie : 即:

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

EDIT 编辑

Can you try this ? 你可以试试这个吗?

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);

I found the issue. 我发现了问题。 The problem was the characters used for linebreaks in the xml-string. 问题是xml字符串中用于换行符的字符。 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. 在我的xml \\ r \\ n用于换行符中,需要做的就是将其更改为\\ n,这似乎是java所使用的。

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 我在这里找到了答案,Gerben Rampaart在不同的在线sha256计算器上注意到了同一件事,而ken2k知道有什么区别

Once I had done that SHA256.TransformFinalBlock() worked like a charm. 一旦完成此操作, SHA256.TransformFinalBlock()像魅力一样SHA256.TransformFinalBlock()

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! 非常感谢所有帮助过我的人!

Below sample may be giving same result. 下面的示例可能会给出相同的结果。 Because you are making same operation long way. 因为您要进行相同的操作很长的路要走。 In your code, you are getting cleaned xml from XmlDsigExcC14NWithCommentsTransform then calculate hash. 在您的代码中,您将从XmlDsigExcC14NWithCommentsTransform中获取xml,然后计算哈希。 Below example calculate directly. 下面的例子直接计算。

XmlDocument doc = new XmlDocument();
doc.LoadXml("<a><xmlString>mkysoft</xmlString></a>");
XmlDsigExcC14NWithCommentsTransform c14n = new XmlDsigExcC14NWithCommentsTransform();
c14n.LoadInput(doc);
var digest = c14n.GetDigestedOutput(SHA256.Create());

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM