← Back to all articles

Detección de manipulaciones en archivos de documentos: cómo funcionan las cadenas de hashes

SealDoc Team · · 8 min read

No puedes verificar que un documento no ha sido manipulado con solo mirarlo. Un PDF modificado es visualmente idéntico al original. Un archivo sustituido tiene el mismo nombre de fichero. Una entrada de registro de auditoría editada silenciosamente no deja rastro visible.

La detección de manipulaciones requiere un mecanismo que haga que la modificación produzca un artefacto detectable, preferiblemente uno que pueda verificar alguien que no estuvo presente en la creación original. Las cadenas de hashes son uno de los mecanismos fundamentales que lo logran.

Qué hace una función hash criptográfica

Una función hash criptográfica toma una entrada de longitud arbitraria y produce una salida de longitud fija (el resumen) con dos propiedades críticas:

  1. Determinismo: la misma entrada siempre produce la misma salida
  2. Efecto avalancha: cualquier cambio en la entrada, incluso un solo bit, produce una salida completamente diferente

SHA-256 produce un resumen de 256 bits (32 bytes). Para cualquier entrada práctica, es computacionalmente inviable:

  • Encontrar dos entradas distintas que produzcan la misma salida (resistencia a colisiones)
  • Reconstruir la entrada a partir de la salida (resistencia a preimagen)
  • Producir una salida específica sin conocer la entrada (resistencia a segunda preimagen)

Estas propiedades convierten un hash SHA-256 en una huella digital fiable de un documento. Si el hash coincide, el documento es idéntico al que se procesó con el hash. Si no coincide, algo ha cambiado.

var hash = SHA256.HashData(File.ReadAllBytes("invoice.pdf"));
Console.WriteLine(Convert.ToHexString(hash));
// A3F8C2...1B7D  (64 hex chars, always the same for this file, always different if file changes)

Por qué un único hash no es suficiente

Calcular el hash de un documento te da una huella digital en un momento concreto. Pero ¿quién almacena esa huella y qué impide que alguien sustituya tanto el documento como el hash almacenado?

Si almacenas el hash en el mismo sistema que el documento, y tú controlas ese sistema, un atacante determinado (o un actor interno que quiera borrar sus huellas) puede sustituir ambos. El hash seguirá coincidiendo con el nuevo documento. La manipulación es indetectable.

Por eso la detección de manipulaciones requiere un ancla externa: un hash almacenado en algún lugar que el custodio no pueda modificar unilateralmente. Un sello de tiempo RFC 3161 es el mecanismo estándar: incrusta el hash del documento en un token firmado por una TSA de terceros. El custodio no puede alterar el token sin la clave privada de la TSA.

Qué añade una cadena de hashes

Una cadena de hashes extiende esto a una secuencia de eventos. En lugar de calcular el hash únicamente del documento, calculas el hash de cada entrada de auditoría e incluyes el hash de la entrada anterior en la actual.

Hash(Entrada N) = SHA256( DatosEvento(N) + Hash(Entrada N-1) )

Esto crea una cadena en la que cada entrada se compromete con todas las anteriores. Si modificas la Entrada 3 en una cadena de 10 entradas, el Hash(Entrada 3) cambia. Como la Entrada 4 incluye el Hash(Entrada 3), el Hash(Entrada 4) también cambia. Y así sucesivamente hasta la Entrada 10.

No se puede modificar silenciosamente una entrada pasada. La cadena no validará.

A continuación se muestra una implementación mínima:

public sealed record AuditEntry(
    string EventType,
    string Actor,
    DateTimeOffset Timestamp,
    string DocumentHash,
    string PreviousEntryHash)
{
    public string ComputeHash()
    {
        var raw = $"{EventType}|{Actor}|{Timestamp:O}|{DocumentHash}|{PreviousEntryHash}";
        return Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(raw)));
    }
}

public static string AppendEntry(IList<AuditEntry> chain, string eventType,
    string actor, byte[] documentBytes)
{
    var previousHash = chain.Count == 0
        ? new string('0', 64)
        : chain[^1].ComputeHash();

    var docHash = Convert.ToHexString(SHA256.HashData(documentBytes));
    var entry = new AuditEntry(eventType, actor, DateTimeOffset.UtcNow, docHash, previousHash);
    chain.Add(entry);
    return entry.ComputeHash();
}

public static bool VerifyChain(IList<AuditEntry> chain)
{
    var expectedPrevious = new string('0', 64);
    foreach (var entry in chain)
    {
        if (entry.PreviousEntryHash != expectedPrevious) return false;
        expectedPrevious = entry.ComputeHash();
    }
    return true;
}

La verificación es O(n) y no requiere llamadas externas. Cualquiera que tenga la cadena puede ejecutar VerifyChain y confirmar que ninguna entrada ha sido modificada.

Anclar la cadena con un sello de tiempo

Una cadena de hashes verificada prueba la consistencia interna: ninguna entrada fue modificada después de que se construyera la cadena. Pero no prueba cuándo se construyó la cadena.

Si construyes una cadena fraudulenta hoy y afirmas que representa eventos de hace tres años, la cadena validará correctamente. La cadena de hashes no tiene reloj.

