哈希与消息认证页面中的每一种哈希,其设计目标都是让哪怕一个比特的改变 也会产生完全不相关的摘要。TLSH(趋势科技局部敏感哈希)的设计目标恰恰相反:相似的输入会产生相似的摘要, sgcTLSH_Diff 用于衡量两个摘要之间的差异程度。它回答的是“这两个文件有多相似”,而不是“这两个文件是否完全相同”, 这正是它在聚类与近似重复检测、恶意软件家族归类,以及查找被复制并轻微修改过的文档等场景中有用的原因。
TLSH 不是安全哈希,请勿将其用于完整性或身份认证目的。
它不具备抗碰撞性,能够控制输入内容的攻击者可以刻意引导摘要的走向。所有函数都位于 sgcCrypto_TLSH 单元中。
计算摘要
输入长度必须至少为 50 字节(cTLSH_MinDataLength), 并且需要有足够的变化以填充超过一半的内部桶;摘要长度为 72 个字符 (cTLSH_DigestLength), 以版本前缀 T1 开头。 一个太短或太单一的输入(例如长串重复同一个字节)没有足够的信号可供刻画, 此时下面这些函数会返回空字符串,而不是一个没有意义的摘要。
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;
大文件不需要一次性载入内存;可以通过流式接口分块处理,或者直接把一个流传给 sgcTLSH_Stream:
procedure sgcTLSH_Init(var aContext: TsgcTLSHContext);
procedure sgcTLSH_Update(var aContext: TsgcTLSHContext; const aData: TBytes);
function sgcTLSH_Final(var aContext: TsgcTLSHContext): string;
比较两个摘要
function sgcTLSH_Diff(const aLeft, aRight: string; aLengthDiff: Boolean = True): Integer;
零(cTLSH_IdenticalDiff) 表示两个摘要相同;分数会随着两个输入的差异增大而增大,且没有固定的上限。没有一个通用阈值, 需要针对您自己的语料库进行校准,但作为一个起点,距离在 30 左右以内通常表明内容相同或几乎相同, 数值越高则表示相关性依次降低。aLengthDiff 会把输入长度上的差异也计入分数;在比较那些经过合理填充或截断的内容时(例如按不同大小轮转的日志文件), 请将其关闭。如果任一摘要格式有误,函数返回 -1。