我有两个问题我不明白。请帮我看看。谢谢。
Java中MessageDigest.isEqual函数有什么用?
解释为什么在 Java SE 6 Update 17 之前的某些版本中,它容易受到计时攻击。
我有两个问题我不明白。请帮我看看。谢谢。
Java中MessageDigest.isEqual函数有什么用?
解释为什么在 Java SE 6 Update 17 之前的某些版本中,它容易受到计时攻击。
查看 Java SE 6 Update 10 实现,我们看到:
public static boolean isEqual(byte digesta[], byte digestb[]) {
if (digesta.length != digestb.length)
return false;
for (int i = 0; i < digesta.length; i++) {
if (digesta[i] != digestb[i]) {
return false;
}
}
return true;
}
修复后我们看到:
public static boolean isEqual(byte[] digesta, byte[] digestb) {
if (digesta.length != digestb.length) {
return false;
}
int result = 0;
// time-constant comparison
for (int i = 0; i < digesta.length; i++) {
result |= digesta[i] ^ digestb[i];
}
return result == 0;
}
旧的实现似乎更有效,因为它false
在找到第一个不相等的字节时返回,但我假设它已被替换,因为它可能允许调用者测试两个输入字节数组彼此之间的相似程度关于方法的运行时间。
新实现总是具有相同的运行时间(对于相同长度的数组),因为它遍历整个数组(即使数组的第一个字节不同)。
我搜索了调用此方法的位置。一个例子是engineVerify(byte[] signature)
在com.sun.org.apache.xml.internal.security.algorithms.implementations.IntegrityHmac
课堂上,它通过将其与某个内部字节数组进行比较来测试传递给它的签名字节数组是否有效。在修复之前,通过测量该方法的运行时间,您可以尝试生成一个可以通过比较的字节数组(方法运行时间越长意味着两个数组的较大前缀相等)。
参考以下网页链接: http ://codahale.com/a-lesson-in-timing-attacks/
我可以选择我想要验证的消息——比如说一个具有特定用户 ID 的会话 cookie——然后计算 256 个可能的值:
0000000000000000000000000000000000000000
0100000000000000000000000000000000000000
0200000000000000000000000000000000000000
... snip 250 ...
FD00000000000000000000000000000000000000
FE00000000000000000000000000000000000000
FF00000000000000000000000000000000000000
我遍历这些值中的每一个,直到找到一个——A100000000000000000000000000000000000000——这比其他值长了几分之一毫秒。我现在知道该消息的 HMAC 的第一个字节应该是 A1。对剩下的 19 个字节重复这个过程,突然间我就以你的身份登录了。