2009-05-18 4 views
3

Ich sehe keine Möglichkeit, eine MD5.ComputeHash (Stream) zu salzen. Fehle mir eine Möglichkeit, Bytes in den HashAlgorithm zu injizieren?Saling ein C# MD5 ComputeHash in einem Stream

Ich habe versucht, einen ComputeHash (byte []) durchzuführen, bevor ich die Stream-Berechnung durchführte, aber es war nicht überraschend, dass es keinen Effekt hatte. Irgendwelche Ideen (abgesehen von der Änderung der Datei)?

Danke für Ihre Zeit.

Nachtrag Nur ein wenig genauer zu sein, möchte ich einen Stream verwenden, um einen Hash, der auf einer großen Datei zu erhalten, die ich will nicht in den Speicher laden.

FileInfo myFI= new FileInfo("bigfile.dat"); 
FileStream myIFS = piFile.OpenRead(); 
MD5 md5 = MD5.Create(); 
byte[] hash = md5.ComputeHash (myIFS); 
myIFS.Close(); 
+0

Ich weiß nicht, ob es eine bestimmte Art und Weise zu Salz ist der Algorithmus. Sie können jedoch problemlos Ihre eigene Stream-Klasse erstellen, die das angegebene Stream-Objekt umschließt. Wenn nach den ersten paar Bytes gefragt wird, könnte das Wrapper-Objekt die Salz-Bytes geben und dann beginnen, die zugrunde liegenden Stream-Bytes zu liefern. –

+0

In diesem Fall, mit den gegebenen Informationen, ist ein Salz unnötig und wahrscheinlich nicht möglich zu implementieren (erinnern Sie sich, dass Salze * mit * den Salzhash-Daten gespeichert werden müssen). – yfeldblum

Antwort

1

glaube ich Ihnen eine Syntax verwenden können, wie:

byte[] saltedBytes; 
//TODO: fill the saltedBytes; 
var hasher=new MD5CryptoServiceProvider(); 
var memoryStream=new MemoryStream(saltedBytes); 
hasher.ComputeHash(memoryStream); 
memoryStream.Close; 
5

Die Antwort auf den Mangel an Beispielen meiner Meinung nach ist: Sie nicht wirklich zu Salz brauchen.

Der Hashalgorithmus wie MD5 nimmt eine Tabelle von Bytes beliebiger Länge und konvertiert sie in eine Tabelle von Bytes bekannter Länge - die Operation ist nicht leicht umkehrbar und kleine Änderungen an der Eingabetabelle verursachen unvorhersehbare Änderungen in der Ausgabetabelle:

input => MD5 => Ausgabe

der Zweck des Salzens Schutz gegen Angriffe ist, wo der Benutzer bereits im voraus berechnete Tabelle von Hash-Ergebnissen hat (rainbow tables). Durch die Einführung von kleinen Änderungen des Eingang, sind die Ergebnisse drastisch ändern, so dass selbst wenn Angreifer das Hash-Ergebnis und das Salz wissen, es ist sehr schwierig, den Eingang zu erraten:

Eingang + Salz => MD5 => Ausgang

Der Grund für Hashing-Dateien besteht darin, eine Prüfsumme zu berechnen. Z.B. Sie veröffentlichen eine Datei auf Ihrer Webseite zusammen mit dem Hash-Ergebnis. Der Benutzer lädt dann eine Datei herunter, führt sie durch MD5 und vergleicht das Ergebnis mit Ihrem veröffentlichten Ergebnis. Es wäre sehr schwierig, die Datei zu manipulieren, da jede Manipulation den resultierenden Hash ändern würde.

Salzen ist hier nicht notwendig, weil Sie das Salz mit dem resultierenden Hash veröffentlichen müssten, damit der Benutzer den Hash-Vorgang wiederholen kann.

Wenn Sie wirklich Salzen einführen müssen, ändern Sie einfach den Eingangsstrom in der wiederholbaren Weise, z. füge zu jedem Byte einen (mit Überlauf) hinzu.

+1

Es gibt auch eine Situation, in der Sie verhindern möchten, dass eine Datei geändert wird, indem Sie ihren gespeicherten MD5-Hash mit dem berechneten MD5 vergleichen. Mit Salz können Sie das bekannte MD5 im Freien aufbewahren. Ohne Salz kann der Benutzer das MD5 neu berechnen und ersetzen, so dass keine Änderung erkannt wird. Vielen Dank für die Zeit zu nehmen, um alle zu beantworten. –

+2

Ich bin immer noch nicht klar in diesem Kommentar. Sie möchten den Hash "im Freien" speichern und verhindern, dass ein Angreifer ihn mutieren könnte, indem er das Salz geheim hält. Aber die Leute müssen das Salz kennen, um den Hash zu verifizieren. Es klingt wie, was wirklich eine digitale Signatur gewollt ist. (Obwohl Angreifer jede Art von Integritätsberechtigung ändern können, öffnet sich eine ziemlich eklatante Denial-of-Service-Schwachstelle.) –

0

Um zu vermeiden, ziehen Sie die gesamte Datei in den Speicher wie Dabblernl Lösung wollen Sie einen FileStream verwenden, wie in dieser SO Frage Computing MD5SUM of large files in C# diskutiert, aber der MD5CryptoServiceProvider können Sie keine zusätzlichen Daten am Ende hinzufügen.

