Вычислить хеш 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
Я думаю, что он хочет сгенерировать серийный ключ
Тьяго

Ответы:

198

Согласно 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();
    }
}
Анант Дабхи
источник
9
Источник: msdn.microsoft.com/en-us/library/…
yǝsʞǝla
5
Вы всегда должны говорить, откуда вы берете код, если копируете / вставляете откуда-то, иначе это классифицируется как плагиат.
DavidG
1
Класс MD5 реализует IDisposable, не забудьте удалить свой экземпляр. ;)
Паоло Иоммарини
6
В общем, вам следует использовать хеш-кодировку текста без потерь, например UTF8.
Оливер Бок
5
@PrashantPimpale MD5 - алгоритм дайджеста. Думайте об этом как о превращении коровы в стейк.
Анант Дабхи
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 спросил, какой алгоритм хеширования лучше всего использовать, ответ был бы другим (соответственно).
Майкл
8
Я ценю то, что голосование "против" за что-то вырванное из контекста для темы, которой больше двух лет. ;)
Майкл
Почему «похоже на формат UNIX»? Что это не совсем то?
Игорь Гатис
это дает другой результат от онлайн-чекеров md5. или это только у меня ??
bh_earth0
@ bh_earth0 кажется, что BitConverterон не работает одинаково в Windows и Linux, см. этот вопрос: stackoverflow.com/questions/11454004/…
eddyP23
10

Пытался создать строковое представление хэша MD5 с помощью LINQ, однако ни один из ответов не был решениями LINQ, поэтому добавлял это в шведский стол доступных решений.

string result;
using (MD5 hash = MD5.Create())
{
    result = String.Join
    (
        "",
        from ba in hash.ComputeHash
        (
            Encoding.UTF8.GetBytes(observedText)
        ) 
        select ba.ToString("x2")
    );
}
craigdfrench
источник
return string.Join( "", hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );
Однострочный
... в этом случае я предлагаю return string.Concat( hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );вместо этого. Это немного короче, возможно, более четкое намерение и работает немного быстрее (увеличение производительности <10%).
Marc.2377
9

Полностью зависит от того, чего вы пытаетесь достичь. Технически вы могли бы просто взять первые 12 символов из результата хеширования MD5, но спецификация MD5 состоит в том, чтобы сгенерировать 32 символа.

Уменьшение размера хэша снижает безопасность и увеличивает вероятность коллизий и поломки системы.

Возможно, если вы сообщите нам больше о том, чего вы пытаетесь достичь, мы сможем больше вам помочь.

KingCronus
источник
+1 Это ответ, но я тоже очень сомневаюсь в его надежности.
lc.
спасибо за Ваш ответ. и сожалею о моем плохом объяснении. Я хочу опубликовать приложение для Windows, пользователь должен купить лицензию на использование моего приложения, поэтому мое приложение запрашивает два поля: USERNAME: ... и KEY: .... Я хочу хешировать USERNAME и создать KEY , затем пользователь должен ввести конкретное ИМЯ ПОЛЬЗОВАТЕЛЯ и КЛЮЧ. Моя проблема здесь в том, что KEY должен быть 12-значным (но в хеш-коде MD5 я получаю 32-символьный KEY). пожалуйста, помогите мне, мне это действительно нужно.
Мухамад Джафарнеджад
8

Вы можете использовать Convert.ToBase64Stringдля преобразования 16-байтового вывода MD5 в строку из 24 символов. Немного лучше без снижения безопасности. ( j9JIbSY8HuT89/pwdC8jlw==для вашего примера)

ФУНТ
источник
2
Хороший обходной путь, но я сомневаюсь, что OP захочет, чтобы он был чувствителен к регистру и со специальными
символами
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
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);
    }
}

Вы можете оптимизировать его еще больше, если уверены, что ваши строки достаточно малы, и замените encoding.GetBytes на unsafe int GetBytes (ReadOnlySpan chars, Span bytes) альтернативой.

Томаш Кубес
источник
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/en-us/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);

            }
KhaledDev
источник
0

Я хотел бы предложить альтернативу, которая работает как минимум на 10% быстрее, чем ответ craigdfrench в моих тестах (.NET 4.7.2):

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);
Marc.2377
источник
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("-","");
IntegratedHen
источник