根据字符串计算MD5哈希


131

我使用以下C#代码从字符串中计算MD5哈希值。它运作良好,并生成一个32个字符的十六进制字符串,如下所示: 900150983cd24fb0d6963f7d28e17f72

string sSourceData;
byte[] tmpSource;
byte[] tmpHash;
sSourceData = "MySourceData";

//Create a byte array from source data.
tmpSource = ASCIIEncoding.ASCII.GetBytes(sSourceData);
tmpHash = new MD5CryptoServiceProvider().ComputeHash(tmpSource);

// and then convert tmpHash to string...

有没有办法使用像这样的代码来生成16个字符的十六进制字符串(或12个字符的字符串)?32个字符的十六进制字符串很好,但是我认为客户输入代码会很无聊!


7
为什么您需要客户输入十六进制?
丹·迪努

5
我认为他想生成一个序列密钥
-Thiago

Answers:


197

根据MSDN

创建MD5:

public static string CreateMD5(string input)
{
    // Use input string to calculate MD5 hash
    using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
    {
        byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
        byte[] hashBytes = md5.ComputeHash(inputBytes);

        // Convert the byte array to hexadecimal string
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < hashBytes.Length; i++)
        {
            sb.Append(hashBytes[i].ToString("X2"));
        }
        return sb.ToString();
    }
}


5
如果您从某处复制/粘贴,则应始终说出从何处获取代码,否则将其归类为gi窃。
DavidG

1
MD5类实现IDisposable,请记住布置您的实例。;)
Paolo Iommarini

5
通常,您应该对无损文本编码进行哈希处理,例如UTF8。
奥利弗·博克

5
@PrashantPimpale MD5是摘要算法。可以把它想象成将牛变成牛排。
Anant Dabhi

95
// given, a password in a string
string password = @"1234abcd";

// byte array representation of that string
byte[] encodedPassword = new UTF8Encoding().GetBytes(password);

// need MD5 to calculate the hash
byte[] hash = ((HashAlgorithm) CryptoConfig.CreateFromName("MD5")).ComputeHash(encodedPassword);

// string representation (similar to UNIX format)
string encoded = BitConverter.ToString(hash)
   // without dashes
   .Replace("-", string.Empty)
   // make lowercase
   .ToLower();

// encoded contains the hash you want

13
我的回答不是代表最佳实践。在OP提出他的问题的背景下提供。如果OP询问使用哪种最合适的哈希算法,答案将是不同的(相应地)。
迈克尔

8
对于两年多来的线程在上下文中删除的内容,我表示不赞成。;)
Michael

为什么“类似于UNIX格式”?有什么不完全一样?
Igor Gatis 2015年

这与在线md5检查器给出了不同的结果。还是只是我?
bh_earth0

@ bh_earth0 BitConverter在Windows和Linux上似乎无法以相同的方式工作,请参见以下问题:stackoverflow.com/questions/11454004/…–
eddyP23

10

试图使用LINQ创建MD5哈希的字符串表示形式,但是,答案都不是LINQ解决方案,因此将其添加到了可用解决方案的大杂烩中。

string result;
using (MD5 hash = MD5.Create())
{
    result = String.Join
    (
        "",
        from ba in hash.ComputeHash
        (
            Encoding.UTF8.GetBytes(observedText)
        ) 
        select ba.ToString("x2")
    );
}

一线式,方法语法:return string.Join( "", hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );
Marc.2377

...在这种情况下,我建议return string.Concat( hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );。它略短一些,可能更清晰,并且执行速度略快(<10%的性能提升)。
Marc.2377

9

完全取决于您要实现的目标。从技术上讲,您可以仅从MD5哈希的结果中获取前12个字符,但是MD5的规范是生成32个字符。

减小散列的大小会降低安全性,并增加冲突和系统损坏的机会。

也许,如果您让我们更多地了解您要达到的目标,我们可能会提供更多帮助。