Aquí es donde los sellos de tiempo RFC 3161 anclan la cadena al tiempo real. En puntos clave de la cadena (como mínimo: cuando se finaliza la cadena; idealmente en cada evento significativo), solicita un sello de tiempo a una TSA cualificada. La TSA incrusta el hash de la entrada actual en un token firmado con un sello de tiempo de confianza.

Ahora la cadena tiene un ancla externa. No puedes antedatar la cadena más allá del sello de tiempo más antiguo, porque el token de la TSA prueba que el hash existía en ese momento, y el reloj de la TSA es autoritativo.

// After appending an entry, request a timestamp for the entry hash
var entryHash = AppendEntry(chain, "created", "api:tenant-1", documentBytes);
var entryHashBytes = Convert.FromHexString(entryHash);
var timestampToken = await RequestTimestampAsync(entryHashBytes, tsaUrl);

// Store the token alongside the chain entry
chain[^1] = chain[^1] with { TimestampToken = timestampToken };

Un auditor que verifique la cadena puede:

  1. Verificar que la cadena de hashes es internamente consistente (sin modificaciones)
  2. Verificar cada token de sello de tiempo contra el certificado público de la TSA (sin antedatado)
  3. Verificar el hash del documento en cada entrada contra el documento actual (sin sustitución)

Cadenas de hashes frente a otros mecanismos de integridad

Registros de solo adición (p. ej., tablas de base de datos sin DELETE): Evitan el borrado mediante controles de acceso, pero solo son tan fiables como el sistema de control de acceso. Un administrador de base de datos puede saltárselos. Las cadenas de hashes están garantizadas matemáticamente, no por políticas.

Firmas digitales en documentos individuales: Una firma demuestra que un documento fue firmado por una clave específica en el momento de la firma. No registra qué ocurrió con el documento después. La cadena de custodia requiere registrar los eventos posteriores a la firma (transmisión, conversión, archivo), no solo el momento de la firma.

Cadena de bloques: Utiliza cadenas de hashes como primitiva fundamental, pero añade consenso distribuido para evitar que una sola parte reescriba la historia. Para archivos de documentos, una cadena de hashes local anclada con sellos de tiempo RFC 3161 externos proporciona la misma garantía de resistencia a manipulaciones sin la complejidad de una red distribuida. La distinción importa: no necesitas consenso entre desconocidos para probar que un documento no fue modificado; necesitas un ancla externa que no controles tú.

Almacenamiento WORM (Write Once Read Many): Evita la modificación en la capa de almacenamiento. El soporte físicamente no puede sobrescribirse. Esto es complementario a las cadenas de hashes, no un sustituto. WORM prueba que los bits almacenados no han cambiado. Una cadena de hashes prueba qué secuencia de eventos produjo esos bits. Ambos juntos proporcionan garantías más sólidas que cualquiera de ellos por separado.

Cómo es la verificación en la práctica

Un flujo de verificación completo para un documento en un archivo con cadena de hashes:

  1. Recuperar el documento y la pista de auditoría del archivo
  2. Calcular el SHA-256 del documento; confirmar que coincide con documentHash en la última entrada de la cadena
  3. Recorrer la cadena hacia atrás, recalculando cada entryHash y confirmando que coincide con el previousEntryHash de la siguiente entrada
  4. Para cada entrada con un token de sello de tiempo, verificar el token contra el certificado de la TSA y confirmar que el hash del token coincide con el entryHash calculado
  5. Confirmar que el hash del documento del paso 2 coincide con el hash del documento en la entrada más antigua que cubre la forma definitiva del documento

Si los cinco pasos pasan, el documento se verifica como no modificado desde su creación, la pista de auditoría registra con precisión cada paso de procesamiento, y los sellos de tiempo proporcionan anclas temporales verificables externamente.

Esta verificación requiere: el documento, la pista de auditoría, los tokens de sello de tiempo y los certificados públicos de la TSA. Sin acceso a la red. Sin dependencia de que los sistemas del custodio estén operativos. La evidencia es autónoma.

La detección de manipulaciones como infraestructura

La mayoría de las organizaciones no implementan cadenas de hashes porque las perciben como una característica avanzada. No lo son. SHA-256 está disponible en cualquier entorno de ejecución moderno. La construcción de la cadena son pocas decenas de líneas de código. El beneficio es que puedes demostrar la integridad de los documentos a un tercero escéptico sin depender de que confíen en tu organización.

Para sectores regulados (finanzas, sanidad, seguros, administración pública), esa prueba no es opcional. Para cualquier organización que quiera presentar documentos digitales como evidencia en una disputa, es la línea de base.

SealDoc implementa pistas de auditoría con cadena de hashes para cada documento de su flujo de procesamiento. La cadena se exporta en el Paquete de Evidencia Legal y es verificable sin conexión. Para organizaciones que necesiten construir su propia infraestructura de evidencia, la API de SealDoc expone la pista de auditoría y los tokens de sello de tiempo como datos estructurados que puedes incorporar a tus propios flujos de verificación.


← Back to all articles