Hashes, salts y nonces — terminología criptográfica
En la documentación SSI aparecen estos tres términos constantemente: hash, salt, nonce. Aunque suenan similares, son cosas distintas con usos específicos. Este artículo aclara las diferencias para que no se confundan.
Hash — resumen criptográfico irreversible
Un hash es una función matemática que toma una entrada de cualquier tamaño y produce una salida de tamaño fijo. Propiedades clave:
Determinístico
Mismo input → mismo output, siempre.
Irreversible
Dado el output, no podés calcular el input.
Sensitivo a cambios
Cambiar 1 bit del input cambia drásticamente el output.
Algoritmos hash modernos comunes:
- SHA-256 (32 bytes output, default en SD-JWT VC y la mayoría de gov modernos).
- SHA-384 y SHA-512 (mayor tamaño, más resistente a ataques futuros).
- BLAKE3 (más rápido que SHA, no estandarizado en gov todavía).
Uso típico en SSI: el JWT incluye hashes de los atributos individuales (en _sd). El verificador puede confirmar autenticidad del atributo recibido recalculando el hash y comparando.
Salt — entropía aleatoria adicional
Un salt es una cadena aleatoria que se concatena con un dato antes de hashearlo. Su propósito: prevenir ataques rainbow table.
El ataque sin salt
Imagina que hasheas el dato "nombre". Cualquiera puede precalcular hashes de nombres comunes ("Juan", "María", etc.) y matchear contra hashes que vea en el sistema. Si solo hay 1000 nombres comunes y se hashean directamente, el atacante puede revelar todos.
La defensa con salt
salt = random(128 bits)
hash = sha-256(salt + nombre)
Ahora cada hash es único incluso para el mismo nombre, porque cada uno tiene su propio salt aleatorio. El atacante necesitaría precalcular hashes para todos los (salt, nombre) posibles — imposible con 128 bits de entropía.
Uso típico en SSI: cada Disclosure de SD-JWT incluye un salt único. Sin salt, los hashes en _sd serían vulnerables a rainbow table attacks.
Nonce — número usado una sola vez
Un nonce es un número (o string) que se usa exactamente una vez en un contexto criptográfico. Su propósito: prevenir replay attacks.
El ataque sin nonce
Si un sistema acepta una credencial / firma como válida sin chequear contexto, un atacante puede:
- Interceptar una presentación legítima.
- Replicarla más tarde en otro contexto.
- El sistema la acepta porque la firma es válida.
La defensa con nonce
1. Verifier genera nonce único: "abc-xyz-123"
2. Holder firma incluyendo el nonce en la presentation.
3. Verifier acepta solo si el nonce coincide con el que generó.
4. Verifier descarta el nonce después de usarlo.
Si el atacante replica la presentación, el verifier rechaza porque el nonce no coincide con el nuevo nonce activo.
Uso típico en SSI: OID4VCI usa c_nonce para evitar replay en pedidos de credencial. OID4VP usa nonce en el key binding del holder.
Las diferencias clave
| Hash | Salt | Nonce | |
|---|---|---|---|
| Qué es | Función | Cadena aleatoria | Cadena aleatoria |
| Propósito | Compresión irreversible | Prevenir rainbow tables | Prevenir replay |
| Uso | Generar hashes únicos | Adicional al input del hash | Adicional al input de la firma |
| Reusable | N/A (es función) | NO por contexto, único por dato | NO, único por sesión |
| Tamaño típico | 256 bits (32 bytes) | 128 bits (16 bytes) | 128-256 bits |
Errores comunes
Cómo se ven en código
import { randomBytes, createHash } from "node:crypto";
// Hash
const data = "Juan Pérez";
const hash = createHash("sha256").update(data).digest("hex");
// → "abc123..."
// Hash con salt
const salt = randomBytes(16).toString("hex");
const hashWithSalt = createHash("sha256").update(salt + data).digest("hex");
// Nonce
const nonce = randomBytes(16).toString("base64url");
// → "Xy_z123Abc..."
En SSI específicamente
| Donde aparece | Uso |
|---|---|
_sd array en SD-JWT | Hashes de disclosures |
| Disclosures de SD-JWT | Cada uno con salt único |
c_nonce en OID4VCI | Nonce para anti-replay |
nonce en OID4VP | Nonce para anti-replay |
| Status List index | Hash del identificador |
Referencias
- NIST SP 800-132 — Recommendation for Password-Based Key Derivation
- RFC 6151 — MD5/SHA-1 Security Considerations
Relacionados
- Firmas digitales en 5 minutos — el contexto criptográfico
- SD-JWT — cómo funciona la divulgación selectiva — uso concreto de hashes + salts en SD-JWT