+1这是答案,但是我也确实质疑它的安全性。
lc。

感谢您的回答。对我的错误解释深表歉意。我想为Windows发布一个应用程序,用户应该购买使用我的应用程序的许可证,因此我的应用程序请求两个字段:USERNAME:...和KEY:...。我想散列USERNAME并创建KEY ,则用户应输入特定的USERNAME和KEY。我的问题是KEY应该是12个字符(但是在MD5哈希中,我得到了32个字符的KEY)。请帮助我,我真的很需要。
Muhamad Jafarnejad

8

您可以使用Convert.ToBase64String将MD5的16字节输出转换为约24个字符的字符串。在不降低安全性的情况下好一点。(j9JIbSY8HuT89/pwdC8jlw==以您的示例为例)


2
一个不错的解决方法,但我怀疑他的OP会希望区分大小写并使用特殊字符...
KingCronus 2012年

5

支持字符串和文件流。

例子

string hashString = EasyMD5.Hash("My String");

string hashFile = EasyMD5.Hash(System.IO.File.OpenRead("myFile.txt"));

--

   class EasyMD5
        {
            private static string GetMd5Hash(byte[] data)
            {
                StringBuilder sBuilder = new StringBuilder();
                for (int i = 0; i < data.Length; i++)
                    sBuilder.Append(data[i].ToString("x2"));
                return sBuilder.ToString();
            }

            private static bool VerifyMd5Hash(byte[] data, string hash)
            {
                return 0 == StringComparer.OrdinalIgnoreCase.Compare(GetMd5Hash(data), hash);
            }

            public static string Hash(string data)
            {
                using (var md5 = MD5.Create())
                    return GetMd5Hash(md5.ComputeHash(Encoding.UTF8.GetBytes(data)));
            }
            public static string Hash(FileStream data)
            {
                using (var md5 = MD5.Create())
                    return GetMd5Hash(md5.ComputeHash(data));
            }

            public static bool Verify(string data, string hash)
            {
                using (var md5 = MD5.Create())
                    return VerifyMd5Hash(md5.ComputeHash(Encoding.UTF8.GetBytes(data)), hash);
            }

            public static bool Verify(FileStream data, string hash)
            {
                using (var md5 = MD5.Create())
                    return VerifyMd5Hash(md5.ComputeHash(data), hash);
            }
        }

4

我想最好在字符串MD5中使用UTF-8编码。

public static string MD5(this string s)
{
    using (var provider = System.Security.Cryptography.MD5.Create())
    {
        StringBuilder builder = new StringBuilder();                           

        foreach (byte b in provider.ComputeHash(Encoding.UTF8.GetBytes(s)))
            builder.Append(b.ToString("x2").ToLower());

        return builder.ToString();
    }
}

3

MD5哈希是128位,因此您不能用少于32个字符的十六进制表示它...


好吧,我一定在这里想念什么。怎么样?
lc。

@lc。,抱歉,我的回答中有错字,我写的是“可以”而不是“不能” ...
Thomas Levesque 2012年

3
System.Text.StringBuilder hash = new System.Text.StringBuilder();
        System.Security.Cryptography.MD5CryptoServiceProvider md5provider = new System.Security.Cryptography.MD5CryptoServiceProvider();
        byte[] bytes = md5provider.ComputeHash(new System.Text.UTF8Encoding().GetBytes(YourEntryString));

        for (int i = 0; i < bytes.Length; i++)
        {
            hash.Append(bytes[i].ToString("x2")); //lowerCase; X2 if uppercase desired
        }
        return hash.ToString();

3

.NET Core 2.1及更高版本的现有答案的更快替代方法:

