Calcola un hash MD5 da una stringa


131

Uso il seguente codice C # per calcolare un hash MD5 da una stringa. Funziona bene e genera una stringa esadecimale di 32 caratteri come questa: 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...

Esiste un modo per utilizzare codice come questo per generare una stringa esadecimale di 16 caratteri (o stringa di 12 caratteri)? Una stringa esadecimale di 32 caratteri è buona ma penso che sarà noioso inserire il codice per il cliente!


7
perché hai bisogno che il cliente entri nell'esagono?
Dan Dinu,

5
Penso che voglia generare una chiave seriale
Thiago il

Risposte:


197

Secondo MSDN

Crea 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
Dovresti sempre dire da dove ottieni il codice se copi / incolla da qualche parte, altrimenti è classificato come plagio.
DavidG

1
La classe MD5 implementa IDisposable, ricorda di disporre l'istanza. ;)
Paolo Iommarini,

5
In generale dovresti avere una codifica di testo senza perdita di dati, come UTF8.
Oliver Bock

5
@PrashantPimpale MD5 è un algoritmo digest. Pensa a come convertire una mucca in una bistecca.
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
La mia risposta non è stata quella di indicare le migliori pratiche. È stato previsto nel contesto che l'OP aveva formulato la sua domanda. Se l'OP avesse chiesto qual è l'algoritmo di hashing più appropriato da utilizzare, la risposta sarebbe stata diversa (di conseguenza).
Michael,

8
Apprezzo il voto negativo per qualcosa che è stato escluso dal contesto per un thread che ha più di due anni. ;)
Michael,

Perché "simile al formato UNIX"? Cosa non è esattamente lo stesso?
Igor Gatis,

questo dà risultati diversi dai controllori md5 online. o sono solo io??
bh_earth0,

@ bh_earth0 sembra che BitConverternon funziona allo stesso modo su Windows e Linux, vedere questa domanda: stackoverflow.com/questions/11454004/...
eddyP23

10

Stavo cercando di creare una rappresentazione in formato stringa dell'hash MD5 usando LINQ, tuttavia, nessuna delle risposte erano soluzioni LINQ, quindi aggiungendo questo allo smorgasbord delle soluzioni disponibili.

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

One-liner, nella sintassi del metodo:return string.Join( "", hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );
Marc.2377,

... in tal caso, propongo return string.Concat( hash.ComputeHash( Encoding.UTF8.GetBytes(observedText) ).Select( x => x.ToString("x2") ) );invece. È un'intenzione un po 'più breve, forse più chiara, e funziona leggermente più velocemente (aumento del <10% perf.).
Marc.2377,

9

Dipende interamente da ciò che stai cercando di ottenere. Tecnicamente, potresti semplicemente prendere i primi 12 caratteri dal risultato dell'hash MD5, ma la specifica di MD5 è di generare un 32 caratteri.

Ridurre la dimensione dell'hash riduce la sicurezza e aumenta le possibilità di collisioni e di rottura del sistema.

Forse se ci fai sapere di più su ciò che stai cercando di ottenere, potremmo essere in grado di aiutare di più.


+1 Questa è la risposta, ma anch'io metto davvero in dubbio la sua sicurezza.
lc.

grazie per la tua risposta. e scusa per la mia cattiva spiegazione. Voglio pubblicare un'applicazione per Windows, l'utente deve acquistare la licenza per utilizzare la mia applicazione, quindi la mia applicazione richiede due campi: USERNAME: ... e KEY: .... Voglio eseguire l'hashing di USERNAME e creare il KEY , quindi l'utente deve inserire USERNAME e KEY specifici. il mio problema qui è che il KEY dovrebbe essere di 12 caratteri, (ma nell'hash MD5, ottengo il KEY a 32 caratteri). per favore aiutami, ne ho davvero bisogno.
Muhamad Jafarnejad,

8

È possibile utilizzare Convert.ToBase64Stringper convertire l'output a 16 byte di MD5 in una stringa di caratteri ~ 24. Un po 'meglio senza ridurre la sicurezza. ( j9JIbSY8HuT89/pwdC8jlw==per il tuo esempio)


2
Una bella soluzione, ma dubito che OP vorrà avere la distinzione tra maiuscole e minuscole e con caratteri speciali ...
KingCronus

5

Supporto stringa e flusso di file.

esempi

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

Suppongo che sia meglio usare la codifica UTF-8 nella stringa 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();
    }
}

3

Un hash MD5 ha 128 bit, quindi non puoi rappresentarlo in esadecimale con meno di 32 caratteri ...


Ok, mi manca qualcosa qui. Come?
lc.

@lc., scusa, c'era un errore di battitura nella mia risposta, avevo scritto "can" invece di "can" ...
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

Un'alternativa più rapida della risposta esistente per .NET Core 2.1 e versioni successive:

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

Puoi ottimizzarlo ancora di più se sei sicuro che le tue stringhe sono abbastanza piccole e sostituiscono la codifica.GetBytes con insicuro int GetBytes (caratteri ReadOnlySpan, byte span).


3

Questa soluzione richiede c # 8 e ne sfrutta Span<T>. Nota, dovrai comunque chiamare .Replace("-", string.Empty).ToLowerInvariant()per formattare il risultato, se necessario.

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

            }

0

Vorrei offrire un'alternativa che sembra funzionare almeno il 10% più velocemente della risposta di Craigdfrench nei miei test (.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 si preferisce avere using System.Runtime.Remoting.Metadata.W3cXsd2001;in cima, il metodo corporeo può essere reso più facile da leggere con una sola riga:

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

Abbastanza ovvio, ma per completezza, nel contesto di OP sarebbe usato come:

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

0

Idk qualsiasi cosa su stringhe esadecimali di 16 caratteri ....

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

Ma ecco il mio per creare l'hash MD5 in una riga.

string hash = BitConverter.ToString(MD5.Create().ComputeHash(Encoding.ASCII.GetBytes("THIS STRING TO MD5"))).Replace("-","");
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.