Fuzzy hashing (TLSH)

Ogni hash nella pagina Hashing e autenticazione dei messaggi è costruito in modo che un singolo bit modificato produca un digest completamente diverso. TLSH (Trend Micro Locality Sensitive Hash) è costruito per fare l'opposto: input simili producono digest simili, e sgcTLSH_Diff misura quanto sono distanti due digest. Risponde a "quanto sono simili questi due file" anziché a "questi due file sono identici", il che è ciò che lo rende utile per il clustering e il rilevamento di quasi duplicati, il triage delle famiglie di malware, e per trovare documenti che sono stati copiati e leggermente modificati.

TLSH non è un hash di sicurezza. Non utilizzarlo per l'integrità o l'autenticazione.

Non è resistente alle collisioni, e un attaccante che controlla l'input può orientare deliberatamente il digest. Ogni funzione si trova in sgcCrypto_TLSH.

Calcolo di un digest

L'input deve essere di almeno 50 byte (cTLSH_MinDataLength) e sufficientemente variato da riempire più della metà dei bucket interni; un digest è di 72 caratteri (cTLSH_DigestLength), a partire dal prefisso di versione T1. Un input troppo corto o troppo uniforme (una lunga sequenza di un unico byte ripetuto, ad esempio) non ha segnale sufficiente da caratterizzare, e le funzioni seguenti restituiscono una stringa vuota anziché un digest privo di significato.


function sgcTLSH(const aData: TBytes): string;
function sgcTLSH_Stream(aStream: TStream): string;
function sgcTLSH_IsValid(const aDigest: string): Boolean;

var
  vDigest: string;
begin
  vDigest := sgcTLSH(oFileBytes);
  if vDigest = '' then
    { too short or too uniform to characterize }
  else
    { vDigest is a 72-character T1... string };
end;

Un file di grandi dimensioni non deve necessariamente essere tenuto tutto in memoria; alimentarlo a blocchi attraverso l'interfaccia di streaming, oppure passare direttamente uno stream a sgcTLSH_Stream:


procedure sgcTLSH_Init(var aContext: TsgcTLSHContext);
procedure sgcTLSH_Update(var aContext: TsgcTLSHContext; const aData: TBytes);
function sgcTLSH_Final(var aContext: TsgcTLSHContext): string;

Confronto di due digest


function sgcTLSH_Diff(const aLeft, aRight: string; aLengthDiff: Boolean = True): Integer;

Zero (cTLSH_IdenticalDiff) significa lo stesso digest; il punteggio cresce in base a quanto sono diversi i due input, senza un limite superiore fisso. Non esiste una soglia universale, va calibrata sul proprio corpus, ma come punto di partenza una distanza sotto circa 30 indica di solito lo stesso contenuto o un contenuto quasi identico, mentre valori più alti indicano una relazione progressivamente minore. aLengthDiff incorpora nel punteggio la differenza di lunghezza dell'input; disattivarlo quando si confronta contenuto legittimamente riempito (padded) o troncato, come file di log ruotati a dimensioni diverse. La funzione restituisce -1 se uno dei due digest è malformato.