DevKitLab Logo DevKitLab
Hashing / Checksums / Integridad / Depuración

¿Por qué no coincide mi checksum? Guía de hashes que no cuadran

Un checksum que no coincide parece una alarma, pero la alarma solo tiene una posición: los dos flujos de bytes no son iguales. No te dice por qué. La habilidad no está en volver a calcular el hash, sino en acotar el desajuste a una de tres causas: los datos de verdad difieren, estás comparando los dos hashes de forma injusta, o el valor de referencia en el que confías es el que está mal. Esta guía recorre las tres.

Descargas una versión —una ISO, un .tar.gz, un instalador— y el proyecto, muy amable, pone un SHA-256 al lado. Ejecutas sha256sum sobre tu copia, alineas las dos cadenas y no coinciden. ¿Y ahora qué? La respuesta honesta, la que casi todos pasan por alto, es que el desajuste por sí solo no te dice casi nada. Un hash está hecho para que un solo bit cambiado y un archivo por completo distinto produzcan una huella igual de distinta. No hay «casi». La comparación es de todo o nada, y una comparación fallida significa una única cosa: los dos flujos de bytes que entraron en los dos hashes no eran idénticos. Ni corruptos, ni manipulados, ni rotos: solo distintos. Todo lo útil está en averiguar por qué lo eran.

(Un apunte sobre las palabras: este artículo usa «checksum» en el sentido cotidiano de descarga, el valor que comparas después de bajar un archivo. En rigor, SHA-256 es un hash criptográfico, o resumen; algo como CRC32 es un checksum no criptográfico. MD5 sigue siendo un hash criptográfico, pero su resistencia a colisiones está rota: aún detecta la mayoría de los cambios accidentales en verificaciones de archivos sin adversario, pero no sirve para autenticación de seguridad. Tengas el que tengas, la depuración de abajo es la misma.)

Así que no vuelvas a calcular el hash cinco veces esperando que cambie. No cambiará. Trata el desajuste como el punto de partida de una bifurcación triple. Una comparación de checksum tiene exactamente tres piezas móviles, y un desajuste significa que una o más de ellas fallan —a veces varias a la vez—, y por eso la lista del final recorre las tres en lugar de parar en el primer acierto:

  1. Los datos de verdad son distintos. Los bytes que hasheaste no son los bytes con los que se calculó la referencia: una descarga cortada o interrumpida, el archivo equivocado, un archivo reempaquetado, o corrupción real en el tránsito.
  2. Estás comparando los dos hashes de forma injusta. Puede que los bytes sean idénticos, pero no pones los dos resúmenes en igualdad de condiciones: algoritmo distinto, un desfase entre hex y base64, o ruido de copiado en la cadena que miras.
  3. El valor de referencia está mal o no es fiable. El número contra el que comparas está caducado, es de otra compilación, o llega de un sitio en el que no tienes motivo para confiar; y ahí una «coincidencia» habría sido el verdadero problema.

Esta guía recorre las tres en el orden en que conviene revisarlas de verdad, porque la causa más barata y frecuente —comparaste mal las cadenas— es la que la gente sospecha la última.

La idea central: un hash es una huella, y las huellas no vienen en «casi»

Todo lo de abajo se apoya en una propiedad. Un hash criptográfico mapea cualquier entrada —un byte o una imagen de disco de 4 GB— a una huella de longitud fija, y está hecho para ser sensible al efecto avalancha: cambia un solo bit de la entrada y cambia aproximadamente la mitad de los bits de salida. Ese es todo el objetivo. Es lo que permite que una cadena de 64 caracteres sustituya a un gigabyte y aun así atrape la corrupción de un byte.

