2010-02-06 40 views
14

Al calcular una única suma de comprobación MD5 en un archivo grande, ¿qué técnica se utiliza generalmente para combinar los diversos valores MD5 en un único valor? ¿Simplemente los agregas juntos? No estoy realmente interesado en ningún idioma, biblioteca o API particular que haga esto; más bien, estoy interesado en la técnica detrás de esto. ¿Alguien puede explicar cómo se hace?Combinación de valores hash MD5

Dado el siguiente algoritmo en pseudocódigo:

MD5Digest X 
for each file segment F 
    MD5Digest Y = CalculateMD5(F) 
    Combine(X,Y) 

Pero, ¿qué haría Combine? ¿Agrega los dos resúmenes MD5 juntos, o qué?

+0

¿Por qué querrías hacer eso? – AndiDog

+0

Para calcular valores MD5 para archivos que son demasiado grandes para caber en la memoria – channel72

+5

MD5 solo tiene un estado de 128 bits que rastrea un fragmento de archivo de 512 bits durante el cálculo; a quién le importa qué tan grande es el archivo? –

Respuesta

16

Con el fin de calcular los valores de MD5 para los archivos que son demasiado grandes para caber en la memoria

Con esto en mente, que no quieren "combinar" dos hashes MD5. Con cualquier implementación de MD5, tiene un objeto que mantiene el estado de suma de comprobación actual. Por lo tanto, puede extraer la suma de comprobación MD5 en cualquier momento, lo que es muy útil al mezclar dos archivos que comparten el mismo comienzo. Para archivos grandes, simplemente continúe ingresando datos; no hay diferencia si ha copiado el archivo de una vez o en bloques, a medida que se recuerda el estado. En ambos casos obtendrá el mismo hash.

2

La librería OpenSSL permite agregar bloques de datos a un hash en curso (SHA1/MD5) a continuación, cuando haya terminado de añadir todos los datos que llamar al método Final y te mostrará el último hash.

No calcula md5 en cada bloque individual y, a continuación, agréguelo, en lugar de agregar los datos al método hash en curso de la biblioteca openssl. Esto le dará un hash md5 de todos los bloques de datos individuales sin límite en el tamaño de datos de entrada.

http://www.openssl.org/docs/crypto/md5.html#

2

Esta pregunta no tiene mucho sentido que el algoritmo MD5 toma cualquier entrada de longitud. Una biblioteca decente debería tener funciones para que no tenga que agregar todo el mensaje al mismo tiempo, ya que el mensaje se divide en bloques, un hash secuencialmente, y el bloque que se está procesando depende únicamente de los hashes resultantes del anterior lazo.

El pseudocódigo en wikipedia article debería ofrecer una visión general de cómo funciona el algoritmo.

1

La mayoría de las implementaciones de cálculo de resumen le permiten alimentar los datos en bloques más pequeños. No puede combinar múltiples compendios de MD5 de forma que el resultado sea igual al MD5 de toda la entrada. MD5 hace algo de relleno y usa la cantidad de bytes procesados ​​en la etapa final, lo que hace que el estado original del motor no se pueda recuperar del valor de resumen final.

+0

¿Entonces el siguiente es un gran ejemplo de cómo no implementar múltiples combinaciones de MD5? Ese usuario simplemente concatena múltiples valores hash individuales para bloques individuales de un archivo grande. http://www.postgresql-archive.org/md5-large-object-id-tp5866710p5869128.html –

+0

@Thorsten: puede ser apropiado concatenar sumas de hash de bloques de tamaño fijo y luego haschar la cadena concatenada nuevamente para obtener un solo valor de hash La suma de hash resultante no es la misma que obtendría si hubiera procesado todo el archivo. Esto significa que la concatenación es inútil si necesita compararla con una que no se calcule de esta manera, pero si define su propio protocolo, puede decidir definir un determinado tamaño de bloque y calcular sus hashes siempre de esta manera. La calidad del hash no es peor que la función hash original. El uso compartido de archivos p2p de edonkey usa hashes como este. – x4u

6

MD5 es un algoritmo iterativo. No necesita calcular una tonelada de MD5 pequeños y luego combinarlos de alguna manera. Simplemente lee pequeños trozos del archivo y los agrega al resumen a medida que avanza, por lo que nunca tendrá que tener todo el archivo en la memoria a la vez. Aquí hay una implementación de 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. Tiene el MD5 de un archivo completo sin tener el archivo completo en la memoria a la vez.

Vale la pena señalar que si por alguna razón desea MD5 hashes de subsecciones del archivo a medida que avanza (esto a veces es útil para hacer comprobaciones provisionales en un archivo grande que se transfiere a través de una conexión de ancho de banda bajo) puede conseguir clonando el objeto de digestión en cualquier momento, al igual que

byte[] interimHash = ((MessageDigest)digest.clone()).digest(); 

Esto no afecta a la real digerir objeto para que pueda seguir trabajando con el hash MD5 en general.

También vale la pena señalar que MD5 es un hash obsoleto para fines criptográficos (como verificar la autenticidad del archivo de una fuente que no es de confianza) y debe reemplazarse con algo mejor en la mayoría de los casos, como SHA-1. Para fines no criptográficos, como verificar la integridad del archivo entre dos fuentes de confianza, MD5 sigue siendo adecuado.

+0

Tengo un caso de uso para necesitar sumar MD5. Leo varios archivos en paralelo y deseo tener una suma de comprobación única para toda la colección (suponiendo que los archivos están en el orden alfabético de los archivos). – Synesso

1

Aquí hay una forma C# para combinar hash. Vamos a hacer métodos de extensión para simplificar el código de usuario.

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

Uso:

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 y h2 son las mismas. Eso es.

+0

Bienvenido a SO, user1326493, y gracias por su respuesta. – Brian

1

Un ejemplo de Python 2.7 para la respuesta de AndiDog. El archivo 123.txt tiene múltiples líneas.

>>> 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' 

Para archivos grandes que no caben en la memoria, se pueden leer línea por línea o por partes. Un uso de este MD5 es la comparación de dos archivos grandes cuando falla el comando diff.