2009-05-18 8 views
3

MD5.ComputeHash(ストリーム)をソルトする方法がありません。 HashAlgorithmにバイトを挿入する方法がありませんか?ストリームでC#MD5 ComputeHashをソートする

ストリーム計算を実行する前にComputeHash(byte [])を実行しようとしましたが、意外にも効果がありませんでした。任意のアイデア(ファイルの変更は別として)?

お時間をいただきありがとうございます。

補遺 ただ、もう少し具体的には、私は私がメモリにロードしたくない大容量のファイルのハッシュを取得するためのストリームを使用します。

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

塩アルゴリズムをする特定の方法があるかどうか、私は知りません。しかし、Streamオブジェクトをラップする独自のStreamクラスを簡単に作成できます。最初の数バイトを要求されると、ラッパーオブジェクトはソルトバイトを与えてから、基礎となるストリームバイトを取得することができます。 –

+0

この場合、与えられた情報で、塩は不要で、おそらく実装が不可能です(saltは塩析データと一緒に*保存する必要があります)。 – yfeldblum

答えて

1

私はあなたのような構文を使用することができると思う:

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

例の欠如への答えは私の意見である:あなたは本当に塩にそれを必要としません。

MD5のようなハッシュアルゴリズムは、任意の長さのバイトテーブルを取り、既知の長さのバイトテーブルに変換します。操作は簡単には可逆ではなく、入力テーブルの小さな変更は出力テーブルに予期しない変更を引き起こします。

入力=> MD5 =>出力

塩析の目的は、ユーザが、ハッシュ結果の既に事前計算テーブル(rainbow tables)を有している攻撃に対する保護です。入力の小さな変化を導入することにより、結果が大幅に変更されているので、攻撃者がハッシュ結果と塩を知っていたとしても、入力を推測することは非常に困難である:

入力+塩=> MD5 =>出力

ファイルをハッシュする理由は、チェックサムを計算するためです。例えば。ハッシュ結果とともにWebページにファイルを公開します。ユーザーはファイルをダウンロードし、MD5で実行し、その結果を公開された結果と比較します。ファイルを改ざんするのは非常に難しいでしょう。なぜなら、それぞれの操作によって結果のハッシュが変更されるからです。

ここでは、ユーザーがハッシング操作を繰り返すことができるように、結果のハッシュでソルトを公開する必要があるため、ここでソルトする必要はありません。

実際に塩析を導入する必要がある場合は、入力ストリームを反復可能な方法で変更してください。各バイトに1つ(オーバーフローで)を追加します。

+1

また、格納されたMD5ハッシュと計算されたMD5を比較することによってファイルが変更されないようにしたい場合もあります。 塩を使用することで、既知のMD5を開いた状態で保存できます。塩がなければ、ユーザーはMD5を再計算して交換することができ、変更は検出されません。 皆、お答えしていただきありがとうございます。 –

+2

このコメントで私はまだ明確ではない。ハッシュを「開いた状態で」保存し、攻撃者が塩の秘密を保持することによってそれを突き止めることができないようにします。しかし、人々はハッシュを検証するために塩を知る必要があります。本当に欲しいのはデジタル署名だと思います。 (攻撃者があらゆる種類の完全性証明書を変更することは、かなり激しいサービス拒否の脆弱性を引き起こします。) –

0

Dabblernlのソリューションのようにすべてのファイルをメモリにプルするのを避けるには、このSOの質問Computing MD5SUM of large files in C#で議論されているようにFileStreamを使用したいが、MD5CryptoServiceProviderでは余分なデータを最後まで追加することはできません。

したがって、あなたがこのようなマージされたストリームを必要とする:

あなたは、あなたのようなToAnsiiBytesとPrintHashだけというユーティリティ関数でハッシュ

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

を提出塩には、このように使用することができます

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

を:

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

時にファイルc:TEXT.TXTテキストTOTOが含まれています\、ファイル+塩は、テキスト「totoSALT」これで

 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"); 

と同じに等しいことを確認するためにこのコードを実行することができます出力

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

あなたはHMACMD5クラスを使用して、代わりにKeyプロパティを設定することを検討することがあります。一般的に、HMACは標準のハッシュ関数ではなく、セキュリティが少し向上しているので、HMACを使用します。

4

これはそれを行うための正しい方法である:

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; 
    } 
関連する問題