La consecuencia que se olvida es la otra cara de ese poder: la salida no lleva ninguna información sobre cuánto diferían las entradas. Dos archivos que difieren en un byte y dos archivos que no comparten nada producen resúmenes que se ven igual de inconexos. Así que, ante un desajuste, no puedes leer la gravedad. «El hash es totalmente distinto» no significa «el archivo está muy corrupto»: es también lo que verías por un solo salto de línea de más. Por eso mirar más rato las dos cadenas hex nunca ayuda, y por eso la depuración nunca es «cuánto difieren», sino siempre «cuál de las tres piezas falló».

Tenlo presente: la huella te da un bit de información y se calla. Y fíjate en qué dirección es cuál. Un desajuste demuestra que los flujos de bytes difieren; esa conclusión es segura. Una coincidencia es prueba fuerte de que son iguales, pero con un algoritmo resistente a colisiones es prueba, no demostración matemática: que dos entradas distintas compartan resumen (una colisión) es astronómicamente improbable en SHA-256, pero no imposible en lógica. Para este artículo esa asimetría casi no importa: estás depurando un desajuste, y un desajuste nunca miente sobre si los bytes difieren. Solo que no te dirá por qué. El resto corre de tu cuenta.

Los comandos que vas a ejecutar de verdad

Antes de las categorías, las herramientas. En macOS o Linux, o calculas un hash y lo comparas a ojo, o dejas que el sistema verifique un archivo de checksums entero por ti:

sha256sum file.iso            # Linux: imprime el SHA-256
shasum -a 256 file.iso        # macOS: lo mismo, con las herramientas BSD
sha256sum -c checksums.txt    # verifica cada archivo de la lista contra su hash registrado

Esa última forma es la preferible cuando un proyecto trae un checksums.txt (o SHA256SUMS): hace la comparación de cadenas por ti e imprime OK o FAILED por archivo, con lo que esquiva de lleno los errores de copiar y pegar de la sección siguiente. En PowerShell de Windows:

Get-FileHash .\file.iso -Algorithm SHA256

Con esto a mano, veamos por qué el resumen o la comparación aún pueden fallar.

Primero comprueba: ¿estás comparando los dos hashes de forma justa?

Es la causa menos vistosa y una de las más frecuentes, así que descártala antes de tocar la descarga. Los bytes pueden estar perfectos; solo que no comparas los dos resúmenes en igualdad de condiciones.

Ruido al copiar y pegar. Seleccionaste el hash de referencia de una página web y te llevaste un espacio inicial, un salto de línea final o —en una línea que se partió— un trozo que quedó cortado sin que lo notaras. Un resumen es de longitud fija, así que la longitud es tu aliada: MD5 tiene 32 caracteres hex, SHA-1 tiene 40, SHA-256 tiene 64, SHA-512 tiene 128. Si la cadena que pegaste tiene 63 donde debería tener 64, no obtuviste otro archivo: obtuviste una copia mala. Cuenta los caracteres antes de concluir nada.

Mayúsculas y minúsculas del hex. La gente se asusta cuando una cadena está en mayúsculas y la otra en minúsculas. No hace falta: el caso no cambia el valor. AB y ab son el mismo byte, 0xAB. El hex es solo una forma de escribir el resumen, y sha256sum resulta que saca minúsculas, mientras algunas herramientas de Windows y páginas de descarga usan mayúsculas. Toda comparación correcta ignora el caso en el hex. La trampa no es el caso en sí, sino que al «arreglarlo» a mano, o al copiar cruzando de un caso a otro, a veces se te cae o se te añade un carácter. El valor es idéntico entre casos; una comparación literal con === en un script no lo es, así que pasa ambos lados a minúsculas antes de comparar en código.

Hex frente a base64. El mismo resumen, dos alfabetos. Un SHA-256 son 32 bytes crudos; escrito en hex son 64 caracteres, pero en base64 es una cadena de 44 caracteres que termina en =. Los atributos de Subresource Integrity en HTML (integrity="sha256-…") usan base64; sha256sum usa hex. Si un lado se ve como 47DEQpj8HBSa… y el otro como e3b0c44298fc…, puede que estés viendo un mismo resumen en dos codificaciones, y no dos archivos distintos; pero confirma primero que ambas referencias nombran el mismo algoritmo, y solo entonces convierte un alfabeto al otro y compara. Dos cadenas de aspecto distinto no prueban por sí solas un resumen compartido: son un aviso para verificar. (El base64 tiene sus propios motivos para «verse mal» que hacen tropezar justo así; esa es otra historia.)

