假设我们正在构建一个通用的时序安全比较函数以供通用使用。众所周知,当两个字符串长度相等时,它是安全的。但是,我不确定的是,如果字符串长度不同(任意),我们如何使其安全。
一个字符串将被视为“已知”,而另一个字符串将被视为“未知”。我们假设攻击者只能控制“未知”值。理想情况下,此函数不应泄漏有关已知字符串长度的任何信息。
一个简单的实现,例如:
// returns 1 is same, 0 otherwise
int timing_safe_compare(char *known, size_t known_len, char *unknown, size_t unknown_len) {
// Safe since all strings **will** be null terminated
size_t mod_len = known_len + 1;
size_t i;
int result = 0;
result = known_len - unknown_len;
for (i = 0; i < unknown_len; i++) {
result |= known[i % mod_len] ^ unknown[i];
}
return result == 0 ? 1 : 0;
}
但这里的问题是可能存在缓存信息泄漏。
例如,x64 中的字长为 64 位。所以我们可以在一个寄存器中容纳 8 个字符。如果已知值是一个不超过 7 个字符的字符串(因为我们将 known_len 加 1),则比较永远不需要对已知字符串进行另一次加载操作,即使未知字符串也会这样做。
换句话说,如果未知字符串的大小与已知字符串相差一个或多个单词边界,则正在完成的“工作”总量可能会发生变化。
我的第一直觉是只比较大小相等的字符串,但是长度信息会泄露(因为执行会遵循几个不同的分支)。
所以,这留下了两个问题:
这个微小的差异是否足以引起人们的关注?
可以在不泄露已知大小的信息的情况下防止这种差异吗?