Hache SHA1 fichiers volumineux (plus de 2 Go) en C #

Je suis à la recherche d’une solution pour le hachage du contenu de fichiers volumineux (les fichiers peuvent contenir plus de 2 Go en 32 bits). Y at-il une solution facile pour cela? Ou simplement lire par partie et charger dans le tampon?

La solution de Driis semble plus flexible, mais HashAlgorithm.ComputeHash accepte également les parameters de Stream .

Utilisez TransformBlock et TransformFinalBlock pour calculer le hachage bloc par bloc afin que vous n’ayez pas besoin de lire le fichier entier en mémoire. (Il y a un bel exemple dans le premier lien – et un autre dans la question précédente ).

Si vous choisissez d’utiliser TransformBlock , vous pouvez ignorer le dernier paramètre en toute sécurité et définir le paramètre outputBuffer sur null . TransformBlock va copier de l’entrée vers le tableau de sortie – mais pourquoi voudriez-vous simplement copier des bits sans raison valable?

De plus, tous les algorithmes HashAlgorithms de mscorlib fonctionnent comme prévu: la taille du bloc ne semble pas affecter la sortie du hachage; et si vous transmettez les données dans un tableau, puis le hachage en morceaux en modifiant le inputOffset ou le hachage en transmettant des tableaux plus petits et séparés, peu importe. J’ai vérifié cela en utilisant le code suivant:

(c’est un peu long, juste ici pour permettre aux gens de vérifier par eux-mêmes que les implémentations de HashAlgorithm sont saines).

 public static void Main() { RandomNumberGenerator rnd = RandomNumberGenerator.Create(); byte[] input = new byte[20]; rnd.GetBytes(input); Console.WriteLine("Input Data: " + BytesToStr(input)); var hashAlgoTypes = Assembly.GetAssembly(typeof(HashAlgorithm)).GetTypes() .Where(t => typeof(HashAlgorithm).IsAssignableFrom(t) && !t.IsAbstract); foreach (var hashType in hashAlgoTypes) new AlgoTester(hashType).AssertOkFor(input.ToArray()); } public static ssortingng BytesToStr(byte[] bytes) { SsortingngBuilder str = new SsortingngBuilder(); for (int i = 0; i < bytes.Length; i++) str.AppendFormat("{0:X2}", bytes[i]); return str.ToString(); } public class AlgoTester { readonly byte[] key; readonly Type type; public AlgoTester(Type type) { this.type=type; if (typeof(KeyedHashAlgorithm).IsAssignableFrom(type)) using(var algo = (KeyedHashAlgorithm)Activator.CreateInstance(type)) key = algo.Key.ToArray(); } public HashAlgorithm MakeAlgo() { HashAlgorithm algo = (HashAlgorithm)Activator.CreateInstance(type); if (key != null) ((KeyedHashAlgorithm)algo).Key = key; return algo; } public byte[] GetHash(byte[] input) { using(HashAlgorithm sha = MakeAlgo()) return sha.ComputeHash(input); } public byte[] GetHashOneBlock(byte[] input) { using(HashAlgorithm sha = MakeAlgo()) { sha.TransformFinalBlock(input, 0, input.Length); return sha.Hash; } } public byte[] GetHashMultiBlock(byte[] input, int size) { using(HashAlgorithm sha = MakeAlgo()) { int offset = 0; while (input.Length - offset >= size) offset += sha.TransformBlock(input, offset, size, input, offset); sha.TransformFinalBlock(input, offset, input.Length - offset); return sha.Hash; } } public byte[] GetHashMultiBlockInChunks(byte[] input, int size) { using(HashAlgorithm sha = MakeAlgo()) { int offset = 0; while (input.Length - offset >= size) offset += sha.TransformBlock(input.Skip(offset).Take(size).ToArray() , 0, size, null, -24124512); sha.TransformFinalBlock(input.Skip(offset).ToArray(), 0 , input.Length - offset); return sha.Hash; } } public void AssertOkFor(byte[] data) { var direct = GetHash(data); var indirect = GetHashOneBlock(data); var outcomes = new[] { 1, 2, 3, 5, 10, 11, 19, 20, 21 }.SelectMany(i => new[]{ new{ Hash=GetHashMultiBlock(data,i), Name="ByMSDN"+i}, new{ Hash=GetHashMultiBlockInChunks(data,i), Name="InChunks"+i} }).Concat(new[] { new { Hash = indirect, Name = "OneBlock" } }) .Where(result => !result.Hash.SequenceEqual(direct)).ToArray(); Console.Write("Testing: " + type); if (outcomes.Any()) { Console.WriteLine("not OK."); Console.WriteLine(type.Name + " direct was: " + BytesToStr(direct)); } else Console.WriteLine(" OK."); foreach (var outcome in outcomes) Console.WriteLine(type.Name + " differs with: " + outcome.Name + " " + BytesToStr(outcome.Hash)); } }