Объединение значений хеша MD5
При вычислении одной контрольной суммы MD5 для большого файла какой метод обычно используется для объединения различных значений MD5 в одно значение? Вы просто добавляете их вместе? Меня не интересует какой-либо конкретный язык, библиотека или API, которые это сделают; скорее меня интересует только техника. Может кто-нибудь объяснить, как это делается?
Учитывая следующий алгоритм в псевдокоде:
MD5Digest X
for each file segment F
MD5Digest Y = CalculateMD5(F)
Combine(X,Y)
Но что именно сделал бы Combine
? Добавляет ли он два дайджеста MD5 вместе или что?
Ответы
Ответ 1
Чтобы вычислить значения MD5 для файлов, которые слишком велики для размещения в памяти
С учетом этого вы не хотите "комбинировать" два хэша MD5. При любой реализации MD5 у вас есть объект, который сохраняет текущее состояние контрольной суммы. Таким образом, вы можете в любой момент извлечь контрольную сумму MD5, что очень удобно при хэшировании двух файлов, которые используют одно и то же начало. Для больших файлов вы просто продолжаете подавать данные - нет никакой разницы, если вы хэш файл сразу или в блоках, поскольку состояние запоминается. В обоих случаях вы получите тот же хеш.
Ответ 2
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 voila. У вас есть MD5 всего файла, не имея сразу всего файла в памяти.
Стоит отметить, что если по какой-то причине вам понадобятся хэши MD5 под подразделов файла, как вы идете (это иногда полезно для промежуточных проверок большого файла, передаваемого по низкоскоростному соединению), то вы можете получить их путем клонирования объекта дайджеста в любое время, например:
byte[] interimHash = ((MessageDigest)digest.clone()).digest();
Это не влияет на реальный объект дайджеста, поэтому вы можете продолжать работать с общим хешем MD5.
Также стоит отметить, что MD5 представляет собой устаревший хеш для криптографических целей (например, проверку подлинности файла из ненадежного источника) и должен быть заменен чем-то лучшим в большинстве случаев, например SHA-1. Для некриптографических целей, таких как проверка целостности файла между двумя надежными источниками, MD5 по-прежнему является адекватным.
Ответ 3
Библиотека openSSL позволяет добавлять блоки данных к текущему хешу (sha1/md5), а затем, когда вы закончите добавлять все данные, которые вы вызываете методом Final
, и выводит окончательный хэш.
Вы не вычисляете md5 на каждом отдельном блоке, а затем добавляете его, вместо этого добавляете данные в текущий хэш-метод из библиотеки openssl. После этого вы получите хеш-память md5 всех отдельных блоков данных без ограничения размера входных данных.
http://www.openssl.org/docs/crypto/md5.html#
Ответ 4
Этот вопрос не имеет особого смысла, поскольку алгоритм MD5 принимает любой ввод длины. Достойная библиотека должна иметь функции, так что вам не нужно добавлять все сообщение за один раз, когда сообщение разбивается на блоки хэширования последовательно, причем блок, который обрабатывается, зависит только от результирующих хэшей из предыдущего цикл.
Псевдокод в статье wikipedia должен дать обзор того, как работает алгоритм.
Ответ 5
Большинство реализаций вычисления дайджеста позволяют вам комбинировать данные в меньших блоках. Вы не можете комбинировать несколько дайджестов MD5 таким образом, чтобы результат был равен MD5 всего ввода. MD5 выполняет некоторую отладку и использует количество завершенных байтов на заключительном этапе, что делает исходное состояние двигателя невосстановимым из окончательного значения дайджест.
Ответ 6
Вот способ С# для объединения хэша. Давайте сделаем методы расширения для упрощения кода пользователя.
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 совпадают. Что это.
Ответ 7
Пример Python 2.7 для ответа AndiDog. Файл 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 не работает.