Hashing e autenticazione dei messaggi

Un hash crittografico trasforma una quantità qualsiasi di dati in un digest breve e di dimensione fissa. Lo stesso input produce sempre lo stesso digest, un input diverso (anche un solo bit modificato) produce un digest completamente diverso, e non esiste un modo praticabile per trovare un input che produca un digest scelto. Un codice di autenticazione del messaggio (MAC) aggiunge a questa idea una chiave segreta, in modo che il digest dimostri anche che i dati non sono stati alterati da chi non possiede la chiave.

Tutte le funzioni di questa pagina accettano e restituiscono TBytes e risiedono in sgcCrypto_SHA2, sgcCrypto_Keccak, sgcCrypto_Blake2b, sgcCrypto_Blake2s, sgcCrypto_SipHash, sgcCrypto_HMAC, sgcCrypto_CMAC e sgcCrypto_Poly1305.

SHA-2

La famiglia di hash dietro i certificati TLS, il code signing e la maggior parte dei protocolli oggi in produzione. Utilizzare SHA-256 a meno che qualcosa di specifico non richieda una dimensione diversa.


function sgcSHA1(const aData: TBytes): TBytes;
function sgcSHA224(const aData: TBytes): TBytes;
function sgcSHA256(const aData: TBytes): TBytes;
function sgcSHA384(const aData: TBytes): TBytes;
function sgcSHA512(const aData: TBytes): TBytes;

SHA-3, SHAKE, cSHAKE e KMAC

SHA-3 è costruito su una struttura diversa (Keccak) rispetto a SHA-2, quindi una debolezza in una famiglia non si ripercuote sull'altra, il che è il motivo per cui i protocolli che necessitano di garanzie a lungo termine spesso specificano entrambe. SHAKE128 e SHAKE256 sono funzioni di output estendibile: invece di una dimensione di digest fissa, si richiede tanti byte quanti ne servono, e un output più corto è sempre un prefisso di uno più lungo a partire dallo stesso input. ML-KEM, ML-DSA e SLH-DSA (vedere Crittografia post-quantistica) sono tutti costruiti internamente su SHAKE. KMAC è il codice di autenticazione dei messaggi nativo di SHA-3, costruito su cSHAKE.


function sgcSHA3_224(const aData: TBytes): TBytes;
function sgcSHA3_256(const aData: TBytes): TBytes;
function sgcSHA3_384(const aData: TBytes): TBytes;
function sgcSHA3_512(const aData: TBytes): TBytes;
function sgcSHAKE128(const aData: TBytes; aLen: Integer): TBytes;
function sgcSHAKE256(const aData: TBytes; aLen: Integer): TBytes;
function sgcKMAC128(const aKey, aData: TBytes; aLen: Integer; const aCustom: TBytes): TBytes;
function sgcKMAC256(const aKey, aData: TBytes; aLen: Integer; const aCustom: TBytes): TBytes;

BLAKE2b e BLAKE2s

BLAKE2 è più veloce di SHA-2 e SHA-3 in software pur offrendo lo stesso margine di sicurezza, e accetta direttamente una chiave opzionale, senza la costruzione HMAC. BLAKE2b è mirata alle piattaforme a 64 bit con digest fino a 512 bit; BLAKE2s è mirata alle piattaforme a 32 bit ed embedded con digest fino a 256 bit. Un digest più corto non è un troncamento di quello completo, la lunghezza è mescolata nell'hash stesso, quindi un programma non può cambiare dimensione e aspettarsi un output corrispondente.


function sgcBlake2b(const aData: TBytes; aDigestLen: Integer = 64): TBytes;
function sgcBlake2b_Keyed(const aKey, aData: TBytes; aDigestLen: Integer = 64): TBytes;
function sgcBlake2s(const aData: TBytes; aDigestLen: Integer = 32): TBytes;
function sgcBlake2s_Keyed(const aKey, aData: TBytes; aDigestLen: Integer = 32): TBytes;

SipHash

SipHash-2-4 è un hash veloce e con chiave, progettato per le ricerche nelle hash table. Il suo compito è impedire a un attaccante di fornire alla propria applicazione input scelti che finiscano tutti nello stesso bucket, trasformando una ricerca O(1) in O(n), una tecnica di denial of service nota come hash flooding. Richiede esattamente 16 byte di chiave e produce un tag di 8 byte; non è un MAC general purpose e non dovrebbe essere utilizzato per autenticare i messaggi.