Para quitar la adivinanza del algoritmo y del caso del hex, sube tu archivo, o pega el texto que quieres calcular, en el generador de hash, elige el algoritmo exacto que nombra la referencia y compara su salida hexadecimal. Puedes cambiar de algoritmo y alternar el hex entre mayúsculas y minúsculas, así que puedes igualar la función y el caso exactos de la referencia en vez de suponerlos. Ojo: la herramienta solo saca hex, no base64, de modo que si la referencia está en base64 tendrás que convertir un lado.

Luego: ¿seguro que es el mismo algoritmo?

Si ambos valores están en la misma representación hexadecimal y sus longitudes difieren, esto suele ser evidente: hasheaste con SHA-256 (64 caracteres hex) y la página listaba un MD5 (32) o un SHA-512 (128). El matiz importa: hex y base64 codifican el mismo resumen en longitudes distintas, así que descarta primero un desfase de codificación; un SHA-256 en base64 de 44 caracteres no es «un algoritmo más corto». Iguala el algoritmo y sigue.

La versión más traicionera es misma longitud, familia distinta. SHA-256 y SHA3-256 producen los dos 64 caracteres hex y son funciones por completo distintas. Lo mismo pasa con SHA-224 y SHA-384, con las variantes de resumen truncado y con BLAKE2 configurado a 256 bits de salida: todos fáciles de confundir con un vecino de la misma longitud. Una página que solo dice «SHA256: …» suele ser SHA-2, pero un «SHA3», «Keccak» o «BLAKE» en la etiqueta significa que debes elegir esa función exacta, no la predeterminada de la misma longitud. Cuando dos hashes de 64 caracteres no cuadran y el archivo es genuinamente idéntico, lo primero que hay que sospechar es una confusión entre familias de algoritmos: la longitud te dio la falsa confianza de estar comparando iguales con iguales.

Entradas de texto: los bytes cambiaron aunque el «contenido» no

Todo hasta aquí daba por hecho que hasheas un archivo: una secuencia fija de bytes que llega intacta o no llega. Hashear texto abre un segundo frente, porque «el mismo texto» puede ser varias secuencias de bytes distintas, y el hash ve bytes, no significado. Un resumen calculado a partir de una cadena divergirá si:

  • la codificación de caracteres difiere (UTF-8 frente a UTF-16, o UTF-8 frente a una página de códigos heredada),
  • hay una marca de orden de bytes (BOM) en un lado y no en el otro,
  • los finales de línea son LF en una máquina y CRLF en otra,
  • un lado tiene un salto de línea final y el otro no: el caso clásico de hashear un byte a secas frente al mismo byte con un salto de línea añadido:
printf x     | sha256sum   # un byte: 'x'
printf 'x\n' | sha256sum   # dos bytes: 'x' más un salto de línea — un resumen por completo distinto

(Esta es justo la trampa de echo "x" | sha256sum, ya que echo te añade ese salto de línea sin avisar.) Cada uno de estos cambia los bytes de entrada sin cambiar nada que una persona llamaría «el contenido», y con un hash criptográfico como SHA-256 el efecto avalancha convierte cualquiera de ellos en un resumen completamente distinto. Las diferencias de codificación y de finales de línea dan para bastante —y causan buena parte de esas sorpresas de «misma entrada, hash distinto» entre dos máquinas— como para tener una guía aparte; aquí basta con saber que, si hasheas texto en vez de un archivo descargado, la capa de codificación y saltos de línea es la principal sospechosa. El arreglo depende de quién controla los dos lados: si ambos son tuyos, normalízalos para que coincidan (misma codificación, mismos finales de línea, una decisión deliberada sobre el salto final) antes de hashear. Si comparas contra una referencia publicada, no puedes «normalizar» el valor fijo de otra persona: tienes que reproducir los bytes exactos con los que se calculó (la codificación correcta, la convención de saltos correcta) y hashear esos.

