2009-11-11 10 views
5

Ich schreibe eine C# -Routine, die Hashes aus JPG-Dateien erstellt. Wenn ich ein Byte-Array an mein SHA512-Objekt übergebe, erhalte ich das erwartete Verhalten. Wenn ich jedoch einen Speicherstream übergebe, werden die beiden Dateien immer auf denselben Wert gerastert.Warum werden diese beiden Dateien bei der Verwendung von MemoryStream auf den gleichen Wert gesetzt?

Beispiel 1:

 SHA512 mySHA512 = SHA512.Create(); 

     Image img1 = Image.FromFile(@"d:\img1.jpg"); 
     Image img2 = Image.FromFile(@"d:\img2.jpg"); 
     MemoryStream ms1 = new MemoryStream(); 
     MemoryStream ms2 = new MemoryStream(); 

     img1.Save(ms1, ImageFormat.Jpeg); 
     byte[] buf1 = ms1.GetBuffer(); 
     byte[] hash1 = mySHA512.ComputeHash(buf1); 

     img2.Save(ms2, ImageFormat.Jpeg); 
     byte[] buf2 = ms2.GetBuffer(); 
     byte[] hash2 = mySHA512.ComputeHash(buf2); 

     if (Convert.ToBase64String(hash1) == Convert.ToBase64String(hash2)) 
      MessageBox.Show("Hashed the same"); 
     else 
      MessageBox.Show("Different hashes"); 

Das "Different Hashes" produziert. Aber eine der Überladungen der ComputeHash-Methode verwendet ein Stream-Objekt und ich würde das lieber verwenden. Wenn ich das tue:

 SHA512 mySHA512 = SHA512.Create(); 

     Image img1 = Image.FromFile(@"d:\img1.jpg"); 
     Image img2 = Image.FromFile(@"d:\img2.jpg"); 
     MemoryStream ms1 = new MemoryStream(); 
     MemoryStream ms2 = new MemoryStream(); 

     img1.Save(ms1, ImageFormat.Jpeg); 
     byte[] hash1 = mySHA512.ComputeHash(ms1); 

     img2.Save(ms2, ImageFormat.Jpeg); 
     byte[] hash2 = mySHA512.ComputeHash(ms2); 

     if (Convert.ToBase64String(hash1) == Convert.ToBase64String(hash2)) 
      MessageBox.Show("Hashed the same"); 
     else 
      MessageBox.Show("Different hashes"); 

Das produziert "Hashed the selbe".

Was passiert hier, dass ich vermisse?

+0

Sie sind keine Kopien des _same_ Bildes, oder? –

+0

Was passiert, wenn Sie nach dem .Save-Aufruf den Anfang des Streams suchen? z.B. ms1.Seek (0, SeekOrigin.Begin); – Joe

+0

In diesem Fall könnten Sie 'mySHA512.ComputeHash.ComputeHash (ms1.GetBuffer(), 0, (int) ms1.Length)' verwenden. Vermeidet unnötige Kopien – CodesInChaos

Antwort

14

Sie spulen Ihre MemoryStreams nicht zurück, daher wird der Hashwert aus einer leeren Bytefolge berechnet. Verwendung

ms1.Position = 0; 
ms2.Position = 0; 

nach dem Aufruf Save. Ein weiterer Hinweis: GetBuffer auf diese Weise nicht verwenden Verwenden Sie ToArray, die Ihnen ein Byte-Array die gleiche Größe wie die Länge des Streams geben wird - GetBuffer gibt den Raw-Puffer zurück, der (normalerweise) eine Auffüllung haben wird, die Sie nicht versehentlich verwenden möchten. Sie können GetBuffer verwenden, wenn Sie dann sicherstellen, dass Sie nur den relevanten Teil davon natürlich verwenden - dies vermeidet das Erstellen einer neuen Kopie der Daten.

+0

Danke für den Hinweis, das funktioniert! –