C# MD5 哈希函数 return 奇怪的结果?

C# MD5 hash function return weird result?

我刚刚尝试在 C# 中创建一个 MD5 哈希程序。我的朋友给了我一个关于这个的示例代码,但是当我尝试 运行 使用“123456”进行测试时,而不是返回正确的哈希结果

e10adc3949ba59abbe56e057f20f883e

它returns结果

ce0bfd15059b68d67688884d7a3d3e8c

我试图阅读主要代码,但仍然一无所获!

string value = textBox1.Text;

byte[] valueBytes = new byte[value.Length * 2];

Encoder encoder = Encoding.Unicode.GetEncoder();
encoder.GetBytes(value.ToCharArray(), 0, value.Length, valueBytes, 0, true);

MD5 md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(valueBytes);

StringBuilder stringBuilder = new StringBuilder();

for (int i = 0; i < hashBytes.Length; i++)
{
    stringBuilder.Append(hashBytes[i].ToString("x2"));
}
textBox2.Text = stringBuilder.ToString();

你期待的是UTF8字符串,为什么要用Unicode编码?使用 UTF8,你会得到你期望的结果:

string value = "123456";

byte[] valueBytes = new byte[value.Length]; // <-- don't multiply by 2!

Encoder encoder = Encoding.UTF8.GetEncoder(); // <-- UTF8 here
encoder.GetBytes(value.ToCharArray(), 0, value.Length, valueBytes, 0, true);

MD5 md5 = new MD5CryptoServiceProvider();
byte[] hashBytes = md5.ComputeHash(valueBytes);

StringBuilder stringBuilder = new StringBuilder();

for (int i = 0; i < hashBytes.Length; i++)
{
    stringBuilder.Append(hashBytes[i].ToString("x2"));
}

Console.WriteLine(stringBuilder.ToString()); // "e10adc3949ba59abbe56e057f20f883e"

看起来你的朋友使用了 Encoding.Default 而不是 Encoding.Unicode

.NET 中的字符串是 UTF16。但是,哈希适用于 bytes,不适用于字符串。字符串必须转换为字节。为此,必须使用特定的编码。

如果使用 .NET 本机编码,即 UTF16,原始字节缓冲区将为 12 个字节长,哈希的十六进制表示将为 ce0bfd15059b68d67688884d7a3d3e8c :

var valueBytes=Encoding.Unicode.GetBytes("123456");
Debug.Assert(valueBytes.Length==12);
var md5=System.Security.Cryptography.MD5.Create();
byte[] hashBytes = md5.ComputeHash(valueBytes);
var hexText=String.Join("",hashBytes.Select(c=>c.ToString("x2")));

如果使用 7 位 US-ASCII 编码,数组长度为 6 个字节,十六进制表示为 e10adc3949ba59abbe56e057f20f883e :

var valueBytes=Encoding.ASCII.GetBytes("123456");
Debug.Assert(valueBytes.Length==6);

var md5=System.Security.Cryptography.MD5.Create();
byte[] hashBytes = md5.ComputeHash(valueBytes);
var hexText=String.Join("",hashBytes.Select(c=>c.ToString("x2")));

大多数代码页的前 127 个字节匹配 7 位 US-ASCII 字符,因此 most encodings,包括 UTF8,将 return e10adc3949ba59abbe56e057f20f883e。以下编码将 return 相同的散列字符串:Encoding.GetEncoding(1251)(西里尔文),Encoding.GetEncoding(20000)(繁体中文)将产生相同的散列。

Encoding.Default 值 return 是与计算机系统区域设置相对应的编码。它是非 Unicode 应用程序使用的编码,例如使用 ANSI 字符串类型编译的 C++ 应用程序。

Encoding.GetEncoding(20273) 虽然会 return 一个不同的值 - 这是一个 IBM EBCDIC,即使对于英文字母和数字也使用不同的字节。这将 return : 73e00d17ee63efb9ae91d274baae2459