JDK-8179098 : Crypto AES/ECB encryption/decryption performance regression (introduced in jdk9b73)
  • Type: Bug
  • Component: security-libs
  • Sub-Component: javax.crypto
  • Affected Version: 9,11,12
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: x86
  • Submitted: 2017-04-21
  • Updated: 2022-06-16
  • Resolved: 2018-07-13
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 12 JDK 8 Other
11.0.2Fixed 12 b03Fixed 8u261Fixed openjdk7uFixed
Related Reports
Relates :  
Relates :  
Relates :  
Description
Modifications done by https://bugs.openjdk.java.net/browse/JDK-8076112 issue introduced performance regression for AES/ECB algorithm.

Performance JDK9 became worse than JDK8 by 20%-28%.

(data collected on Intel Core i5-5300U)

jdk8 1.8.0_65-b17
Benchmark               (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt        Score       Error  Units
AESBench.decrypt  AES/ECB/NoPadding        1024          128              thrpt   40   877361.121 ± 16739.704  ops/s
AESBench.encrypt  AES/ECB/NoPadding        1024          128              thrpt   40  1044189.005 ± 13780.381  ops/s

jdk9b72
Benchmark               (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt       Score      Error  Units
AESBench.decrypt  AES/ECB/NoPadding        1024          128              thrpt  240  824861.201 ± 6783.383  ops/s
AESBench.encrypt  AES/ECB/NoPadding        1024          128              thrpt  240  965084.477 ± 6624.554  ops/s

jdk9b73
Benchmark               (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt       Score      Error  Units
AESBench.decrypt  AES/ECB/NoPadding        1024          128              thrpt  240  733935.602 ± 3856.189  ops/s
AESBench.encrypt  AES/ECB/NoPadding        1024          128              thrpt  240  819966.663 ± 8685.148  ops/s

The reason of the performance regression in adding range checks into com.sun.crypto.provider.AESCrypt.encryptBlock/decryptBlock methods and hotspot is unable to move out of loop this checks.

Sugested fix: introduce methods encryptBlocks/decryptBlocks and move range checks out of loop manually.

Results (on jdk10):
jdk10(baseline)
Benchmark               (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt       Score       Error  Units
AESBench.decrypt  AES/ECB/NoPadding        1024          128              thrpt   40  660722.552 ± 22153.323  ops/s
AESBench.encrypt  AES/ECB/NoPadding        1024          128              thrpt   40  699155.163 ± 61539.097  ops/s

jdk10(fixed)
Benchmark               (algorithm)  (dataSize)  (keyLength)  (provider)   Mode  Cnt        Score       Error  Units
AESBench.decrypt  AES/ECB/NoPadding        1024          128              thrpt   40   939556.785 ±  9222.515  ops/s
AESBench.encrypt  AES/ECB/NoPadding        1024          128              thrpt   40  1141960.563 ± 11074.921  ops/s

Suggested fix not only remove the regression, besides it gives small speedup and finally JDK10 is 7%-9% faster than JDK8.

Suggested fix: http://cr.openjdk.java.net/~skuksenko/crypto/8179098/webrev.00/


Comments
We have pushed the backport to 11.0.4 already: JDK-8220034 -- the change is the same as in jdk/jdk, but you can eyeball it too.
05-03-2019

This addresses performance problems in more than just ECB code. I'd vote for backporting this. The essence of this fix is to perform the bounds check up one level outside the loop, should not be risky as long as the range is calculated correctly. Please look at the actual changeset instead of the suggested fix.
05-03-2019

As mentioned in Fix Request, if we don't backport this patch, then we cannot apply JDK-8201633 cleanly. This is even more risky, as it deviates from the code tested in jdk, jdk12 and jdk11-11.0.4-oracle.
28-02-2019

I'm skeptical about the need for this one. I'm assuming it fixes performance problems in ECB mode only, and that's not terribly important. It's also a non-negligible risk in the code that it touches.
28-02-2019

Fix Request Backporting this patch should improve AES performance and provide the basis for clean backport of JDK-8201633 regression fix. Patch applies cleanly to 11u, passes jdk_security and tier1 tests. I failed to confirm the performance improvement so far, but that might be indicative of benchmark's run-to-run variance: http://cr.openjdk.java.net/~shade/8179098/perf.txt
27-02-2019

URL: http://hg.openjdk.java.net/jdk/jdk/rev/080776992b29 User: valeriep Date: 2018-07-13 03:00:06 +0000
13-07-2018

Thank you, Valerie.
08-05-2017

Move the per-block-encryption bounds check outside of the loop, so it's done per encryption call.
05-05-2017

Sergey's suggested fix works but I prefer to make less code changes as long as the performance regression is taken care of. Given Zoltan's feedback, I will keep the bounds check, but move it upward to the outer loop so it does not occur for each block encryption. This way we do not have to change SymmetricCipher class with new APIs. Given that we security team knows the codebase better, I will assign myself as the RE for this.
05-05-2017

Re-assigning to the RE of JDK-8076112 as that's when the new checks are added. The input and output buffers for the encryptBlock calls are either internal buffers or already-validated external buffers whose range has been checked when they first passed in. Is it really necessary to check the ranges here again? If not, then we can simply remove these 2 new checks.
29-04-2017