在大文件上计算单个MD5校验和时,通常使用什么技术将各种MD5值组合成单个值?你刚刚把它们加在一起吗?我对任何特定的语言,库或API都不感兴趣;相反,我只对它背后的技术感兴趣。有人可以解释一下它是如何完成的吗?
在伪代码中给出以下算法:
MD5Digest X
for each file segment F
MD5Digest Y = CalculateMD5(F)
Combine(X,Y)
但是Combine
究竟会做什么?它是将两个MD5摘要一起添加还是什么?
答案 0 :(得分:16)
为了计算太大而无法放入内存的文件的MD5值
考虑到这一点,您不希望“合并”两个MD5哈希值。使用任何 MD5实现,您有一个保持当前校验和状态的对象。因此,您可以随时提取MD5校验和,这在散列共享相同开头的两个文件时非常方便。对于大文件,您只需继续输入数据 - 如果您一次或在块中散列文件,则没有区别,因为状态会被记住。在这两种情况下,您都会获得相同的哈希值。
答案 1 :(得分:6)
MD5是一种迭代算法。你不需要计算大量的小型MD5,然后以某种方式将它们组合起来。您只需读取文件的小块并将其添加到摘要中,这样您就不必立即将整个文件放在内存中。这是一个java实现。
FileInputStream f = new FileInputStream(new File("bigFile.txt"));
MessageDigest digest = MessageDigest.getInstance("md5");
byte[] buffer = new byte[8192];
int len = 0;
while (-1 != (len = f.read(buffer))) {
digest.update(buffer,0,len);
}
byte[] md5hash = digest.digest();
Et瞧。您拥有整个文件的MD5,而不会立即将整个文件放在内存中。
值得注意的是,如果由于某种原因你确实需要MD5哈希的文件子部分(这有时对通过低带宽连接传输的大文件进行临时检查有用)那么你可以得到他们可以随时克隆摘要对象,如此
byte[] interimHash = ((MessageDigest)digest.clone()).digest();
这不会影响实际的摘要对象,因此您可以继续使用整个MD5哈希值。
还值得注意的是,MD5是用于加密目的的过时哈希(例如从不受信任的来源验证文件真实性),并且在大多数情况下应该用更好的东西替换,例如SHA-1。对于非加密目的,例如验证两个可信源之间的文件完整性,MD5仍然足够。
答案 2 :(得分:2)
openSSL库允许您将数据块添加到正在进行的散列(sha1 / md5)中,然后当您添加完所有数据时调用Final
方法,它将输出最终散列。
您不计算每个块上的md5然后添加它,而是将数据添加到openssl库中的正在进行的哈希方法中。然后,这将为您提供所有单个数据块的md5哈希,而不限制输入数据大小。
答案 3 :(得分:2)
这个问题没有多大意义,因为MD5算法需要任何长度输入。一个像样的库应该具有一些功能,这样你就不必一次添加整个消息,因为消息被分解为一个顺序散列的块,而正在处理的块只取决于前一个产生的散列。循环。
wikipedia article中的伪代码应概述算法的工作原理。
答案 4 :(得分:1)
大多数摘要计算实现允许您以较小的块提供数据。您不能以一种结果等于整个输入的MD5的方式组合多个MD5摘要。 MD5执行一些填充并使用最后阶段中的proccessed字节数,这使得原始引擎状态无法从最终摘要值恢复。
答案 5 :(得分:1)
这是一种组合哈希的C#方式。让我们制作扩展方法来简化用户代码。
public static class MD5Append
{
public static int Append(this MD5 md5, byte[] data)
{
return md5.TransformBlock(data, 0, data.Length, data, 0);
}
public static void AppendFinal(this MD5 md5, byte[] data)
{
md5.TransformFinalBlock(data, 0, data.Length);
}
}
用法:
using (var md5 = MD5CryptoServiceProvider.Create("MD5"))
{
md5.Initialize();
var abcBytes = Encoding.Unicode.GetBytes("abc");
md5.Append(abcBytes);
md5.AppendFinal(abcBytes);
var h1 = md5.Hash;
md5.Initialize(); // mandatory
var h2= md5.ComputeHash(Encoding.Unicode.GetBytes("abcabc"));
Console.WriteLine(Convert.ToBase64String(h1));
Console.WriteLine(Convert.ToBase64String(h2));
}
h1和h2是相同的。就是这样。
答案 6 :(得分:1)
AndiDog回答的Python 2.7示例。文件123.txt有多行。
>>> import hashlib
>>> md5_A, md5_B, md5_C = hashlib.md5(), hashlib.md5(), hashlib.md5()
>>> with open('123.txt', 'r') as f_r:
... md5_A.update(f_r.read()) # read whole contents
...
>>> with open('123.txt', 'r') as f_r:
... for line in f_r: # read file line by line
... md5_B.update(line)
...
>>> with open('123.txt', 'r') as f_r:
... while True: # read file chunk by chunk
... chunk = f_r.read(10)
... if not chunk: break
... md5_C.update(chunk)
...
>>> md5_A.hexdigest()
'5976ddfa19bc2e1669ac3bd836101f58'
>>> md5_B.hexdigest()
'5976ddfa19bc2e1669ac3bd836101f58'
>>> md5_C.hexdigest()
'5976ddfa19bc2e1669ac3bd836101f58'
对于无法放入内存的大文件,可以逐行读取或按块读取块。这个MD5的一个用法是在diff命令失败时比较两个大文件。