Ahora sí, la descarga: los datos de verdad difieren

Solo cuando has confirmado que comparas el mismo algoritmo, de forma justa, sobre el mismo tipo de entrada, tiene sentido concluir que los bytes difieren de verdad. Y cuando lo hacen, los culpables suelen ser mecánicos:

  • Una transferencia cortada o interrumpida. La descarga paró antes de tiempo —una conexión caída, un disco lleno, un proxy que cerró el flujo— y hasheaste un archivo parcial. Compara el tamaño en disco con el que anuncia una fuente fiable: la página de la versión, o la cabecera Content-Length cuando ese valor existe y es fiable. Un archivo claramente más pequeño que el tamaño fiable apunta a una descarga cortada, aunque el tamaño por sí solo no lo demuestra; confírmalo volviendo a descargar y a calcular el hash.
  • Cogiste un artefacto distinto del que describe el checksum. Los checksums son por archivo. El valor junto a app-linux-x64.tar.gz no coincidirá con app-linux-arm64.tar.gz, y el checksum de la versión 2.4.0 no coincidirá con la 2.4.1 que en realidad bajaste de un servidor espejo. Confirma para qué nombre de archivo y qué versión se publicó la referencia.
  • El archivo se reempaquetó. Dos .zip o .tar.gz pueden tener un contenido idéntico byte a byte y aun así dar hashes distintos, porque el contenedor registra marcas de tiempo, orden de archivos y ajustes de compresión que cambian entre compilaciones. Si un servidor espejo recomprimió la publicación, su checksum no coincidirá con el del proveedor original aunque cada archivo extraído sea el mismo. Verifica contra el checksum de la misma fuente que produjo el archivo.
  • Corrupción genuina. Más rara que las anteriores en redes modernas, pero real: un disco inestable, RAM defectuosa, un cable roto. Una redescarga limpia que sí coincide confirma solo que la primera copia difería, no por qué. Igual pudo ser el archivo o la versión equivocados la primera vez, un servidor espejo sirviendo otros bytes, un archivo reempaquetado o una edición local. La corrupción es una hipótesis compatible con la redescarga, no algo que esta demuestre por sí sola.

Fíjate en que «los datos difieren» es la última categoría que merece un análisis a fondo, no la primera. Un desajuste se siente como corrupción, pero la corrupción genuina suele ser menos común que los errores de comparación o de referencia.

Por último: ¿deberías siquiera fiarte de la referencia?

Aléjate un momento de la mecánica, porque hay un caso en el que el desajuste está haciendo su trabajo y una coincidencia habría sido el resultado preocupante. Un checksum solo significa algo si el valor de referencia viene de una fuente en la que confías y te llegó por un canal que no pudo alterar el archivo y el número a la vez.

Si la descarga y su hash publicado se encuentran en la misma página, servida por HTTP en claro, entonces quien pudiera manipular el archivo podría reescribir también el hash para que cuadre. La comprobación pasaría y no probaría nada. Aquí importa el propósito de un checksum, y muerde un malentendido habitual: un MD5 o SHA-256 a secas junto a una descarga es una comprobación de integridad contra daño accidental —una transferencia corrupta, un servidor espejo defectuoso, un archivo cortado—. No es una garantía de autenticidad contra un atacante deliberado. Un hash por sí mismo no lleva ningún secreto; cualquiera puede recalcularlo para cualquier archivo, así que publicar un checksum junto al archivo que describe no frena a un atacante que controle esa página y reemplace ambos a la vez. Para defenderte de la manipulación necesitas algo que un atacante no pueda falsificar, y cuál depende de tu escenario:

  • Para distribución pública de software —una página de descarga que cualquiera puede pedir— la respuesta es una firma digital: GPG, o Ed25519/minisign, donde el proveedor firma la versión (o su archivo de checksums) con una clave privada y tú verificas con su clave pública ampliamente difundida. Por eso las distribuciones de Linux entregan un archivo de checksums firmado, no un hash a secas.
  • Un HMAC es la herramienta correcta solo cuando ambas partes ya comparten una clave secreta: una API que verifica un payload de webhook, dos servicios que tú controlas. No sirve para una descarga pública, porque tendrías que entregar la clave a cada persona que descarga, y en cuanto la entregas deja de ser secreta y el atacante también la tiene.

