在流上腌制C#MD5 ComputeHash

我看不出任何方法来加密MD5.ComputeHash(Stream)。 我错过了一些将字节注入HashAlgorithm的方法吗?

我在执行流计算之前尝试执行ComputeHash(byte []),但不出所料,它没有任何效果。 任何想法(除了修改文件)?

谢谢你的时间。

附录只是为了更具体一点,我想使用一个流来获取我不想加载到内存中的大文件的哈希值。

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

在我看来,缺乏例子的答案是:你真的不需要加盐。

像MD5这样的散列算法采用任意长度的字节表并将其转换为已知长度的字节表 – 操作不容易反转,输入表的小变化会导致输出表中出现不可预测的变化:

input => MD5 =>输出

salting的目的是防止攻击,其中用户已经预先计算了哈希结果表 ( 彩虹表 )。 通过在输入中引入微小的变化,结果会发生巨大变化,因此即使攻击者知道散列结果和盐,也很难猜测输入:

输入+盐=> MD5 =>输出

散列文件的原因是计算校验和。 例如,您在网页上发布文件以及哈希结果。 然后,用户下载文件,通过MD5运行,并将结果与​​发布的结果进行比较。 篡改文件非常困难,因为每次操作都会改变生成的哈希值。

此处不需要Salting,因为您必须使用生成的哈希值发布salt,以便用户可以重复哈希操作。

如果你真的需要引入salting,只需以可重复的方式更改输入流,例如为每个字节添加一个(带溢出)。

这是正确的方法:

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

您可以考虑使用HMACMD5类并设置Key属性。 一般来说,我会使用HMAC而不是标准哈希函数,因为它们提供了更好的安全性。

我想你可以使用如下语法:

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

为了避免像Dabblernl的解决方案一样将所有文件拉入内存,您将需要使用FileStream,如在C#中的大文件的计算MD5SUM中讨论的那样,但MD5CryptoServiceProvider不允许您向末尾添加额外数据。

因此,您需要一个合并的流,如下所示:

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

然后您可以使用这样来为您提供文件哈希值

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

使用ToAnsiiBytes和PrintHash只是实用function:

  static void HashAndPrint(TextWriter op, string text) { MD5 md5 = new MD5CryptoServiceProvider(); byte[] bytes = ToAnsiiBytes(text); byte[] hash = md5.ComputeHash(bytes); PrintHash(Console.Out, hash); Console.Out.WriteLine( " = {0}", text); } 

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

当文件c:\ text.txt包含文本toto时,您可以运行此代码以查看文件+ salt与文本“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