Calcular un hash MD5 a partir de una cadena

131

Utilizo el siguiente código C # para calcular un hash MD5 a partir de una cadena. Funciona bien y genera una cadena 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...

¿Hay alguna manera de usar un código como este para generar una cadena hexadecimal de 16 caracteres (o una cadena de 12 caracteres)? Una cadena hexadecimal de 32 caracteres es buena, ¡pero creo que será aburrido que el cliente ingrese el código!

Muhamad Jafarnejad
fuente
77
¿Por qué necesitas que el cliente ingrese al hex?
Dan Dinu
55
Creo que quiere generar una clave de serie
Thiago

Respuestas:

197

Según MSDN

Crear 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
fuente
9
La fuente: msdn.microsoft.com/en-us/library/…
yǝsʞǝla
55
Siempre debe decir de dónde obtiene el código si copia / pega desde algún lugar, de lo contrario, se clasifica como plagio.
DavidG
1
La clase MD5 implementa IDisposable, recuerde disponer su instancia. ;)
Paolo Iommarini
55
En general, debe codificar una codificación de texto sin pérdidas, como UTF8.
Oliver Bock
55
@PrashantPimpale MD5 es un algoritmo de resumen. Piense en ello como convertir una vaca en un bistec.
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
Miguel
fuente
13
Mi respuesta no fue denotar las mejores prácticas. Se proporcionó en el contexto de que el OP había formulado su pregunta. Si el OP hubiera preguntado cuál es el algoritmo de hash más apropiado para usar, la respuesta habría sido diferente (en consecuencia).
Michael
8
Agradezco el voto negativo por algo sacado de contexto para un hilo que tiene más de dos años. ;)
Michael
¿Por qué "similar al formato UNIX"? ¿Qué no es exactamente lo mismo?
Igor Gatis
Esto da un resultado diferente de los verificadores md5 en línea. ¿¿O solo soy yo??
bh_earth0
@ bh_earth0 parece que BitConverterno funciona de la misma manera en Windows y Linux, vea esta pregunta: stackoverflow.com/questions/11454004/…
eddyP23
10

Estaba tratando de crear una representación de cadena de hash MD5 usando LINQ, sin embargo, ninguna de las respuestas eran soluciones de LINQ, por lo tanto, agregamos esto a la gran variedad de soluciones disponibles.

string result;
using (MD5 hash = MD5.Create())
{
    result = String.Join
    (
        "",
        from ba in hash.ComputeHash
        (
            Encoding.UTF8.GetBytes(observedText)
        ) 
        select ba.ToString("x2")
    );
}
craigdfrench
fuente
One-liner, en sintaxis de método:return string.Join( "", hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );
Marc.2377
... en cuyo caso, propongo en su return string.Concat( hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );lugar. Es un poco más corto, posiblemente con una intención más clara, y funciona marginalmente más rápido (<10% de aumento de rendimiento).
Marc.2377
9

Depende completamente de lo que intentes lograr. Técnicamente, podría tomar los primeros 12 caracteres del resultado del hash MD5, pero la especificación de MD5 es generar uno de 32 caracteres.

Reducir el tamaño del hash reduce la seguridad y aumenta la posibilidad de colisiones y la ruptura del sistema.

Quizás si nos hace saber más sobre lo que está tratando de lograr, podríamos ayudarlo más.

KingCronus
fuente
+1 Esta es la respuesta, pero yo también cuestiono realmente la seguridad.
lc.
gracias por tu respuesta. y perdón por mi mala explicación Quiero publicar una aplicación para Windows, el usuario debe comprar la licencia para usar mi aplicación, por lo que mi aplicación debe solicitar dos campos: NOMBRE DE USUARIO: ... y CLAVE: .... Quiero cambiar el nombre de usuario y crear la CLAVE , el usuario debe ingresar el NOMBRE DE USUARIO y la CLAVE específicos. mi problema aquí es que la CLAVE debe tener 12 caracteres (pero en el hash MD5, obtengo la CLAVE de 32 caracteres). por favor ayúdame, realmente lo necesito.
Muhamad Jafarnejad
8

Puede usar Convert.ToBase64Stringpara convertir la salida de 16 bytes de MD5 a una cadena de ~ 24 caracteres. Un poco mejor sin reducir la seguridad. ( j9JIbSY8HuT89/pwdC8jlw==por tu ejemplo)

LB
fuente
2
Una buena solución, pero dudo que OP quiera tener mayúsculas y minúsculas y caracteres especiales ...
KingCronus
5

Cadena de soporte y secuencia de archivo.

ejemplos

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);
            }
        }
Piensa en grande
fuente
4

Supongo que es mejor usar la codificación UTF-8 en la cadena 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();
    }
}
Tomás Kubes
fuente
3

Un hash MD5 tiene 128 bits, por lo que no puede representarlo en hexadecimal con menos de 32 caracteres ...

Thomas Levesque
fuente
Ok, debo estar perdiendo algo aquí. ¿Cómo?
lc.
@lc., lo siento, había un error tipográfico en mi respuesta, había escrito "puede" en lugar de "no puedo" ...
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
fuente
3

Una alternativa más rápida de respuesta existente para .NET Core 2.1 y 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);
    }
}

Puede optimizarlo aún más si está seguro de que sus cadenas son lo suficientemente pequeñas y reemplazan la codificación. GetBytes por la alternativa insegura GetBytes (caracteres de ReadOnlySpan, bytes de extensión).

Tomás Kubes
fuente
3

Esta solución requiere c # 8 y se aprovecha Span<T>. Tenga en cuenta que aún deberá llamar .Replace("-", string.Empty).ToLowerInvariant()para formatear el resultado si es necesario.

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

Me gustaría ofrecer una alternativa que parece funcionar al menos un 10% más rápido que la respuesta de craigdfrench en mis pruebas (.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();
    }
}

Si prefiere tener using System.Runtime.Remoting.Metadata.W3cXsd2001;en la parte superior, el cuerpo del método puede ser más fácil de leer:

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

Obviamente, pero para completar, en el contexto de OP se usaría como:

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

No sé nada sobre cadenas hexadecimales de 16 caracteres ...

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

Pero aquí está el mío para crear hash MD5 en una línea.

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