crypto.createHash / createHmac în Node.js

Criptografie și utilitare Node.js 0.1.92; crypto.hash din 20.12 / 21.7 (stabil din 24.13.1 / 25.5)

Calculează amprenta (hash) unui text sau fișier cu SHA-256 și semnături HMAC pentru verificarea mesajelor.

Sintaxă
import { createHash, createHmac, hash } from "node:crypto";
createHash("sha256").update(date).digest("hex")
createHmac("sha256", cheie).update(date).digest("hex")
hash("sha256", date)

Ce face crypto.createHash / createHmac

O funcție hash transformă orice date într-o amprentă de lungime fixă: aceleași date dau mereu aceeași amprentă, iar o schimbare cât de mică dă alta complet diferită. Se folosește pentru a verifica dacă un fișier descărcat este întreg, pentru a detecta modificări sau ca cheie de cache.

createHash(algoritm) creează un obiect căruia îi dai datele cu update() (de mai multe ori, dacă vin pe bucăți) și la final ceri rezultatul cu digest("hex") sau digest("base64"). Pentru date mici, crypto.hash(algoritm, date) face totul într-un singur apel. Algoritmi uzuali: "sha256", "sha512"; "md5" și "sha1" nu mai sunt sigure, folosește-le doar pentru compatibilitate.

createHmac(algoritm, cheie) calculează o amprentă care depinde și de o cheie secretă. Așa verifici că un mesaj vine de la cineva care știe cheia: de exemplu notificările (webhook) de la procesatorii de plăți. Pentru parole nu folosi niciun hash simplu: folosește crypto.scrypt.

Parametri

Parametru Descriere
algoritm "sha256", "sha512", "sha3-256" etc. Lista: crypto.getHashes().
update(date, [codificare]) Adaugă date (șir sau Buffer); se poate apela de mai multe ori.
digest([codificare]) Termină calculul: "hex", "base64" sau, fără argument, un Buffer.
cheie La createHmac: cheia secretă.

Ce returnează

digest() întoarce amprenta ca șir sau Buffer. Obiectul nu mai poate fi folosit după digest().

Exemple

Exemplul 1: Amprenta unui text

import { createHash, hash } from "node:crypto";

console.log(createHash("sha256").update("Ana are mere").digest("hex"));
console.log(hash("sha256", "Ana are mere"));
console.log(hash("sha256", "Ana are mere."));
console.log(createHash("sha256").update("Iași").digest("base64"));

Rezultat

04c43a6d8236091578fcbebadfab4940a1f2387d3b21468f2eb6e0e01824089e
04c43a6d8236091578fcbebadfab4940a1f2387d3b21468f2eb6e0e01824089e
481656b0fa73b82651a113ec41089519b832cbdd73e1af591178610f2df58e2f
cE7/J7Amair6dYIjAsxf1osXK34A+PuEWO6aWghwK3E=

Exemplul 2: Hash pentru un fișier, pe bucăți

Obiectul hash este și stream de transformare, deci un fișier mare trece prin el fără să fie încărcat tot în memorie.

import { createHash } from "node:crypto";
import { createReadStream, writeFileSync } from "node:fs";
import { pipeline } from "node:stream/promises";

writeFileSync("factura.txt", "Factura 2026-104\nClient: Ana Popescu\nTotal: 1.250 lei\n");

const h = createHash("sha256");
await pipeline(createReadStream("factura.txt"), h);
console.log(h.digest("hex"));

Rezultat

b0ae1ab4ea6813b7f50c3a453cabcb65743308c5c55476ea0920958ecfa37cf8

Exemplul 3: Verificarea unui webhook cu HMAC

Serverul care trimite notificarea calculează semnătura cu cheia comună. Tu o calculezi din nou și compari cu timingSafeEqual, care nu dezvăluie prin durată câte caractere s-au potrivit.

import { createHmac, timingSafeEqual } from "node:crypto";

const cheie = "cheie-secreta-magazin";
const corp = JSON.stringify({ comanda: 1024, stare: "platita", suma: 250 });
const semnaturaPrimita = createHmac("sha256", cheie).update(corp).digest("hex");

function esteValid(corp, semnatura) {
  const asteptat = Buffer.from(createHmac("sha256", cheie).update(corp).digest("hex"));
  const primit = Buffer.from(semnatura);
  return primit.length === asteptat.length && timingSafeEqual(primit, asteptat);
}

console.log(esteValid(corp, semnaturaPrimita));
console.log(esteValid(corp.replace("250", "2500"), semnaturaPrimita));

Rezultat

true
false

Greșeli frecvente

  • Salvezi parolele ca sha256(parola): se sparg ușor cu tabele precalculate și plăci video. Pentru parole folosește scrypt cu sare aleatorie.
  • Compari semnăturile cu ===: durata comparației poate dezvălui cât din semnătură este corect. Folosește crypto.timingSafeEqual.
  • Apelezi digest() de două ori pe același obiect: a doua oară primești eroarea ERR_CRYPTO_HASH_FINALIZED. Creează un obiect nou pentru fiecare calcul.

Comenzi înrudite

  • crypto.scrypt (parole): Transformă o parolă într-o cheie greu de spart, cu sare aleatorie: modul corect de a salva parolele cu modulele Node.js.
  • crypto.randomBytes / randomUUID / randomInt: Valori aleatorii sigure pentru criptografie: octeți pentru chei și token-uri, UUID-uri, numere întregi într-un interval.
  • Buffer: Șir de octeți din Node.js: date binare din fișiere, rețea sau criptografie, cu conversii în text, hex și base64.
  • stream.pipeline: Leagă stream-uri în lanț (citire → transformare → scriere), cu tratarea erorilor și închiderea tuturor la final.