Implementar funciones de hash y HMAC desde una línea de comandos en Node.js es más sencillo de lo que parece. La librería crypto de Node actúa como un wrapper alrededor de OpenSSL, lo que significa que todos los algoritmos de hashing soportados por OpenSSL están disponibles directamente en tu proyecto. A continuación se explica paso a paso cómo construir ambas funciones y cuáles son sus diferencias fundamentales.
¿Cómo se implementa una función de hash en Node.js?
A diferencia de otros comandos criptográficos, una función de hash requiere pocos parámetros: el algoritmo, el archivo de entrada (input) y el encoding de salida [01:00]. No necesita una llave porque no se trata de un código de autenticación, sino de generar un resumen determinista del contenido.
La implementación se reduce a tres pasos:
- Llamar a
crypto.createHash(algoritmo) pasando el nombre del algoritmo como string.
- Ejecutar
.update() con el contenido del archivo leído mediante readFileSync.
- Invocar
.digest(encoding) para obtener el resumen final en el formato deseado.
typescript
import crypto from 'crypto';
import { BinaryToTextEncoding } from 'crypto';
import { readFileSync } from 'fs';
export default function hash(algorithm: string, encoding: BinaryToTextEncoding, input: string) {
return crypto.createHash(algorithm)
.update(readFileSync(input))
.digest(encoding);
}
El método digest resume toda la información acumulada en el hash y devuelve el resultado. Es importante notar que el tipo de encoding de salida es BinaryToTextEncoding, un subset más estricto que BufferEncoding [03:15].
¿Qué diferencia hay entre SHA-256, SHA-512, MD5 y Blake2?
Al ejecutar la CLI con distintos algoritmos se observan diferencias claras [04:10]:
- SHA-256: algoritmo por defecto, ampliamente utilizado y con buena resistencia a colisiones.
- SHA-512: produce un output más largo y ofrece mayor resistencia cuando se necesita un nivel superior de seguridad.
- MD5: genera un string mucho más corto, pero está deprecado en la práctica porque no es resistente a colisiones.
- Blake2: alternativa moderna con propiedades distintas según el caso de uso.
La resistencia a colisiones es la capacidad de un algoritmo para evitar que dos entradas distintas produzcan el mismo hash. Elegir el algoritmo adecuado depende de los requerimientos de tu sistema: algunos son más intensivos en recursos de cómputo y otros ofrecen propiedades adicionales como soporte para números secretos.
¿Cómo funciona un HMAC y en qué se diferencia de un hash?
Un HMAC (Hash-based Message Authentication Code) es un código de autenticación que utiliza un algoritmo de hashing junto con una llave secreta [05:45]. Esta llave es la diferencia principal respecto a un hash tradicional: se añade al contenido antes de generar el resumen.
typescript
import crypto from 'crypto';
import { BinaryToTextEncoding } from 'crypto';
import { readFileSync } from 'fs';
export default function hmac(algorithm: string, key: string, encoding: BinaryToTextEncoding, input: string) {
return crypto.createHmac(algorithm, Buffer.from(key))
.update(readFileSync(input))
.digest(encoding);
}
La llave se envuelve en un Buffer.from() porque createHmac espera la entrada en bits y bytes. Pasar un string directamente depende del encoding del sistema, y envolverlo en un buffer elimina esa ambigüedad [07:20].
¿Por qué cambiar la llave altera completamente el resultado?
Al modificar la llave de autenticación —por ejemplo, de "Platzi" a "Platzi2"— el hash resultante cambia de forma total y absoluta [08:00]. Esto se debe a que la llave forma parte integral de la información que el algoritmo procesa. Si necesitas verificar la integridad de un archivo, tanto el emisor como el receptor deben usar la misma llave para obtener el mismo resultado.
¿Dónde se usan los hashes y los HMAC en la práctica?
La construcción de hashes tiene aplicaciones que van más allá del cálculo de resúmenes [08:50]:
- TLS (Transport Layer Security): el protocolo del candadito verde en tu navegador utiliza HMACs como códigos de autenticación para establecer comunicaciones seguras.
- Árboles de Merkle: estructura que emplea hashes para verificar que una pieza de información pertenece a un grupo más grande, fundamental en blockchains y sistemas de archivos distribuidos.
- Verificación de integridad: comparar el hash de un archivo descargado con el publicado por el autor para confirmar que no fue alterado.
Estas son solo algunas de las muchas formas en que los hashes interactúan con otras herramientas criptográficas para construir protocolos robustos. ¿Has implementado alguna de estas funciones en tus proyectos? Comparte tu experiencia en los comentarios.