恒定时间等于

2022-09-04 02:35:35

为了防止定时攻击,有时需要恒定的时间。有MessageDigest.isEqual没有记录为常量时间方法和番石榴HashCode.equals等。他们都做这样的事情equals

boolean areEqual = true;
for (int i = 0; i < this.bytes.length; i++) {
    areEqual &= (this.bytes[i] == that.getBytesInternal()[i]);
}
return areEqual;

    int result = 0;
    for (int i = 0; i < digesta.length; i++) {
        result |= digesta[i] ^ digestb[i];
    }
    return result == 0;

谁说JIT在优化时不能引入短路呢?

例如,这并不难发现,这永远不会再成为现实并打破循环。areEqual


我尝试了CR,方法是根据所有输入位计算一个值,并将其提供给自制的 。Blackhole


答案 1

你无法知道未来

从根本上说,您无法预测未来的优化器可能会或可能不会用任何语言做什么。

展望未来,操作系统本身提供定时常数测试的可能性最大,这样就可以在所有环境中正确测试和使用它们。

这已经持续了相当长一段时间。例如,libc 中的 timingsafe_bcmp() 函数首次出现在 OpenBSD 4.9 中。(2011年5月发布)

显然,编程环境需要拾取这些和/或提供自己的功能,这些功能保证不会被优化。

检查程序集代码

这里有一些关于优化器的讨论。这是C(和C++)的思想,但它实际上是语言独立的,你只能看看当前的优化者可以做什么,而不是未来的优化者可能会做什么。无论如何,他们理所当然地建议检查汇编代码,以了解优化程序的作用。

对于java来说,考虑到它的性质,这并不一定像C或C++那样“容易”,但是对于特定的安全功能来说,对于当前的环境来说,实际上并不是不可能做到这一点。

可以避免

您可以尝试避免计时攻击。

例如:

虽然直观地添加随机时间似乎很麻烦,但它是行不通的:攻击者已经在定时攻击中使用统计分析,你只是增加了一些噪音。

https://security.stackexchange.com/questions/96489/can-i-prevent-timing-attacks-with-random-delays

不过:这并不意味着如果你的应用程序足够慢,你就不能做一个时间常数的实现。即:等待足够长的时间。例如,您可以等待计时器关闭,然后继续处理比较结果,从而避免定时攻击。

检波

应该可以使用时序常数比较的实现将时序攻击漏洞的检测写入应用程序。

醚:

  • 在初始化期间运行的一些测试
  • 作为正常操作的一部分,定期进行相同的测试。

同样,优化器将很难处理,因为它可以(有时也会)改变事物的执行顺序。但是,例如,使用程序在其代码中没有的输入(例如外部文件),并运行两次:一次使用正常的比较和相同的字符串,一次使用完全不同的字符串(例如xored),然后再次使用这些输入,但具有恒定的时间比较。您现在有4个时间:正常比较不应该相同,恒定时间比较应该更慢且相同。如果失败:警告应用程序的用户/维护者,在生产使用中可能会破坏恒定时间的东西。

  • 理论上的选择是自己收集实际时间(也记录失败/成功),并自己进行统计分析。但是在实践中执行起来会很棘手,因为您的测量需要非常准确,因为您无法循环播放几百万次,您只处理测量一个比较,并且没有足够准确的分辨率来测量它......

答案 2

JIT不仅允许进行此类优化,而且有时实际上会这样做

以下是我在 JMH 中发现的一个示例 bug,其中短路优化导致基准测试分数不稳定。JIT 优化了 的评估,尽管它被使用而不是 ,即使 和 被声明。(bool == bool1 & bool == bool2)&&&bool1bool2volatile

JIT 不保证它能优化什么,不优化什么。即使您验证它是否按预期工作,未来的JVM版本也可能会打破这些假设。理想情况下,核心 JDK 库中应该有针对此类重要安全原语的内嵌方法。

您可以尝试通过某些技术避免不必要的优化,例如

  • 涉及易挥发性领域;
  • 应用增量积累;
  • 产生副作用,例如,写入共享内存等。

但它们也不是100%防弹的,因此您必须验证生成的汇编代码并在每次重大Java更新后重新查看它。