Calcular um hash MD5 a partir de uma sequência

131

Eu uso o seguinte código C # para calcular um hash MD5 de uma seqüência de caracteres. Funciona bem e gera uma cadeia hexadecimal de 32 caracteres como esta: 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...

Existe uma maneira de usar código como este para gerar uma cadeia hexadecimal de 16 caracteres (ou cadeia de 12 caracteres)? Uma string hexadecimal de 32 caracteres é boa, mas acho que será chato para o cliente digitar o código!

Muhamad Jafarnejad
fonte
7
por que você precisa que o cliente digite o hexadecimal?
Dan Dinu
5
Eu acho que ele quer gerar uma chave serial
Thiago

Respostas:

197

Conforme MSDN

Crie 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();
    }
}
Anant Dabhi
fonte
9
A fonte: msdn.microsoft.com/en-us/library/…
yǝsʞǝla
5
Você sempre deve dizer de onde obtém o código se copiar / colar de algum lugar, caso contrário, será classificado como plágio.
DavidG
1
A classe MD5 implementa IDisposable, lembre-se de descartar sua instância. ;)
Paolo Iommarini 28/02
5
Em geral, você deve fazer o hash de uma codificação de texto sem perdas, como UTF8.
Oliver Bock
5
@PrashantPimpale MD5 é um algoritmo de resumo. Pense nisso como converter uma vaca em um bife.
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
Michael
fonte
13
Minha resposta não foi denotar as melhores práticas. Foi fornecido no contexto em que o OP havia enquadrado sua pergunta. Se o OP tivesse perguntado qual é o algoritmo de hash mais apropriado a ser usado, a resposta teria sido diferente (de acordo).
Michael
8
Agradeço o voto negativo de algo retirado do contexto de um tópico com mais de dois anos de idade. ;)
Michael
Por que "semelhante ao formato UNIX"? O que não é exatamente o mesmo?
Igor Gatis 12/06
isso dá um resultado diferente dos verificadores MD5 on-line. Ou é só comigo??
bh_earth0
@ bh_earth0 parece que BitConverternão funciona da mesma maneira no Windows e Linux, consulte esta pergunta: stackoverflow.com/questions/11454004/...
eddyP23
10

Estava tentando criar uma representação de string do hash MD5 usando o LINQ, no entanto, nenhuma das respostas eram soluções LINQ, portanto, adicionando isso ao smorgasbord de soluções disponíveis.

string result;
using (MD5 hash = MD5.Create())
{
    result = String.Join
    (
        "",
        from ba in hash.ComputeHash
        (
            Encoding.UTF8.GetBytes(observedText)
        ) 
        select ba.ToString("x2")
    );
}
craigdfrench
fonte
Uma linha, na sintaxe do método:return string.Join( "", hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );
Marc.2377 24/11/19
... nesse caso, proponho return string.Concat( hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );. É um pouco mais curta, possivelmente uma intenção mais clara, e executa marginalmente mais rápido (<10% de aumento de desempenho).
Marc.2377
9

Depende inteiramente do que você está tentando alcançar. Tecnicamente, você pode apenas pegar os 12 primeiros caracteres do resultado do hash MD5, mas a especificação do MD5 é gerar um caractere de 32 caracteres.

Reduzir o tamanho do hash reduz a segurança e aumenta a chance de colisões e o sistema ser quebrado.

Talvez se você nos informar mais sobre o que está tentando alcançar, poderemos ajudar mais.

KingCronus
fonte
+1 Esta é a resposta, mas eu também questiono realmente a segurança dela.
lc.
obrigado pela sua resposta. e desculpe pela minha má explicação. Quero publicar um aplicativo para Windows, o usuário deve comprar a licença para usar meu aplicativo, portanto, meu aplicativo solicita dois campos: USERNAME: ... e KEY: .... Quero fazer o hash do USERNAME e criar a KEY , o usuário deve inserir o USERNAME e KEY específicos. meu problema aqui é que a chave deve ter 12 caracteres (mas no hash MD5, eu recebo a chave de 32 caracteres). por favor me ajude, eu realmente preciso disso.
Muhamad Jafarnejad 12/12/12
8

Você pode usar Convert.ToBase64Stringpara converter uma saída de 16 bytes do MD5 em uma string de ~ 24 caracteres. Um pouco melhor sem reduzir a segurança. ( j9JIbSY8HuT89/pwdC8jlw==para o seu exemplo)

LIBRA
fonte
2
Uma solução agradável, mas eu duvido que ele OP vai querer tê-lo sensível a maiúsculas e com caracteres especiais ...
KingCronus
5

Sequência de suporte e fluxo de arquivos.

exemplos

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);
            }
        }
Pense grande
fonte
4

Suponho que seja melhor usar a codificação UTF-8 na string MD5.

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();
    }
}
Tomas Kubes
fonte
3

Um hash MD5 tem 128 bits, portanto você não pode representá-lo em hexadecimal com menos de 32 caracteres ...

Thomas Levesque
fonte
Ok, devo estar faltando alguma coisa aqui. Quão?
lc.
. @lc, desculpe, houve um erro na minha resposta, eu tinha escrito "pode" em vez de "não pode" ...
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();
Kristian Jay
fonte
3

Uma alternativa mais rápida da resposta existente para o .NET Core 2.1 e superior:

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);
    }
}

Você pode otimizá-lo ainda mais se tiver certeza de que suas seqüências de caracteres são pequenas o suficiente e substituir a codificação.

Tomas Kubes
fonte
3

Esta solução requer c # 8 e tira proveito Span<T>. Observe que você ainda precisará ligar .Replace("-", string.Empty).ToLowerInvariant()para formatar o resultado, se necessário.

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());
}
Brad M
fonte
0
StringBuilder sb= new StringBuilder();
for (int i = 0; i < tmpHash.Length; i++)
{
   sb.Append(tmpHash[i].ToString("x2"));
}
Suhrob Samiev
fonte
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
fonte
0

Gostaria de oferecer uma alternativa que pareça executar pelo menos 10% mais rápido que a resposta de craigdfrench nos meus testes (.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();
    }
}

Se você preferir ter using System.Runtime.Remoting.Metadata.W3cXsd2001;no topo, o corpo do método pode facilitar a leitura de uma linha:

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

Óbvio o suficiente, mas para ser completo, no contexto do OP, ele seria usado como:

sSourceData = "MySourceData";
tmpHash = GetMD5Hash(sSourceData);
Marc.2377
fonte
0

Idk qualquer coisa sobre cadeias hexadecimais de 16 caracteres ....

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

Mas aqui está o meu para criar o hash MD5 em uma linha.

string hash = BitConverter.ToString(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes("THIS STRING TO MD5"))).Replace("-","");
IntegratedHen
fonte