【问题标题】:Hashing non ascii characters C#散列非 ascii 字符 C#
【发布时间】:2012-01-17 09:42:13
【问题描述】:

这里有两个哈希生成器:

  1. http://www.md5hashgenerator.com/index.php
  2. http://www.miraclesalad.com/webtools/md5.php

现在,我的问题是: 为什么在尝试散列 char '€' (0x80) 时散列不同? 我认为这是因为“€”不是普通的 ASCII 字符。 这两个哈希中的哪一个是“正确的”?

我正在尝试使用 C# 计算哈希生成器 1 返回的哈希。 这个散列函数不返回它。

private string GetMD5Hash(string TextToHash)
{
        if ((TextToHash == null) || (TextToHash.Length == 0))
        {
            return string.Empty;
        }
        MD5 md5 = new MD5CryptoServiceProvider();
        byte[] textToHash = Encoding.Default.GetBytes(TextToHash);
        byte[] result = md5.ComputeHash(textToHash);
        return BitConverter.ToString(result).Replace("-", "").ToLower();
}

我怎样才能改变它,让它返回我想要的哈希值?


附加信息: 我做了一个小 AutoIt 脚本:

#include  <Crypt.au3>
ConsoleWrite(StringLower(StringMid(_Crypt_HashData(Chr(128), $CALG_MD5),3)) & @CRLF)

它会返回我想要的哈希值! 但是我需要一个 C# 代码:)

【问题讨论】:

  • 所以将“Encoding.Default.GetBytes”更改为“Encoding.UTF8.GetBytes”?
  • 我不认为这是错误的,因为 AutoIt 代码获得了正确的哈希值。那么它有什么不同呢??
  • @Alex:没有指定它使用的编码就没有“正确的哈希”这样的东西......哈希应用于二进制数据,而不是字符串 - 所以我们需要知道 binary 数据正在被散列。
  • 对于“正确的哈希”,我的意思是我需要的哈希 :) 但是感谢您清除这个!
  • 另外两个注意事项: 不是“不是普通的 ASCII 字符”——而是:它根本不是 ASCII 字符。此外,说它是“0x80”也没有意义——这取决于编码。唯一有用的数字(没有编码)是 unicode 代码点,即 0x20AC

标签: c# md5


【解决方案1】:

归结为您使用哪种编码将string 转换为byte[](因此我建议使用 UTF-8,因为这是一个很常见的选择;但是,任何完整的 unicode 编码都可以只要你知道使用哪个);例如,根据字符串"abc€",我们可以推断出第一个站点可能正在使用以下任何一个:

874: Thai (Windows)
936: Chinese Simplified (GB2312)
1250: Central European (Windows)
1252: Western European (Windows)
1253: Greek (Windows)
1254: Turkish (Windows)
1255: Hebrew (Windows)
1256: Arabic (Windows)
1257: Baltic (Windows)
1258: Vietnamese (Windows)
50227: Chinese Simplified (ISO-2022)
51936: Chinese Simplified (EUC)
52936: Chinese Simplified (HZ)

就个人而言,我会使用 UTF-8!

这是我用来查找候选编码的代码:

    MD5 md5 = new MD5CryptoServiceProvider();
    foreach (var enc in Encoding.GetEncodings())
    {
        byte[] textToHash = enc.GetEncoding().GetBytes("abc€");
        byte[] result = md5.ComputeHash(textToHash);
        var output = BitConverter.ToString(result).Replace("-", "").ToLower();
        if(output == "7a66042043b2cc38ba16a13c596d740e")
        {  // result from http://www.md5hashgenerator.com/index.php
            Console.WriteLine(enc.CodePage + ": " + enc.DisplayName);
        }
    }

此外,使用字符串"dnos ʇǝqɐɥdʃɐ" 进行测试表明第二个站点肯定使用的是UTF-8;第一个站点找不到匹配项,所以我猜它使用的是基于代码页的编码,简而言之将无法可靠地工作与全范围的 unicode。

【讨论】:

  • 非常感谢!这帮助很大。我一回家就试试看:)我很想给你+1,但我不能:(
  • 代表亚历克斯 +1。我确认站点 2 是 UTF 8,站点 1 显然是西欧......
  • @Alex 如果 Garry 是正确的并且确实是西欧人,那么您将使用 Encoding.GetEncoding(1252).GetBytes(...)
【解决方案2】:

您展示的两个 MD5 页面都将 MD5 描述为适用于字符串的操作。它不是——它是一个适用于 byte 序列的操作。为了从字符串转换为字节序列,您需要使用编码

您选择了Encoding.Default,这几乎总是一个糟糕的选择——我通常会选择Encoding.UTF8。然而,重要的是,这些网站都没有说明他们正在使用什么。但是,在现实生活中,我希望您要么控制两个哈希过程(假设确实有两个),要么您无法控制的任何哈希代码将指定要使用的编码.

请注意,有一种更简单的方法可以创建 MD5 的实例 - 只需使用 MD5.Create。您通常还应该将它放在using 语句中,因为它实现了IDisposable

private static string GetMD5Hash(string text)
{
    if (string.IsNullOrEmpty(text))
    {
        return "";
    }
    using (var md5 = MD5.Create())
    {
        byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(text));
        return BitConverter.ToString(hash).Replace("-", "").ToLower();
    }
}

【讨论】:

  • 谢谢!对我很有用。
猜你喜欢
  • 1970-01-01
  • 2015-12-08
  • 2012-01-23
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 2012-04-28
  • 1970-01-01
相关资源
最近更新 更多