默认启用AES-NI内部函数?

33

针对AES-NI,Oracle关于Java 8的说法是:

加入了硬件内部函数来使用高级加密标准(AES)。可以使用UseAES和UseAESIntrinsics旗标启用基于Intel硬件的硬件AES内部函数。硬件必须是2010年或更新的Westmere硬件。例如,要启用硬件AES,请使用以下旗标:

-XX:+UseAES -XX:+UseAESIntrinsics

要禁用硬件AES,请使用以下标志:

-XX:-UseAES -XX:-UseAESIntrinsics
但是它没有说明是否默认启用了AES指令集(对于支持它的处理器)。所以问题很简单:如果处理器支持AES-NI,那么是否使用AES内部方法?
奖励问题:是否有任何方法可以测试是否正在使用AES-NI?我猜你可以根据性能来猜测,但这不是一种最优或确切的测试方法。
对于不熟悉AES-NI内部方法的读者:它是使用AES-NI指令集将字节码替换为预编译的机器代码。这是由JVM完成的,因此不会显示在Java运行时或字节码的API中。
2个回答

36

默认情况下,标志为true,如果检测失败,则会将其设置为false,因此您可以简单地使用+PrintFlagsFinal来查看它是否被使用:

我的笔记本没有使用AES-NI:

C:\>"C:\Program Files\Java\jdk1.7.0_51\bin\java" -XX:+PrintFlagsFinal -version | find "UseAES"
     bool UseAES                                    = false           {product}
     bool UseAESIntrinsics                          = false           {product}
java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)

在桌面端使用AES-NI:

C:\>"C:\Program Files\Java\jdk7\bin\java" -XX:+PrintFlagsFinal -version | find "AES"
     bool UseAES                                    = true            {product}
     bool UseAESIntrinsics                          = true            {product}

java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)

C:\>"C:\Program Files (x86)\Java\jre7\bin\java" -XX:+PrintFlagsFinal -version | find "AES"
     bool UseAES                                    = true            {product}
     bool UseAESIntrinsics                          = true            {product}

java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) Client VM (build 24.51-b03, mixed mode, sharing)

因此,它适用于使用最新Java 7的x64和i686(WOW64)。该功能是通过https://bugs.openjdk.java.net/browse/JDK-7184394引入的,并被反向移植到了7u40和7u45。


重要提示:AES-NI可能仅在服务器VM上可用。

在提交错误报告后,Oracle对此进行了确认。当他们创建引入Java 8的特性列表(后来也被反向移植到7)时,这个重要信息被遗漏了。服务器VM可以通过在javajavaw命令行中提供-server选项来明确选择。


4

这篇来自openjdk的邮件线程说,所有AES指令都默认启用。虽然我不确定Oracle核心VM代码有多少与openjdk共享。 如果您阅读整个线程,他们还讨论了32位VM面临的挑战,这可能解释了您第二次测试运行时遇到的问题。

  • 关于你的测试,你不觉得CPU的差异会很大吗?Core i7是四核心的,并且通常具有更好的时钟速度。这不会有所影响吗?我猜那个从21秒(core i5,32位VM,AES-NI关闭)到8秒(core i7,64位VM,AES-NI关闭)的转换就是i5和i7之间的区别。
  • 虽然改善不是七倍,但从8秒到3秒确实值得一提!:)
  • 关于检测机制--似乎没有直接的方法。如果启用了标志,则JVM会抛出警告“此CPU上无法使用AES内部功能”,如果找不到AES支持,则会像根据此错误报告

AES CBC在本质上是严格线性的,因此多个核心并不重要(当然我会使用任务调度程序或top命令)。此外,在i5上,我可以清楚地看到启用或禁用时没有性能差异。最后,似乎在错误报告中修复了有关附加CPU指令的旧检查。我没有看到任何确定为什么不支持旧CPU的东西。对于7倍的增加:那是Java 8在i5 32位和更新的i7位上运行。对于相同的类字节来说,仍然是巨大的增加 :) - Maarten Bodewes
哦,而且在普通应用程序方面,i7的性能似乎比i5快了大约2倍(我特别测试了C++编译),这是更快的,但远远不是7倍的差距。请注意,64位优化的应用程序可能会获得额外的加速。我想那些更新的CPU确实有所不同。 - Maarten Bodewes
好的,很有道理。在我的测试中,AES标志似乎没有被遵守。无论我启用还是禁用标志,执行时间都是相同的。因此,如果我们需要CPU支持引入的实际差异,我们可能需要相同的CPU - 一个禁用AES-NI,另一个启用。这里有个人有一些有趣的结果(不是Java),通过内核禁用AES-NI:https://ask.fedoraproject.org/en/question/29298/how-can-i-verify-that-my-luks-will-utilize-aes-ni-encryption-support-in-my-system/ 他的结果非常接近你的(在许多情况下为7倍)。 - Alavalathi
我还注意到Java 8在加密库方面带来了一些改进。对于小型测试(1k、2k缓冲AES-256加密),执行时间相比Java 7快2倍。 - Alavalathi
有一个 bug 报告针对使用相同密钥的 AES 初始化——如果使用相同的密钥,则不需要重新计算 AES 的密钥计划。但我以为这个已经集成了——然而,这可以解释在处理小缓冲区时速度差异的原因——你可以尝试使用 Cipher.getInstance(),看看是否使用同一个实例会有所不同。 - Maarten Bodewes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接