C# 从C中长度未知的流计算哈希#
对于计算长度未知的流的“动态”md5类散列,C#中的最佳解决方案是什么?具体地说,我想根据通过网络接收的数据计算一个散列。我知道当发送方终止连接时,我已经接收不到数据了,所以我事先不知道长度C# 从C中长度未知的流计算哈希#,c#,hash,cryptography,stream,C#,Hash,Cryptography,Stream,对于计算长度未知的流的“动态”md5类散列,C#中的最佳解决方案是什么?具体地说,我想根据通过网络接收的数据计算一个散列。我知道当发送方终止连接时,我已经接收不到数据了,所以我事先不知道长度 [编辑]-现在我正在使用md5,并在数据保存并写入磁盘后对其进行第二次传递。我宁愿在它从网络进入时对其进行散列。System.Security.Cryptography.MD5类包含一个ComputeHash方法,该方法采用字节[]或流。签出。MD5与其他哈希函数一样,不需要两次传递 开始: HashAlg
[编辑]-现在我正在使用md5,并在数据保存并写入磁盘后对其进行第二次传递。我宁愿在它从网络进入时对其进行散列。System.Security.Cryptography.MD5类包含一个
ComputeHash
方法,该方法采用字节[]
或流
。签出。MD5与其他哈希函数一样,不需要两次传递
开始:
HashAlgorithm hasher = ..;
hasher.Initialize();
当每个数据块到达时:
byte[] buffer = ..;
int bytesReceived = ..;
hasher.TransformBlock(buffer, 0, bytesReceived, null, 0);
要完成并检索哈希,请执行以下操作:
hasher.TransformFinalBlock(new byte[0], 0, 0);
byte[] hash = hasher.Hash;
此模式适用于从HashAlgorithm
派生的任何类型,包括MD5CryptoServiceProvider
和SHA1Managed
HashAlgorithm
还定义了一个方法ComputeHash
,该方法接受一个流
对象;但是,此方法将阻塞线程,直到流被消耗。使用TransformBlock
方法允许在数据到达时计算“异步哈希”,而不使用线程。进一步了解@peter mourfield的答案,下面是使用ComputeHash()的代码。
:
由于流和MD5都实现IDisposable,因此需要使用using(…){…}
代码示例中的方法返回用于Azure Blob存储中MD5校验和的相同字符串。Necromancing
C#.NET核心中有两种可能性:
private static System.Security.Cryptography.HashAlgorithm GetHashAlgorithm(System.Security.Cryptography.HashAlgorithmName hashAlgorithmName)
{
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.MD5)
return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.MD5.Create();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA1)
return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA1.Create();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA256)
return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA256.Create();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA384)
return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA384.Create();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA512)
return (System.Security.Cryptography.HashAlgorithm) System.Security.Cryptography.SHA512.Create();
throw new System.Security.Cryptography.CryptographicException($"Unknown hash algorithm \"{hashAlgorithmName.Name}\".");
}
protected override byte[] HashData(System.IO.Stream data,
System.Security.Cryptography.HashAlgorithmName hashAlgorithm)
{
using (System.Security.Cryptography.HashAlgorithm hashAlgorithm1 =
GetHashAlgorithm(hashAlgorithm))
return hashAlgorithm1.ComputeHash(data);
}
或使用BouncyCastle:
private static Org.BouncyCastle.Crypto.IDigest GetBouncyAlgorithm(
System.Security.Cryptography.HashAlgorithmName hashAlgorithmName)
{
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.MD5)
return new Org.BouncyCastle.Crypto.Digests.MD5Digest();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA1)
return new Org.BouncyCastle.Crypto.Digests.Sha1Digest();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA256)
return new Org.BouncyCastle.Crypto.Digests.Sha256Digest();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA384)
return new Org.BouncyCastle.Crypto.Digests.Sha384Digest();
if (hashAlgorithmName == System.Security.Cryptography.HashAlgorithmName.SHA512)
return new Org.BouncyCastle.Crypto.Digests.Sha512Digest();
throw new System.Security.Cryptography.CryptographicException(
$"Unknown hash algorithm \"{hashAlgorithmName.Name}\"."
);
} // End Function GetBouncyAlgorithm
protected override byte[] HashData(System.IO.Stream data,
System.Security.Cryptography.HashAlgorithmName hashAlgorithm)
{
Org.BouncyCastle.Crypto.IDigest digest = GetBouncyAlgorithm(hashAlgorithm);
byte[] buffer = new byte[4096];
int cbSize;
while ((cbSize = data.Read(buffer, 0, buffer.Length)) > 0)
digest.BlockUpdate(buffer, 0, cbSize);
byte[] hash = new byte[digest.GetDigestSize()];
digest.DoFinal(hash, 0);
return hash;
}
这似乎是
加密流
()的完美用例
我使用了CryptoStream
来处理未知长度的数据库结果流,这些数据流需要进行gzip压缩,然后与压缩文件的散列一起通过网络传输。在压缩器和文件编写器之间插入一个加密流
,允许您动态计算散列,以便在写入文件后立即准备好散列
基本方法如下所示:
var hasher = MD5.Create();
using (FileStream outFile = File.Create(filePath))
using (CryptoStream crypto = new CryptoStream(outFile, hasher, CryptoStreamMode.Write))
using (GZipStream compress = new GZipStream(crypto, CompressionMode.Compress))
using (StreamWriter writer = new StreamWriter(compress))
{
foreach (string line in GetLines())
writer.WriteLine(line);
}
// at this point the streams are closed so the hash is ready
string hash = BitConverter.ToString(hasher.Hash).Replace("-", "").ToLowerInvariant();
我见过这些方法,但从未调查过它们的作用。我真丢脸。这看起来是可行的。它不适用于从网络接收流,然后用API CopyTo方法将流发送(复制)到文件系统的情况。CryptoStream解决了这个问题。谢谢分享,很有帮助!非常感谢,这确实适合“动态”散列。。。在阅读散列之前,没有手工制作的流分块到blocks感谢关于关闭流的评论。别担心,没有亡灵术。欢迎提供最新答案。
var hasher = MD5.Create();
using (FileStream outFile = File.Create(filePath))
using (CryptoStream crypto = new CryptoStream(outFile, hasher, CryptoStreamMode.Write))
using (GZipStream compress = new GZipStream(crypto, CompressionMode.Compress))
using (StreamWriter writer = new StreamWriter(compress))
{
foreach (string line in GetLines())
writer.WriteLine(line);
}
// at this point the streams are closed so the hash is ready
string hash = BitConverter.ToString(hasher.Hash).Replace("-", "").ToLowerInvariant();