将C# SHA256哈希转换为Ruby

4

我有以下C#代码:

byte[] bytes = new UnicodeEncoding().GetBytes(input);
return Convert.ToBase64String(new SHA256Managed().ComputeHash(bytes));

这是一个将字符串编码为SHA2哈希值,然后进行base64编码的方法。我需要将其转换为Ruby语言。

我尝试过几种方法,以下是其中一种:

hash = Digest::SHA256.digest(val.encode('utf-8'))
encoded = Base64.urlsafe_encode64(hash)

我的代码都产生了不匹配的相同结果。我无法让它们正常工作。如果能帮忙转换一下就感激不尽。

更新

经过一些尝试,我成功使用硬编码数组使其工作。问题在于C#代码在数组中的每个元素后面添加了一个0。这是带有硬编码数组的可行的Ruby代码:

Digest::SHA256.base64digest([99,0,104,0,97,0,100,0].pack('C*').force_encoding('utf-16'))

我想我可以遍历数组,但这似乎是不必要的。

3个回答

5

解决方案:

为了得到相同的SHA-256哈希值,您需要使用UTF-16LE编码。

p hash = Digest::SHA256.base64digest("Hello".encode('UTF-16LE'))

我是如何找到它的?

我使用在线C#工具使用以下代码创建字符串"Hello"的哈希值:

using System.IO;
using System;
using System.Text;
using System.Security.Cryptography;

class Program
{
    static void Main()
    {
        byte[] bytes = new UnicodeEncoding().GetBytes("Hello");
        String s =  Convert.ToBase64String(new SHA256Managed().ComputeHash(bytes));
        Console.WriteLine(s);
    }
}

以上程序输出结果为oH5Pc0MkbIKybzLlb4VBjVGNiy8trnfx1W/nr1Dbl68=

接着,我编写了一段 Ruby 程序来计算字符串"Hello"的 Base64 编码 SHA-256 哈希值,通过对 Ruby 支持的所有字符编码进行编码,找出哪种字符编码会给出完全相同的结果。

require "digest/sha2"
require "base64"
s = "Hello"
Encoding.list.each { |e| puts "Encoding: #{e.to_s} => Hash: #{Digest::SHA256.base64digest(s.encode(e)) rescue "error"}"}

运行程序后,我得出结论,如果使用 UTF-16LE 编码,你将获得完全相同的输出。
p hash = Digest::SHA256.base64digest("Hello".encode('UTF-16LE'))

根据 UnicodeEncoding文档,它代表Unicode字符的UTF-16编码。

1
我认为您应该将new UnicodeEncoding()更改为new UTF8Encoding()或者直接使用Encoding.UTF8
在C#中,Unicode表示UTF-16。

上面的代码是在反编译用于密码哈希的dll后获取的。也许如果我在Ruby端尝试使用utf-16,那就可以解决问题。 - CWitty
1
我认为使用 utf-16le 可能会起作用(我不太了解 Ruby)... utf-16 将每个字符编码为 2 或 4 个字节... 在 C# 中使用 GetBytes 方法将不会放置 BOM,我认为使用小端可能会起作用。 - Norgerman

0

好的,这是一个多项式。在C#中,UnicodeEncoding().GetBytes(str) 显然会在每个字符后面添加一个0到字节数组中。所以我不得不在Ruby中解决这个问题。幸运的是,我能够使用一些Ruby魔法来解决这个问题。完整的工作解决方案如下。

byte_array = input.bytes.zip(input.bytes.map{|b| 0}).flatten.compact
Digest::SHA256.base64digest(byte_array.pack('C*').force_encoding('utf-16'))

这使我得到了一个与数据库中的值匹配的相同哈希输出。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接