So benötigen Sie einen fusionierten Strom wie folgt aus:

public class MergedStream : Stream, IDisposable 
{ 
    Stream s1; 
    Stream s2; 

    public MergedStream(Stream first, Stream second) 
    { 
     s1 = first; 
     s2 = second; 
    } 

    public override int Read(byte[] buffer, int offset, int count) 
    { 
     int s1count = (int)Math.Min((long)count, s1.Length - s1.Position); 
     int bytesRead = 0; 

     if (s1count > 0) 
     { 
      bytesRead += s1.Read(buffer, offset, s1count); 
     } 

     if (s1count < count) 
     { 
      bytesRead += s2.Read(buffer, offset + s1count, count - s1count); 
     } 

     return bytesRead; 
    } 

    public override void Write(byte[] buffer, int offset, int count) 
    { 
     throw new NotImplementedException(); 
    } 

    public override bool CanRead 
    { 
     get { return s1.CanRead && s2.CanRead; } 
    } 

    public override bool CanSeek 
    { 
     get { return s1.CanSeek && s2.CanSeek; } 
    } 

    public override bool CanWrite 
    { 
     get { return s1.CanWrite && s2.CanWrite; } 
    } 

    public override void Flush() 
    { 
     s1.Flush(); 
     s2.Flush(); 
    } 

    public override long Length 
    { 
     get { return s1.Length + s2.Length; } 
    } 

    public override long Position 
    { 
     get 
     { 
      return s1.Position + s2.Position; 
     } 
     set 
     { 
      throw new NotImplementedException(); 
     } 
    } 

    public override long Seek(long offset, SeekOrigin origin) 
    { 
     throw new NotImplementedException(); 
    } 

    public override void SetLength(long value) 
    { 
     throw new NotImplementedException(); 
    } 

    void IDisposable.Dispose() 
    { 
     s1.Dispose(); 
     s2.Dispose(); 
    } 
} 

die Sie dann wie dieses Salz verwenden, können Sie Dateihash

 FileStream fs = new FileStream(@"c:\text.txt", FileMode.Open); 
     var m = new MemoryStream(ToAnsiiBytes("SALT"), false); 
     var ms = new MergedStream(fs, m); 

     var C = hasher.ComputeHash(ms); 
     PrintHash(Console.Out, C); 

mit ToAnsiiBytes und PrintHash nur Nutzenfunktionen als solche zu sein:

und

public static void PrintHash(TextWriter op, byte[] hash) 
    { 
     foreach (byte b in hash) 
     { 
      op.Write("{0:X2}", b); 
     } 
    } 

, wenn die Datei c: \ text.txt enthält den Text toto Sie diesen Code ausführen können, um zu sehen, dass die Datei + Salz der gleiche wie der Text "totoSALT" gleich

 FileStream fs = new FileStream(@"c:\text.txt", FileMode.Open); 

     var hasher = new MD5CryptoServiceProvider(); 
     var A = hasher.ComputeHash(fs); 
     PrintHash(Console.Out, A); 
     Console.Out.WriteLine(); 

     var salt = new byte[] { 0x53, 0x41, 0x4C, 0x54 }; 

     var B = hasher.ComputeHash(ToAnsiiBytes("SALT")); 
     PrintHash(Console.Out, B); 
     Console.Out.WriteLine(); 

     var m = new MemoryStream(ToAnsiiBytes("SALT"), false); 

     fs.Seek(0, SeekOrigin.Begin); 
     var ms = new MergedStream(fs, m); 

     var C = hasher.ComputeHash(ms); 
     PrintHash(Console.Out, C); 
     Console.Out.WriteLine(); 


     HashAndPrint(Console.Out, "toto"); 
     HashAndPrint(Console.Out, "totoSALT"); 
     HashAndPrint(Console.Out, "SALT"); 

mit diesem Ausgabe

F71DBE52628A3F83A77AB494817525C6 
8C4F4370C53E0C1E1AE9ACD577DDDBED 
308DB2451D6580FEEB09FCF2DC1CEE19 
F71DBE52628A3F83A77AB494817525C6 = toto 
308DB2451D6580FEEB09FCF2DC1CEE19 = totoSALT 
8C4F4370C53E0C1E1AE9ACD577DDDBED = SALT 
3

Sie sich anschauen sollten stattdessen die HMACMD5 Klasse und Einstellung der Key Eigenschaft. Im Allgemeinen würde ich mit einem HMAC anstelle der Standard-Hash-Funktion gehen, da sie ein bisschen bessere Sicherheit bieten.

4

das ist der richtige Weg, es zu tun:

private static byte[] _emptyBuffer = new byte[0]; 

    public static byte[] CalculateMD5(Stream stream) 
    { 
     return CalculateMD5(stream, 64 * 1024); 
    } 

    public static byte[] CalculateMD5(Stream stream, int bufferSize) 
    { 
     MD5 md5Hasher = MD5.Create(); 

     byte[] buffer = new byte[bufferSize]; 
     int readBytes; 

     while ((readBytes = stream.Read(buffer, 0, bufferSize)) > 0) 
     { 
      md5Hasher.TransformBlock(buffer, 0, readBytes, buffer, 0); 
     } 

     md5Hasher.TransformFinalBlock(_emptyBuffer, 0, 0); 

     return md5Hasher.Hash; 
    }