Introducción
Hace poco tuve la necesidad de copiar el contenido de una partición a otra; se trataba de documentos, por lo que necesitaba verificar que la copia fuera correcta. Yo sabía que existe el programa md5sum, pero no lograba hacerlo andar recursivamente, dado que no trae esta opción. Navegando, me topé con este foro donde daban la respuesta de cómo hacer un chequeo md5 de manera recursiva.
Entonces, me decidí a crear un script, el cual comparto aquí.
>> Ver este post en Taringa! <<
Descripción
Este script tiene doble función: por un lado crea recursivamente los hashes md5 de todos los archivos de un determinado directorio, y los guarda en un archivo de texto; por otro lado, es capaz de leer dicho archivo para luego realizar la verificación.
¿De qué se trata? Pues de tener la capacidad de verificar una enorme cantidad de archivos; puede verificarse que la copia fue correcta con facilidad, y detectar si algún archivo falló.
ACTUALIZACIÓN: Gracias Tim7967 por aclarar que MD5 ya se ha probado vulnerable contra distintos ataques, y no puede ser usado con fines criptográficos. Sin embargo, al ser un algoritmo implementado en cualquier linux, y ser muy veloz, sirve a los fines de realizar la verificación de archivos, dado que las probabilidades que se produzca una colisión entre dos o más archivos en una pc, son prácticamente nulas. Pero si ustedes requieren de un algoritmo de alta seguridad, como Tim7967 nos cuenta, deberían pensar en SHA-2. Más información abajo, en los comentarios.
ACTUALIZACIÓN: Gracias a un tip de vocin pongo aquí el código utilizando el comando code
Simplemente deben copiar desde el inicio hasta el final del script, pegarlo en un archivo de texto plano y vacío (gedit, leafpad, vim, nano, etc), guardarlo y darle permiso de ejecucion: chmod +x md5recursivesum ( el nombre que le hayan dado).
#!/bin/bash #------------------------------------------------------------------------ # Script para crear y verificar hashes md5 # CopyLeft HacKan @ HacKan & CuBa co. 2010, 2011, 2012 # http://www.hackan.com.ar # # | Este script se entrega 'tal cual' y como Open Source, # | y como tal puede modificarse, adaptarse y usarse libremente. # | Favor de mantener autores, coautores y demás info intacta, # | añadiendo la suya si así lo desea. # # Si realiza alguna mejora, me gustaría saber de ello# # Para 'instalar' este script, es decir, ejecutarlo como un comando # desde cualquier lugar del sistema, copiarlo a la carpeta # /usr/bin. # P.E.: sudo cp ~/Escritorio/md5recursivesum /usr/bin/md5rsum # Personalmente, le acorte el nombre a md5rsum, por comodidad # # Requerimientos # =============== # # Este script hace uso de los siguientes programas: # md5sum # notify-send, del paquete notify-osd #------------------------------------------------------------------------ #------------------------------------------------------------------------ # Registro de cambios #===================== # # v1.1 # - Corregido: salir con estado 0 en modo verificacion aun cuando # haya ocurrido un error. # # v1.0 # - Agregado grep en verificacion: permite mostrar solo los archivos # correctos o solo los incorrectos, o todos. # - Editada la ayuda acorde # - Se agregó modo silencioso: no muestra mensajes con notify-send # # v0.9 # - Se modificó acción cuando no se especifica archivo # en el modo verificación # - Se agregó segundo argumento para el modo crear, que especifica # la ruta y/o nombre de archivo donde guardar el archivo # de verificación # - Se modificó la ayuda # - En el modo crear, se cambió forma de trabajar: primero # se crea un archivo temporal, y finalmente se copia a # destino y se elimina el temporal # - Se modificó rutina de verificación, para chequear primero que # el archivo exista # - Se agregaron opciones a la configuración interna # # v0.8 # - Algunos cambios en la sintaxis para mejor lectura y optimización # # v0.7 # - Se le agrega notify-send para notificar finalización del proceso # - Se agregan etiquetas para separar el script en secciones: config, # funciones y script. # - Se agrega disclaimer # # v0.6 # - Primera versión funcional #------------------------------------------------------------------------ #------------------------------------------------------------------------ # Para hacer... # ==================== # # - Traducir a inglés #------------------------------------------------------------------------ #--------- Config ---------# title="md5recursivesum" version="1.0" crear="-c" qcrear="${crear}q" # Debe empezar con los caracts. del modo crear verif="-v" qverif="${verif}q" # Debe empezar con los caracts. del modo verif grepOK="-gok" grepKO="-gko" ayuda="--help" iconOK="/usr/share/icons/Humanity/actions/48/dialog-apply.svg" iconKO="/usr/share/icons/Humanity/actions/48/process-stop.svg" iconSTART="/usr/share/icons/Humanity/actions/48/system-run.svg" md5fname="md5sum.md5" tmpdir="/tmp" #--------------------------# #-------- Funciones -------# function fin { echo echo "Script finalizado" exit $1 } function f_ayuda { echo "Crea o verifica un archivo de hash md5. A diferencia de md5sum, permite crear un archivo md5 conteniendo el hash de multiples archivos. Puede procesar directorios recursivamente. Hace uso de md5sum y notify-osd, por lo que requiere de los mismos." echo echo "Modo de uso: ${title} ([${crear} | ${qcrear}] | [${verif} | ${qverif}] | ${ayuda}) ([DIRECTORIO] | ARCHIVO) [/RUTA/ARCHIVO.MD5 | [${grepOK} | ${grepKO}]]" echo echo " ${crear} Modo creacion. Crea un archivo hash md5" echo " ${qcrear} Modo creacion silencioso: no muestra mensajes via notify-osd" echo echo " ${verif} Modo verificacion. Lee un archivo md5 y verifica los archivos correspondientes" echo " ${qverif} Modo verificacion silencioso: no muestra mensajes via notify-osd" echo " ${grepOK} En el modo verificacion: solo muestra los archivos correctos" echo " ${grepKO} En el modo verificacion: solo muestra los archivos incorrectos" echo echo " ${ayuda} Muestra esta ayuda" echo echo echo " Modo creacion" echo "1- Para crear el hash de los archivos de un directorio recursivamente: $title $crear /directorio/a/chequear" echo "P.E.: $title $crear /home/usuario/Documentos" echo "Por defecto, el archivo de verificación será creado en el directorio actual, bajo el nombre ${md5fname}" echo echo "1.1- Se puede especificar la ruta para guardar el archivo de verificacion en un tercer argumento. ¡La misma debe ser absoluta, y NO terminar con '/'!" echo "P.E.: $title $crear /home/usuario/Documentos /home/usuario" echo "Esto guardara el archivo md5sum.md5 en el directorio /home/usuario" echo echo "1.2- También se puede especificar un nombre de archivo, con o sin la ruta. Si no especifica ruta, se considera el directorio actual" echo "P.E.: $title $crear /home/usuario/Documentos /home/usuario/docs.md5" echo "P.E.: $title $crear /home/usuario/Documentos docs.md5" echo echo echo " Modo verificacion " echo "2- Para verificar los archivos con un archivo de hash: $title $verif /ruta/del/archivo.md5" echo "P.E.: $title $verif ./${md5fname}" echo "Si no se especifica ruta del archivo, se buscara el archivo en el directorio actual" echo echo "2.1- Para mostrar solo los archivos correctos, emplee el parámetro ${grepOK}" echo "P.E.: $title $verif ./${md5fname} ${grepOK}" echo echo "2.2- Para mostrar solo los archivos incorrectos, emplee el parámetro ${grepKO}" echo "P.E.: $title $verif ./${md5fname} ${grepKO}" echo echo echo "Esta ayuda se muestra con el parametro \"$ayuda\" o bien si no se le pasan parametros al script" } function notify { # Debe recibir el path al ícono primero, y el texto segundo. # Si es modo quiet, no usar notify-send if [ ${param1} != ${qcrear} ] && [ ${param1} != ${qverif} ]; then notify-send -i "${1}" "${title}" "${2}" fi if [ ${1} = ${iconKO} ]; then echo -n "ERROR: " fi echo ${2} } #--------------------------# #--------- Script ---------# echo "-----------------------------------------------" echo "$title v$version by HacKan & CuBa co. 2010" echo " http://www.hackan.com.ar" echo "-----------------------------------------------" echo # Modo param1=${1} # Ruta para crear archivo (-c) o archivo a verificar (-v) param2=${2} # Destino para almacenar archivo (-c) o modo grep (-v) param3=${3} md5f=${param3} if [ -z ${param1} ] || [ ${param1} = $ayuda ]; then f_ayuda fin 0 fi ECODE=0 # Tomo del primer argumento, la cant de caracteres que tiene el modo if [ ${param1:0:${#crear}} = $crear ]; then # Crear archivo md5 if [ -d ${param2} ]; then if [ -z ${param2} ]; then echo "No se indico directorio, se procesara el actual" param2="./" fi if [ -z ${param3} ]; then # Si no se especifica ruta para guardar # archivo md5, se usa la actual param3=${param2} fi if [ -d ${param3} ]; then # Es un directorio, no un archivo md5f="${param3}/${md5fname}" fi notify ${iconSTART} "Creando hash md5 para los archivos dentro de ${param2}" echo "Espere por favor..." rm -f "${tmpdir}/${md5fname}" find ${param2} -type f -print0 | xargs -0 md5sum >> "${tmpdir}/${md5fname}" cp "${tmpdir}/${md5fname}" "${md5f}" if [ $? -ne 0 ]; then # Error en la copia notify ${iconKO} "Se ha producido un error al copiar el archivo ${tmpdir}/${md5fname} a ${md5f}" fin 1 fi rm -f "${tmpdir}/${md5fname}" notify ${iconOK} "Archivo guardado como ${md5f}" else notify ${iconKO} "No existe el directorio ${param2}" ECODE=1 fi else if [ ${param1:0:${#verif}} = $verif ]; then # Verificar directorio con archivo .md5 if [ -z ${param2} ]; then echo "No se indico ruta del archivo, se usara la actual" param2="./${md5fname}" fi if [ ! -e ${param2} ]; then notify ${iconKO} "No existe el archivo ${param2}; no se puede realizar la verificacion" fin 1 fi notify ${iconSTART} "Verificando archivos en base a ${param2}... Espere por favor..." echo # Verifico archivos md5sum -c ${param2} > "${tmpdir}/md5sum.out" resultado=$? # Imprimo resultado como corresponda # Si el tercer argumento viene vacío, le pongo un texto cualquiera # para que bash no se queje al hacer la comparación con un # string en los próximos if's. if [ -z ${param3} ]; then param3="vacio"; fi if [ ${param3} = ${grepOK} ]; then cat "${tmpdir}/md5sum.out" | grep "suma coincide" elif [ ${param3} = ${grepKO} ]; then cat "${tmpdir}/md5sum.out" | grep "no coincide" else cat "${tmpdir}/md5sum.out" fi # Elimino temporal rm "${tmpdir}/md5sum.out" echo if [ ${resultado} -eq 0 ]; then notify ${iconOK} "Todos los archivos fueron verificados satisfactoriamente" else notify ${iconKO} "Al menos un archivo fallo en la verificacion" fi ECODE=${resultado} else notify ${iconKO} "Opcion invalida: ${param1}. Utilice \"$title $ayuda\" para ver la ayuda" ECODE=1 fi fi fin ${ECODE} #--------------------------#
Ultima versión: 1.1
md5recursivesum.zip – MD5 Hash: 93c9d378af122a03e46caac74e49331d
(Firmado por hackan@hackan.com.ar [ID 0x636A37C0]: md5recursivesum-v1.1.zip.sig) ¿qué significa esto?
Otras versiones
v1.1: md5recursivesum-v1.1 – MD5 Hash: 93c9d378af122a03e46caac74e49331d
v1.0: md5recursivesum-v1.0 – MD5 Hash: eeb76267f9a477b45aeada069d7598b4
v0.9: md5recursivesum-v0.9 – MD5 Hash: 7f2514aeca5fff29d06e68719514b4fe
v0.8: md5recursivesum-v0.8 – MD5 Hash: afd29316c175ca4e0c8b531abaf25a2a
¿De qué se trata esto del chequeo con hashes md5?
MD5 es uno de los algoritmos de reducción criptográficos diseñados por el profesor Ronald Rivest del MIT (Massachusetts Institute of Technology, Instituto Tecnológico de Massachusetts).
La codificación del MD5 de 128 bits es representada típicamente como un número de 32 dígitos hexadecimal. El siguiente código de 28 bytes ASCII será tratado con MD5 y veremos su correspondiente hash de salida:
MD5<”Esto sí es una prueba de MD5″> = e99008846853ff3b725c27315e469fbc
Un simple cambio en el mensaje nos da un cambio total en la codificación hash, en este caso cambiamos dos letras, el «sí» por un «no».
MD5<”Esto no es una prueba de MD5″> = dd21d99a468f3bb52a136ef5beef5034
Otro ejemplo sería la codificación de un campo vacío:
MD5<”"> = d41d8cd98f00b204e9800998ecf8427e
¿De qué nos sirve todo eso? Pues muy simple: el md5 permite crear un hash (un código, digamos) que es único para cada archivo; de esta manera, si p.e. copiamos un archivo, podemos verificar si la copia fue correcta o no creando el hash de cada uno y luego comparándolos: si son iguales es que la copia fue correcta; caso contrario, la misma falló.
El algoritmo es muy veloz, y muy eficiente.
Este script nos facilita realizar esta clase de comprobaciones, sin que tengamos necesidad de saber siquiera qué es md5.
Modo de uso
El modo de uso es bastante simple. El script se ejecuta en la consola, no posee interfaz gráfica; y NO requiere ser root (es decir, NO debe ejecutarse con sudo), a excepción de que los archivos o el directorio a verificar solo pueda ser accedido por el root.
Se ejecuta como cualquier otro script, yendo a su carpeta y poniendo: ./md5recursivesum
Si quieren pueden hacer lo sig. para poder ejecutarlo desde cualquier lado (sin tener q ir al directorio) como si fuera un comando más: sudo ln -t /usr/bin /ruta/al/script/md5recursivesum
Esto crea un link al script en la carpeta /usr/bin. Si desean que esté disponible para todos los usuarios, pueden considerar copiar el script a la carpeta /usr/bin en lugar de poner un link (acceso directo, quiero decir).
1- Para crear el hash de los archivos de un directorio recursivamente: md5recursivesum -c /directorio/a/chequear
P.E.: md5recursivesum -c /home/usuario/Documentos
Esto creará un archivo llamado md5recursivesum.md5 en el directorio actual desde donde ejecutamos el script, cuyo contenido será la ruta y nombre de cada archivo, con su respectivo hash.
2- Para verificar los archivos con un archivo de hash: md5recursivesum -v /ruta/del/archivo.md5
P.E.: md5recursivesum -v ./md5sum.md5
Este modo verifica cada archivo con el hash que encuentra en el archivo de hashes (en el ejemplo, llamado md5sum.md5)
Se puede emplear ‘ | grep “suma coincide”‘ para mostrar solo los correctos y ‘ | grep “no coincide”‘ para solo los incorrectos.
P.E.: md5recursivesum -v ./md5sum.md5 | grep “suma coincide”
Esto mostrará solamente los archivos cuya comprobación resulto correcta.
En la versión 1.0 se agregan los parámetros -gok y -gko para mostrar solo los resultados válidos o solo los inválidos respectivamente, usando grep (esto evita tener que hacer lo antedicho)
Esta ayuda está incorporada al script: md5recursivesum –help
Fuentes
> http://www.linuxquestions.org/questions/linux-software-2/how-to-create-md5sum-for-a-directory-689242/
De allí saqué la forma de realizar el chequeo recursivo.
> http://www.linuxconfig.org/Bash_scripting_Tutorial
Allí aprendí a escribir scripts en bash. Es realmente simple, similar al batch de Winbugs, pero muchísimo más potente.
> http://es.wikipedia.org/wiki/MD5
Info sobre MD5.
Palabras finales
Pueden distribuir y/o modificar el script a gusto y piacere, es open source ![]()
Lo que les pido es que me mencionen en el mismo.
Se aceptan sugerencias, corrección de bugs, etc.
Espero que les sea útil. Sin más, me despido.
¡Saludos!
Fue otra creación de HacKan & CuBa co.
HacKan & CuBa co. CopyLeft 2010.

Seguime en Twitter 
Although if you just found out about MD5, and are really interested in using it to check file security to see if something has been modified, MD5 has been proven to be vulnerable to have collision vulnerabilities, theoretically vulnerable to Preimage Vulnerabilities, and if you are not careful with the salt hashes you use, it is also vulnerable to rainbow tables.
If you are looking for a integrity checking algorithm for security which needs to be secure, I’d recommend the SHA-2 series of hashes (SHA-224, SHA-256, SHA-384, SHA-512). MS5 can still be trusted for most common operations, but if you want to be absolutely secure, you may want to use something else.
Thought I’d point this out for anybody new to file integrity checking.
Of course, MD5 can ONLY be used to check non-security file integrity. YOU CAN’T IMPLEMENT IT as a cryptographic hashing function, ’cause as you said, it’s know to be week with the so-called birthday attack. However, there are ways to secure it, like using random salt, like WP does to store passwords.
But in this case, MD5 comes integrated with every linux, and is one of the fastest algorithms to check for file integriry, which is why is still in use. You won’t likely have a collision attack with your own files, the possibilities are practically null. And even if you do, you might only have with 2 files, no chances at all of having more files collisioning.
You made a really good point, because i see i forget to talk about it