Esa distinción decide además cuánto importa el algoritmo. Para atrapar corrupción aleatoria y sin adversario desde una fuente en la que ya confías, hasta MD5 delata de forma fiable la inmensa mayoría de los cambios accidentales. Para cualquier caso en que alguien pueda construir a propósito un archivo con colisión, MD5 y SHA-1 están rotos y quieres SHA-256 o mejor; y para una protección real contra manipulación, una firma en lugar de un hash a secas. Ese equilibrio —cuándo los algoritmos viejos aún sirven y cuándo no de ninguna manera— tiene su propia comparación. La versión de una línea para ahora mismo: si la referencia y el archivo comparten suerte —el mismo servidor no fiable, el mismo canal—, un hash que coincide es un falso alivio, y el arreglo es conseguir la referencia de un sitio independiente y fiable, no seguir recalculando el hash.

La lista para un checksum que no coincide

Cuando las dos cadenas no cuadran, resiste el impulso de recalcular nada. Recorre esto en orden: va de las causas más baratas y frecuentes a las que merecen mirar más a fondo, y cualquier combinación de ellas puede estar en juego a la vez:

  1. Primero compara ambos valores en igualdad de condiciones. Cuenta los caracteres (32/40/64/128 para MD5/SHA-1/SHA-256/SHA-512). Pasa ambos lados a minúsculas: el caso nunca cambia el valor. Asegúrate de no estar comparando hex contra base64. La mayoría de los «desajustes» mueren aquí mismo.
  2. ¿Mismo algoritmo? Con ambos lados en la misma representación hex, una longitud distinta apunta a otro algoritmo; pero confirma antes que no sea solo hex frente a base64. La misma longitud aún puede ser otra familia: SHA-256, SHA3-256 y BLAKE2 dan todos 64 caracteres hex. Iguala la función exacta que nombra la referencia.
  3. ¿Hasheas texto, no un archivo? Entonces los bytes pueden diferir mientras el «contenido» se ve igual: codificación, un BOM, LF frente a CRLF, un salto de línea final. Si ambos lados son tuyos, normalízalos para que coincidan; si comparas contra una referencia publicada, reproduce los bytes exactos con los que se calculó.
  4. Ahora sospecha de los datos. Compara el tamaño del archivo con el anunciado (descarga cortada), confirma que bajaste el archivo y la versión exactos que nombra el checksum, y recuerda que un archivo reempaquetado da otro hash aunque el contenido sea idéntico.
  5. ¿Te fías siquiera de la referencia? Si el archivo y su hash vienen del mismo sitio no fiable, una coincidencia no prueba nada. Un hash a secas es un detector de accidentes, no una protección contra manipulación: para una descarga pública eso significa una firma digital (GPG, Ed25519), y un HMAC solo donde ya compartes una clave secreta.

Detrás de estos cinco pasos está la idea central del principio: un desajuste demuestra que los flujos de bytes difieren; una coincidencia es prueba de igualdad, no demostración absoluta, y ninguna de las dos te dice por qué. El desajuste no es la respuesta: es la pregunta. Tu trabajo es solo decidir cuál de las tres piezas —los datos, la comparación o la referencia— se movió, y a veces se movió más de una. Cada caso de arriba es una versión concreta de eso.