将SHA256从Java转换为C# [英] Converting SHA256 from Java to C#

查看:89
本文介绍了将SHA256从Java转换为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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