获取文件 SHA256 哈希码和校验和
Get a file SHA256 Hash code and Checksum
之前我问过 关于组合 SHA1+MD5 的问题,但在那之后我明白了计算 SHA1 和 lagrge 文件的 MD5 并不比 SHA256 快。
在我的例子中,一个 4.6 GB 的文件大约需要 10 分钟,在 Linux 系统中使用默认实现 SHA256 和 (C# MONO)。
public static string GetChecksum(string file)
{
using (FileStream stream = File.OpenRead(file))
{
var sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(stream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
然后我阅读了 this topic 并根据他们所说的以某种方式更改了我的代码:
public static string GetChecksumBuffered(Stream stream)
{
using (var bufferedStream = new BufferedStream(stream, 1024 * 32))
{
var sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(bufferedStream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
但是没有那种亲切感,需要9分钟左右
然后我尝试通过 Linux 中的 sha256sum
命令测试同一个文件,这需要大约 28 秒,上面的代码和 Linux 命令给出相同的结果结果 !
有人建议我阅读哈希码和校验和之间的区别,我找到了 this topic 来解释这些区别。
我的问题是:
是什么导致上面的代码和Linux sha256sum
在时间上如此不同?
以上代码的作用是什么? (我的意思是计算hash code还是checksum?因为如果你用C#搜索give a file of a file的hash code和checksum,它们都会达到上面的代码。)
即使 SHA256 是抗碰撞的,是否有任何针对 sha256sum
的有动机的攻击?
如何使我的实现与 C# 中的 sha256sum
一样快?
我最好的猜测是 File.Read
操作的 Mono 实现中有一些额外的缓冲。最近研究了一个大文件的校验和,在一个体面的规格 Windows 机器上,如果一切 运行 顺利,你应该期望每 Gb 大约 6 秒。
奇怪的是,不止一项基准测试报告说 SHA-512 明显比 SHA-256 快(见下面的 3)。另一种可能性是问题不在于分配数据,而在于一旦读取就处理字节。您可以在单个数组上使用 TransformBlock
(和 TransformFinalBlock
),而不是在一个大的 gulp 中读取流——我不知道这是否可行,但值得研究.
哈希码和校验和之间的区别(几乎)是语义。他们都计算出一个较短的 'magic' 数字,该数字对于输入中的数据来说是相当独特的,但如果您有 4.6GB 的输入和 64B 的输出,'fairly' 就有些受限了。
- 校验和是不安全的,通过一些工作,您可以从足够多的输出中找出输入,从输出到输入反向工作,并做各种不安全的事情。
- 加密散列需要更长的时间来计算,但仅更改输入中的一位会从根本上改变输出,并且对于良好的散列(例如 SHA-512),尚无从输出返回输入的已知方法。
MD5 是易碎的:如果需要,您可以在 PC 上制作输入以产生任何给定的输出。 SHA-256(可能)仍然安全,但几年后就不会了——如果你的项目的寿命以几十年为单位,那么假设你需要改变它。 SHA-512 没有已知的攻击,而且可能在相当长一段时间内都不会,而且由于它比 SHA-256 更快,我无论如何都会推荐它。基准测试表明,计算 SHA-512 的时间比计算 MD5 的时间长 3 倍左右,因此如果您的速度问题可以得到解决,这是可行的方法。
不知道,除了上面提到的那些。你做得对。
有关简单阅读,请参阅 Crypto.SE: SHA51 is faster than SHA256?
编辑以回复评论中的问题
校验和的目的是让您检查文件在您最初编写文件和您开始使用它之间是否发生了变化。它通过生成一个小值(在 SHA512 的情况下为 512 位)来实现这一点,其中原始文件的每一位至少对输出值有所贡献。哈希码的目的是相同的,此外,其他任何人都很难通过对文件进行仔细管理的更改来获得相同的输出值。
前提是如果一开始和检查时的校验和相同,那么文件是相同的,如果不同则文件肯定发生了变化。您在上面所做的是通过一种算法完整地提供文件,该算法滚动、折叠和旋转它读取的位以产生小值。
举个例子:在我目前正在编写的应用程序中,我需要知道任何大小的文件的某些部分是否已更改。我将文件分成 16K 块,获取每个块的 SHA-512 哈希,并将其存储在另一个驱动器上的单独数据库中。当我查看文件是否已更改时,我会为每个块重新生成哈希并将其与原始文件进行比较。由于我使用的是 SHA-512,更改后的文件具有相同哈希值的可能性小得难以想象,因此我有信心检测到 100 GB 数据的变化,同时在我的数据库中仅存储几 MB 的哈希值。我在获取哈希的同时复制文件,这个过程完全是磁盘绑定的;将文件传输到U盘大约需要5分钟,其中10秒可能与哈希有关。
缺少存储哈希的磁盘 space 是我无法在 post 中解决的问题——买一个 U 盘?
public string SHA256CheckSum(string filePath)
{
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = File.OpenRead(filePath))
return Convert.ToBase64String(SHA256.ComputeHash(fileStream));
}
}
派对来晚了,但看到 none 个答案提到了它,我想指出:
SHA256Managed
是 System.Security.Cryptography.HashAlgorithm
class 的实现,所有与读取操作相关的功能都在继承的代码中处理。
HashAlgorithm.ComputeHash(Stream)
使用固定的 4096 字节缓冲区从流中读取数据。因此,对于此调用,使用 BufferedStream
并不会真正看到太大差异。
HashAlgorithm.ComputeHash(byte[])
对整个字节数组进行操作,但它会在每次调用后重置内部状态,因此它不能用于增量散列缓冲流。
您最好的选择是使用针对您的用例优化的第三方实施。
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = System.IO.File.OpenRead(filePath))
{
string result = "";
foreach (var hash in SHA256.ComputeHash(fileStream))
{
result += hash.ToString("x2");
}
return result;
}
}
供参考:https://www.c-sharpcorner.com/article/how-to-convert-a-byte-array-to-a-string/
之前我问过
public static string GetChecksum(string file)
{
using (FileStream stream = File.OpenRead(file))
{
var sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(stream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
然后我阅读了 this topic 并根据他们所说的以某种方式更改了我的代码:
public static string GetChecksumBuffered(Stream stream)
{
using (var bufferedStream = new BufferedStream(stream, 1024 * 32))
{
var sha = new SHA256Managed();
byte[] checksum = sha.ComputeHash(bufferedStream);
return BitConverter.ToString(checksum).Replace("-", String.Empty);
}
}
但是没有那种亲切感,需要9分钟左右
然后我尝试通过 Linux 中的 sha256sum
命令测试同一个文件,这需要大约 28 秒,上面的代码和 Linux 命令给出相同的结果结果 !
有人建议我阅读哈希码和校验和之间的区别,我找到了 this topic 来解释这些区别。
我的问题是:
是什么导致上面的代码和Linux
sha256sum
在时间上如此不同?以上代码的作用是什么? (我的意思是计算hash code还是checksum?因为如果你用C#搜索give a file of a file的hash code和checksum,它们都会达到上面的代码。)
即使 SHA256 是抗碰撞的,是否有任何针对
sha256sum
的有动机的攻击?如何使我的实现与 C# 中的
sha256sum
一样快?
我最好的猜测是
File.Read
操作的 Mono 实现中有一些额外的缓冲。最近研究了一个大文件的校验和,在一个体面的规格 Windows 机器上,如果一切 运行 顺利,你应该期望每 Gb 大约 6 秒。奇怪的是,不止一项基准测试报告说 SHA-512 明显比 SHA-256 快(见下面的 3)。另一种可能性是问题不在于分配数据,而在于一旦读取就处理字节。您可以在单个数组上使用
TransformBlock
(和TransformFinalBlock
),而不是在一个大的 gulp 中读取流——我不知道这是否可行,但值得研究.哈希码和校验和之间的区别(几乎)是语义。他们都计算出一个较短的 'magic' 数字,该数字对于输入中的数据来说是相当独特的,但如果您有 4.6GB 的输入和 64B 的输出,'fairly' 就有些受限了。
- 校验和是不安全的,通过一些工作,您可以从足够多的输出中找出输入,从输出到输入反向工作,并做各种不安全的事情。
- 加密散列需要更长的时间来计算,但仅更改输入中的一位会从根本上改变输出,并且对于良好的散列(例如 SHA-512),尚无从输出返回输入的已知方法。
MD5 是易碎的:如果需要,您可以在 PC 上制作输入以产生任何给定的输出。 SHA-256(可能)仍然安全,但几年后就不会了——如果你的项目的寿命以几十年为单位,那么假设你需要改变它。 SHA-512 没有已知的攻击,而且可能在相当长一段时间内都不会,而且由于它比 SHA-256 更快,我无论如何都会推荐它。基准测试表明,计算 SHA-512 的时间比计算 MD5 的时间长 3 倍左右,因此如果您的速度问题可以得到解决,这是可行的方法。
不知道,除了上面提到的那些。你做得对。
有关简单阅读,请参阅 Crypto.SE: SHA51 is faster than SHA256?
编辑以回复评论中的问题
校验和的目的是让您检查文件在您最初编写文件和您开始使用它之间是否发生了变化。它通过生成一个小值(在 SHA512 的情况下为 512 位)来实现这一点,其中原始文件的每一位至少对输出值有所贡献。哈希码的目的是相同的,此外,其他任何人都很难通过对文件进行仔细管理的更改来获得相同的输出值。
前提是如果一开始和检查时的校验和相同,那么文件是相同的,如果不同则文件肯定发生了变化。您在上面所做的是通过一种算法完整地提供文件,该算法滚动、折叠和旋转它读取的位以产生小值。
举个例子:在我目前正在编写的应用程序中,我需要知道任何大小的文件的某些部分是否已更改。我将文件分成 16K 块,获取每个块的 SHA-512 哈希,并将其存储在另一个驱动器上的单独数据库中。当我查看文件是否已更改时,我会为每个块重新生成哈希并将其与原始文件进行比较。由于我使用的是 SHA-512,更改后的文件具有相同哈希值的可能性小得难以想象,因此我有信心检测到 100 GB 数据的变化,同时在我的数据库中仅存储几 MB 的哈希值。我在获取哈希的同时复制文件,这个过程完全是磁盘绑定的;将文件传输到U盘大约需要5分钟,其中10秒可能与哈希有关。
缺少存储哈希的磁盘 space 是我无法在 post 中解决的问题——买一个 U 盘?
public string SHA256CheckSum(string filePath)
{
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = File.OpenRead(filePath))
return Convert.ToBase64String(SHA256.ComputeHash(fileStream));
}
}
派对来晚了,但看到 none 个答案提到了它,我想指出:
SHA256Managed
是 System.Security.Cryptography.HashAlgorithm
class 的实现,所有与读取操作相关的功能都在继承的代码中处理。
HashAlgorithm.ComputeHash(Stream)
使用固定的 4096 字节缓冲区从流中读取数据。因此,对于此调用,使用 BufferedStream
并不会真正看到太大差异。
HashAlgorithm.ComputeHash(byte[])
对整个字节数组进行操作,但它会在每次调用后重置内部状态,因此它不能用于增量散列缓冲流。
您最好的选择是使用针对您的用例优化的第三方实施。
using (SHA256 SHA256 = SHA256Managed.Create())
{
using (FileStream fileStream = System.IO.File.OpenRead(filePath))
{
string result = "";
foreach (var hash in SHA256.ComputeHash(fileStream))
{
result += hash.ToString("x2");
}
return result;
}
}
供参考:https://www.c-sharpcorner.com/article/how-to-convert-a-byte-array-to-a-string/