2010-09-01 34 views
14

¿Cuál es la mejor solución en C# para calcular un md5 "sobre la marcha" como hash de una secuencia de longitud desconocida? Específicamente, quiero calcular un hash a partir de los datos recibidos a través de la red. Sé que he terminado de recibir datos cuando el remitente finaliza la conexión, por lo que no sé la longitud por adelantado.Calcule un hash de una secuencia de longitud desconocida en C#

[EDITAR] - En este momento estoy usando md5, pero esto requiere un segundo pase sobre los datos después de que se haya guardado y escrito en el disco. Prefiero ponerlo en su lugar, ya que viene de la red.

Respuesta

43

MD5, al igual que otras funciones hash, no requiere dos pasadas.

Para empezar:

HashAlgorithm hasher = ..; 
hasher.Initialize(); 

Como cada bloque de datos llega:

byte[] buffer = ..; 
int bytesReceived = ..; 
hasher.TransformBlock(buffer, 0, bytesReceived, null, 0); 

hasta el final y recuperar el hash:

hasher.TransformFinalBlock(new byte[0], 0, 0); 
byte[] hash = hasher.Hash; 

Este modelo funciona para cualquier tipo derivado de HashAlgorithm, incluidos MD5CryptoServiceProvider y SHA1Managed.

HashAlgorithm también define un método ComputeHash que toma un objeto Stream; sin embargo, este método bloqueará el hilo hasta que se consuma el flujo. El uso del método TransformBlock permite un "hash asíncrono" que se calcula a medida que llegan los datos sin utilizar un subproceso.

+0

que había visto esos métodos, pero nunca investigado lo que hicieron. Me avergüenza. Parece que funcionará. – jjxtra

7

Además de @ respuesta de Pedro-mourfield 's, aquí está el código que utiliza ComputeHash():

private static string CalculateMd5(string filePathName) { 
    using (var stream = File.OpenRead(filePathName)) 
    using (var md5 = MD5.Create()) { 
    var hash = md5.ComputeHash(stream); 
    var base64String = Convert.ToBase64String(hash); 
    return base64String; 
    } 
} 

Dado que tanto la corriente, así como MD5 implementan IDisposible, es necesario utilizar using(...){...}

El método en el ejemplo de código devuelve la misma cadena que se utiliza para la suma de comprobación MD5 en Azure Blob Storage.

1

Nigromanciación.

Dos possibilitites en C# .NET Core:

private static System.Security.Cryptography.HashAlgorithm GetHashAlgorithm(System.Security.Cryptography.HashAlgorithmName hashAlgorithmName) 
{ 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.MD5) 
     return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.MD5.Create(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA1) 
     return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA1.Create(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA256) 
     return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA256.Create(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA384) 
     return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA384.Create(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA512) 
     return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA512.Create(); 

    throw new System.Security.Cryptography.CryptographicException($"Unknown hash algorithm \"{hashAlgorithmName.Name}\"."); 
} 


protected override byte[] HashData(System.IO.Stream data, 
    System.Security.Cryptography.HashAlgorithmName hashAlgorithm) 
{ 
    using (System.Security.Cryptography.HashAlgorithm hashAlgorithm1 = 
    GetHashAlgorithm(hashAlgorithm)) 
    return hashAlgorithm1.ComputeHash(data); 
} 

o con BouncyCastle:

private static Org.BouncyCastle.Crypto.IDigest GetBouncyAlgorithm(
    System.Security.Cryptography.HashAlgorithmName hashAlgorithmName) 
{ 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.MD5) 
     return new Org.BouncyCastle.Crypto.Digests.MD5Digest(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA1) 
     return new Org.BouncyCastle.Crypto.Digests.Sha1Digest(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA256) 
     return new Org.BouncyCastle.Crypto.Digests.Sha256Digest(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA384) 
     return new Org.BouncyCastle.Crypto.Digests.Sha384Digest(); 
    if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA512) 
     return new Org.BouncyCastle.Crypto.Digests.Sha512Digest(); 

    throw new System.Security.Cryptography.CryptographicException(
     $"Unknown hash algorithm \"{hashAlgorithmName.Name}\"." 
    ); 
} // End Function GetBouncyAlgorithm 



protected override byte[] HashData(System.IO.Stream data, 
    System.Security.Cryptography.HashAlgorithmName hashAlgorithm) 
{ 
    Org.BouncyCastle.Crypto.IDigest digest = GetBouncyAlgorithm(hashAlgorithm); 

    byte[] buffer = new byte[4096]; 
    int cbSize; 
    while ((cbSize = data.Read(buffer, 0, buffer.Length)) > 0) 
     digest.BlockUpdate(buffer, 0, cbSize); 

    byte[] hash = new byte[digest.GetDigestSize()]; 
    digest.DoFinal(hash, 0); 
    return hash; 
} 
Cuestiones relacionadas