2010-09-01 18 views
14

Quelle est la meilleure solution en C# pour calculer un hachage md5 "à la volée" comme un hachage de longueur inconnue? Plus précisément, je veux calculer un hachage à partir des données reçues sur le réseau. Je sais que j'ai fini de recevoir des données lorsque l'expéditeur met fin à la connexion, donc je ne connais pas la longueur à l'avance. [EDIT] - Actuellement, j'utilise md5, mais cela nécessite un second passage sur les données après qu'il a été enregistré et écrit sur le disque. Je préférerais le mettre en place à mesure qu'il arrive du réseau.Calculer un hachage à partir d'un flux de longueur inconnue en C#

Répondre

43

MD5, comme les autres fonctions de hachage, ne nécessite pas deux passes.

Pour commencer:

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

Comme chaque bloc de données arrive:

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

Pour terminer et récupérer le hachage:

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

Ce modèle fonctionne pour tout type dérivé de HashAlgorithm, y compris MD5CryptoServiceProvider et SHA1Managed.

HashAlgorithm définit également une méthode ComputeHash qui prend un objet Stream; cependant, cette méthode va bloquer le thread jusqu'à ce que le flux soit consommé. L'utilisation de l'approche TransformBlock permet un "hachage asynchrone" qui est calculé lorsque les données arrivent sans utiliser de thread.

+0

j'avais vu ces méthodes, mais jamais enquêté sur ce qu'ils ont fait. Honte sur moi. Cela ressemble à ça va marcher. – jjxtra

7

Suite à @ réponse de peter-mourfield, est le code ici qui utilise 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; 
    } 
} 

Étant donné que le flux ainsi que MD5 mettre en œuvre IDisposible, vous devez utiliser using(...){...}

Le méthode dans l'exemple de code renvoie la même chaîne que celle utilisée pour la somme de contrôle MD5 dans Azure Blob Storage.

1

Nécromage.

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

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