【发布时间】:2014-11-17 11:37:56
【问题描述】:
我正在尝试使用 AES/GCM/NoPadding 加密和解密数据。我安装了 JCE Unlimited Strength Policy Files 并运行了下面的(简单的)基准测试。我使用 OpenSSL 完成了相同的操作,并且能够在我的 PC 上实现超过 1 GB/s 的加密和解密。
通过以下基准测试,我只能在同一台 PC 上使用 Java 8 获得 3 MB/s 加密和解密。知道我做错了什么吗?
public static void main(String[] args) throws Exception {
final byte[] data = new byte[64 * 1024];
final byte[] encrypted = new byte[64 * 1024];
final byte[] key = new byte[32];
final byte[] iv = new byte[12];
final Random random = new Random(1);
random.nextBytes(data);
random.nextBytes(key);
random.nextBytes(iv);
System.out.println("Benchmarking AES-256 GCM encryption for 10 seconds");
long javaEncryptInputBytes = 0;
long javaEncryptStartTime = System.currentTimeMillis();
final Cipher javaAES256 = Cipher.getInstance("AES/GCM/NoPadding");
byte[] tag = new byte[16];
long encryptInitTime = 0L;
long encryptUpdate1Time = 0L;
long encryptDoFinalTime = 0L;
while (System.currentTimeMillis() - javaEncryptStartTime < 10000) {
random.nextBytes(iv);
long n1 = System.nanoTime();
javaAES256.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(16 * Byte.SIZE, iv));
long n2 = System.nanoTime();
javaAES256.update(data, 0, data.length, encrypted, 0);
long n3 = System.nanoTime();
javaAES256.doFinal(tag, 0);
long n4 = System.nanoTime();
javaEncryptInputBytes += data.length;
encryptInitTime = n2 - n1;
encryptUpdate1Time = n3 - n2;
encryptDoFinalTime = n4 - n3;
}
long javaEncryptEndTime = System.currentTimeMillis();
System.out.println("Time init (ns): " + encryptInitTime);
System.out.println("Time update (ns): " + encryptUpdate1Time);
System.out.println("Time do final (ns): " + encryptDoFinalTime);
System.out.println("Java calculated at " + (javaEncryptInputBytes / 1024 / 1024 / ((javaEncryptEndTime - javaEncryptStartTime) / 1000)) + " MB/s");
System.out.println("Benchmarking AES-256 GCM decryption for 10 seconds");
long javaDecryptInputBytes = 0;
long javaDecryptStartTime = System.currentTimeMillis();
final GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(16 * Byte.SIZE, iv);
final SecretKeySpec keySpec = new SecretKeySpec(key, "AES");
long decryptInitTime = 0L;
long decryptUpdate1Time = 0L;
long decryptUpdate2Time = 0L;
long decryptDoFinalTime = 0L;
while (System.currentTimeMillis() - javaDecryptStartTime < 10000) {
long n1 = System.nanoTime();
javaAES256.init(Cipher.DECRYPT_MODE, keySpec, gcmParameterSpec);
long n2 = System.nanoTime();
int offset = javaAES256.update(encrypted, 0, encrypted.length, data, 0);
long n3 = System.nanoTime();
javaAES256.update(tag, 0, tag.length, data, offset);
long n4 = System.nanoTime();
javaAES256.doFinal(data, offset);
long n5 = System.nanoTime();
javaDecryptInputBytes += data.length;
decryptInitTime += n2 - n1;
decryptUpdate1Time += n3 - n2;
decryptUpdate2Time += n4 - n3;
decryptDoFinalTime += n5 - n4;
}
long javaDecryptEndTime = System.currentTimeMillis();
System.out.println("Time init (ns): " + decryptInitTime);
System.out.println("Time update 1 (ns): " + decryptUpdate1Time);
System.out.println("Time update 2 (ns): " + decryptUpdate2Time);
System.out.println("Time do final (ns): " + decryptDoFinalTime);
System.out.println("Total bytes processed: " + javaDecryptInputBytes);
System.out.println("Java calculated at " + (javaDecryptInputBytes / 1024 / 1024 / ((javaDecryptEndTime - javaDecryptStartTime) / 1000)) + " MB/s");
}
编辑: 我把它作为一个有趣的练习来改进这个简单的基准。
我已经使用 ServerVM 进行了更多测试,删除了 nanoTime 调用并引入了预热,但正如我预期的那样,这些都没有对基准测试结果有任何改进。它以每秒 3 兆字节的速度平线。
【问题讨论】:
-
首先,基准测试是错误的:没有预热、单次迭代、过多的 nanoTime 调用。 Hotspot 的 AES-NI 内在函数仅与优化的 JIT 编译器一起使用,您必须在评估性能之前到达那里。其次,尝试 AES/CBC。你真的用 OpenSSL 测量 aes-gcm,它给了你 1 GB/s?
-
另请注意,要使用 AES-NI 内在函数,需要使用服务器 VM,这是一种支持的现代 Intel CPU,和有一个预热序列。请注意,OpenSSL 是目前最快的库之一,字节码对于业务逻辑可能相对较快,但对于密码学,您将看到与良好实现的 C/C++ 库的差异。
-
是的,我知道这不是最强大的基准测试,但 3 MB/s 与 1 GB/s 仍然非常重要,我觉得这个简单的基准测试足以说明这一点。我已经尝试过 AES/CBC,我能够获得超过 400 MB/s 的加密速度和超过 1 GB/s 的使用 Java 密码的解密速度。
-
我正在编写我自己的 JavaFX/Java EE 测试应用程序,它带有一个很棒的 GUI,它通过使用 SRP 验证用户的整个过程,然后使用 AES/GCM 通过 WebSocket 发送加密文件。应用程序完成后,我将返回一个链接。但是现在,我只想说,与未加密的文件传输相比,使用 AES/GCM 对我来说慢了大约 10 倍(96 位身份验证标签,128 位密钥和 IV)。
-
@atrioom 你没有安装Unlimited Strength Jurisdiction Policy Files。
标签: cryptography benchmarking java-8 aes-gcm