Entwickler-Ecke

IO, XML und Registry - SHA512 einer Datei ermitteln


JackCoder - Di 20.05.14 22:08
Titel: SHA512 einer Datei ermitteln
Hallo,
ich möchte von einigen (auch größeren) Dateien den SHA512-Hash ermitteln. Nun habe ich dazu einige Fragen.
Ich habe bereits im Internet einige Lösungen gefunden. Dabei ist mir aufgefallen, dass immer wieder unterschiedliche Konstruktoren benutzt werden:


C#-Quelltext
1:
SHA512 sha512 = SHA512.Create();                    

oder

C#-Quelltext
1:
SHA512Managed sha512 = new SHA512Managed();                    

usw... Was ist der unterschied zwischen diesen Klassen und welche sollte ich nehmen?

Zudem habe ich im Internet folgende Lösung gefunden:

C#-Quelltext
1:
2:
3:
4:
5:
using (FileStream stream = File.OpenRead(file))
    {
        SHA512Managed sha = new SHA512Managed();
        byte[] hash = sha.ComputeHash(stream);
    }


Dazu hat man mir gesagt, es sei die langsamste Art (also eine Datei Bitweise einzulesen) um einen Hash zu berechnen. Ich sollte stattdessen mit Chunks arbeiten. Wie mache ich das?
Kann mir jemand helfen??


Th69 - Mi 21.05.14 10:44

Hallo JackCoder :welcome:

du beziehst dich wohl auf deinen Beitrag myCSharp.de - Feedback: Was haltet ihr von meinem Code der eine Verzeichnisstruktur in eine Datei schreibt? [http://www.mycsharp.de/wbb2/thread.php?threadid=111744] ?

Bzgl. der Konstruktoren gibt es keinen relevanten Unterschied, da SHA512Managed die Implementierung der abstrakten Basisklasse SHA512 ist und beide daher eine SHA512Managed-Instanz zurückgeben, s.a. MSDN SHA512.Create [http://msdn.microsoft.com/de-de/library/hydyw22a%28v=vs.110%29.aspx] und SHA512 [http://msdn.microsoft.com/de-de/library/system.security.cryptography.sha512%28v=vs.110%29.aspx] (unter "Hinweise" bzw. englisch "Remarks").

Und zum chunk-weisen Hashen s. z.B. Hashing Data In Chunks Using .NET [http://www.level533.com/2011/01/hashing-data-in-chunks-using-net/] oder How to compute hash of a large file chunk? [http://stackoverflow.com/questions/20634827/how-to-compute-hash-of-a-large-file-chunk].

Ob jedoch das chunk-weise Verarbeiten wirklich schneller ist, als die Datei als Stream zu bearbeiten, wirst du wohl nur durch Tests rauskriegen.

Einzig jedoch das Rauschreiben des Hashwerts in die Datei mittels

C#-Quelltext
1:
foreach(byte hashSubstring in sha512Hash) File.AppendAllText(pathFileList, Convert.ToString(hashSubstring, 16));                    

solltest du so optimieren, daß zuerst der String berechnet wird und erst abschließend dieser Hash-String als ganzes in die Datei geschrieben wird (IO-Operationen sind immer teuer).


JackCoder - Mi 21.05.14 16:36

Vielen Dank für deine Antwort, ich habe mal ein paar Tests gemacht:
Ohne Chunks zu benutzten, brauche ich um eine bestimmte Datei zu hashen ca. 900ms.
Dann habe ich mit Chunks gearbeitet. Nun hängt die Zeit ganz komisch von der Größe des Buffers ab:
Mache ich das Array 1024 Felder groß, benötigt die Software ca 700ms, nehme ich z.B. 21, brauch das Programm nur 10 MS zum hashen. Komischerweise braucht es bei 22 wieder 700ms. Was geht hier vor? :D
Ich habe die Zeit bisher mit DateTime.Now gemessen und den Unterschied berechnet, geht da vielleicht was schief?


Ralf Jansen - Mi 21.05.14 16:47

Zum Zeitmessen bietet sich die StopWatch [http://msdn.microsoft.com/en-us/library/system.diagnostics.stopwatch.aspx] an.
Um deine Ergebinsse einschätzen zu können wäre es darüber hinaus hilfreich auch zu sehen was du gemacht hast.


JackCoder - Mi 21.05.14 16:52


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
static void Main(string[] args)
        {
            DateTime Time1 = DateTime.Now;
            string sFile = @"C:\test.txt";

            // Use a file as an input stream, but we can pretend that it is something like a response stream from 
            // a web request.
            using (SHA512 md5 = SHA512.Create())
            using (Stream input = File.OpenRead(sFile))
            {
                // small enough buffer to make us read the file in chunks
                byte[] buffer = new byte[BUFFER_SIZE];
                int bytesRead;

                // open the file, 
                while ((bytesRead = input.Read(buffer, 0, buffer.Length)) > 0)
                {
                    // hash each chunk at a time.
                    md5.TransformBlock(buffer, 0, bytesRead, null0);
                }

                // We need this, even though no data is hashed.  Do not
                // pass null for the buffer
                md5.TransformFinalBlock(buffer, 00);

                byte[] hashVal = md5.Hash;

                // convert the hash value to a nice string, something like would see on a download site or 
                // get from the Microsoft hasing utility, fciv.exe.
                StringBuilder sbHash = new StringBuilder(hashVal.Length * 2);
                int idxMax = hashVal.Length;
                for (int idx = 0; idx < idxMax; ++idx)
                {
                    sbHash.Append(hashVal[idx].ToString("x2"));
                }

                Console.WriteLine(sbHash.ToString());
                DateTime Time2 = DateTime.Now;
                TimeSpan timeSpan = Time2 - Time1;
                Console.WriteLine(timeSpan.Milliseconds);
            }


So sieht es im Moment bei mir aus.



EDIT:
Habs jetzt mit StopWatch gemacht, ich bekomme die selben Ergebnisse.:/


Ralf Jansen - Mi 21.05.14 17:13

Sehe keinen Grund warum da bei verschiedenen Blockgrößen große Unterschiede, schon gar nicht die von dir beobachteten, herauskommen sollten. Außer vielleicht bei extrem kleinen Blöcken oder bei Extrem großen dateien wo auch kleine Unterschiede im Promille Bereich sich zu meßbaren Größen addieren. Wenn du zwischendurch mal ~abweichende~ Werte siehst würde ich von äußeren Einflüssen ausgehen. Zum Beispiel das die Datei einmal aus dem Filecache kommt das andere mal von der Platte, Hackler bei der Consolenausgabe du misst ja einen Console.WriteLine mit, irgendwelche Dinge die Windows nebenbei erledigt u.s.w.


JackCoder - Do 22.05.14 11:16

Danke für deine Antwort, ich habe mich dann dafür entschieden ein paar Tests zu machen.
Ich habe jeweils 1000 mal die Dauer gemessen und den Durchschnitt berechnet. Ob ich nun mit Chunks (egal welche Buffer-Größe) oder mit dem Stream arbeite, es dauert alles gleich lange.
Ich entscheide mich dann wohl für die Stream-Methode, die ist etwas kürzer.
Viele Grüße