public static string CreateMD5(string s)
{
    using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
    {
        var encoding = Encoding.ASCII;
        var data = encoding.GetBytes(s);

        Span<byte> hashBytes = stackalloc byte[16];
        md5.TryComputeHash(data, hashBytes, out int written);
        if(written != hashBytes.Length)
            throw new OverflowException();


        Span<char> stringBuffer = stackalloc char[32];
        for (int i = 0; i < hashBytes.Length; i++)
        {
            hashBytes[i].TryFormat(stringBuffer.Slice(2 * i), out _, "x2");
        }
        return new string(stringBuffer);
    }
}

如果您确定您的字符串足够小并且可以用不安全的int GetBytes(ReadOnlySpan chars,Spanbytes)替代int,则可以进一步优化它。


3

此解决方案需要c#8并利用Span<T>。注意,如果需要,您仍然需要调用.Replace("-", string.Empty).ToLowerInvariant()以格式化结果。

public static string CreateMD5(ReadOnlySpan<char> input)
{
    var encoding = System.Text.Encoding.UTF8;
    var inputByteCount = encoding.GetByteCount(input);
    using var md5 = System.Security.Cryptography.MD5.Create();

    Span<byte> bytes = inputByteCount < 1024
        ? stackalloc byte[inputByteCount]
        : new byte[inputByteCount];
    Span<byte> destination = stackalloc byte[md5.HashSize / 8];

    encoding.GetBytes(input, bytes);

    // checking the result is not required because this only returns false if "(destination.Length < HashSizeValue/8)", which is never true in this case
    md5.TryComputeHash(bytes, destination, out int _bytesWritten);

    return BitConverter.ToString(destination.ToArray());
}

0
StringBuilder sb= new StringBuilder();
for (int i = 0; i < tmpHash.Length; i++)
{
   sb.Append(tmpHash[i].ToString("x2"));
}

0

https://docs.microsoft.com/zh-cn/dotnet/api/system.security.cryptography.md5?view=netframework-4.7.2

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

    static string GetMd5Hash(string input)
            {
                using (MD5 md5Hash = MD5.Create())
                {

                    // Convert the input string to a byte array and compute the hash.
                    byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));

                    // Create a new Stringbuilder to collect the bytes
                    // and create a string.
                    StringBuilder sBuilder = new StringBuilder();

                    // Loop through each byte of the hashed data 
                    // and format each one as a hexadecimal string.
                    for (int i = 0; i < data.Length; i++)
                    {
                        sBuilder.Append(data[i].ToString("x2"));
                    }

                    // Return the hexadecimal string.
                    return sBuilder.ToString();
                }
            }

            // Verify a hash against a string.
            static bool VerifyMd5Hash(string input, string hash)
            {
                // Hash the input.
                string hashOfInput = GetMd5Hash(input);

                // Create a StringComparer an compare the hashes.
                StringComparer comparer = StringComparer.OrdinalIgnoreCase;

                return 0 == comparer.Compare(hashOfInput, hash);

            }

0

我想提供一种替代方案,该替代方案在我的测试(.NET 4.7.2)中似乎比craigdfrench的答案至少快10%:

public static string GetMD5Hash(string text)
{
    using ( var md5 = MD5.Create() )
    {
        byte[] computedHash = md5.ComputeHash( Encoding.UTF8.GetBytes(text) );
        return new System.Runtime.Remoting.Metadata.W3cXsd2001.SoapHexBinary(computedHash).ToString();
    }
}

如果您希望using System.Runtime.Remoting.Metadata.W3cXsd2001;位于顶部,可以使方法主体更易于阅读:

using ( var md5 = MD5.Create() )
{
    return new SoapHexBinary( md5.ComputeHash( Encoding.UTF8.GetBytes(text) ) ).ToString();
}

足够明显,但出于完整性考虑,在OP的上下文中,它将用作:

sSourceData = "MySourceData";
tmpHash = GetMD5Hash(sSourceData);

0

关于16个字符的十六进制字符串的任何内容...

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

但是这里是我在一行中创建MD5哈希的方法。

string hash = BitConverter.ToString(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes("THIS STRING TO MD5"))).Replace("-","");
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.