function sgcSipHash24(const aKey, aData: TBytes): TBytes;

HMAC

HMAC trasforma uno qualsiasi degli hash sopra elencati in un codice di autenticazione dei messaggi. È la scelta standard quando l'hash sottostante non accetta direttamente una chiave (SHA-1, SHA-2).


function sgcHMAC_SHA1(const aKey, aData: TBytes): TBytes;
function sgcHMAC_SHA256(const aKey, aData: TBytes): TBytes;
function sgcHMAC_SHA384(const aKey, aData: TBytes): TBytes;
function sgcHMAC_SHA512(const aKey, aData: TBytes): TBytes;

var
  oTag: TBytes;
begin
  oTag := sgcHMAC_SHA256(TBytes(oKey), TBytes(oMessage));
end;

AES-CMAC

CMAC costruisce un MAC a partire da un block cipher invece che da un hash. Utilizzarlo dove un protocollo specifica AES-CMAC per nome (è comune nelle specifiche per smart card e IoT); altrimenti HMAC-SHA256 è la scelta predefinita più consueta.


function sgcAES_CMAC(const aKey, aData: TBytes): TBytes;
function sgcAES_CMAC_Verify(const aKey, aData, aTag: TBytes): Boolean;

Poly1305

Poly1305 è un autenticatore monouso: non deve mai essere utilizzato due volte con la stessa chiave. In pratica non viene chiamato direttamente, è la metà di autenticazione dei cifrari AEAD ChaCha20-Poly1305 e XChaCha20-Poly1305 nella pagina Crittografia simmetrica, che derivano una nuova chiave monouso per ogni messaggio.


function sgcPoly1305(const aKey, aData: TBytes): TBytes;
function sgcPoly1305_Verify(const aKey, aData, aTag: TBytes): Boolean;

Confrontare un MAC o un hash di password

Non confrontare mai due tag o digest con un semplice = quando uno di essi proviene da una fonte non fidata. Un confronto byte per byte che restituisce il risultato non appena trova una discrepanza impiega un tempo misurabilmente inferiore quanto prima si verifica la discrepanza, il che è un segnale sufficiente perché un attaccante possa forgiare un tag valido un byte alla volta nel corso di molti tentativi. Utilizzare invece il confronto a tempo costante di sgcCrypto_Encoding, elencato sotto Codifica e utilità nella pagina panoramica Crittografia.


function sgcConstantTimeEquals(const aLeft, aRight: TBytes): Boolean;

RIPEMD-160

Un digest a 160 bit del progetto europeo RIPE, in sgcCrypto_Legacy ma non legacy nel senso indicato dalla sezione sotto. Non è compromesso come lo sono MD5 e SHA-1, ma è più lento di SHA-256 e offre un margine di sicurezza inferiore, quindi appartiene ai casi in cui un formato lo specifica per nome piuttosto che essere una scelta predefinita. Bitcoin e ogni blockchain da esso discendente lo utilizzano per gli indirizzi, sovrapposto a SHA-256. HMAC-RIPEMD160 è l'RFC 2286.


function sgcRIPEMD160(const aData: TBytes): TBytes;
function sgcHMAC_RIPEMD160(const aKey, aData: TBytes): TBytes;

var
  oHash160: TBytes;
begin
  { il digest dell'indirizzo Bitcoin: RIPEMD-160 su SHA-256 }
  oHash160 := sgcRIPEMD160(sgcSHA256(oPublicKey));
end;

Hash legacy

sgcCrypto_Legacy fornisce MD4, MD5 e HMAC-MD5. Tutti e tre sono compromessi come primitive di sicurezza: sono state pubblicate collisioni pratiche sia per MD4 che per MD5. Esistono solo per interoperare con protocolli e formati di file più datati che li specificano per nome (ad esempio l'autenticazione NTLM). Non sceglierli per nulla di nuovo; utilizzare invece SHA-256 o BLAKE2b.


function sgcMD4(const aData: TBytes): TBytes;
function sgcMD5(const aData: TBytes): TBytes;
function sgcHMAC_MD5(const aKey, aData: TBytes): TBytes;