Skip to content

Conversation

@jianglizhou
Copy link
Contributor

@jianglizhou jianglizhou commented Nov 17, 2025

Please review the fix in StubGenerator::aesgcm_avx512 and StubGenerator::aesgcm_avx2 to handle some edge cases with input sizes that are not multiple of the block size.

Thanks to Thomas Holenstein and Lukas Zobernig for analyzing the issue and providing the test case!


Progress

  • Change must be properly reviewed (1 review required, with at least 1 Reviewer)
  • Change must not contain extraneous whitespace
  • Commit message must refer to an issue

Issue

  • JDK-8371864: GaloisCounterMode.implGCMCrypt0 AVX512/AVX2 intrinsics stubs cause AES-GCM encryption failure for certain payload sizes (Bug - P3)

Contributors

Reviewing

Using git

Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/28363/head:pull/28363
$ git checkout pull/28363

Update a local copy of the PR:
$ git checkout pull/28363
$ git pull https://git.openjdk.org/jdk.git pull/28363/head

Using Skara CLI tools

Checkout this PR locally:
$ git pr checkout 28363

View PR using the GUI difftool:
$ git pr show -t 28363

Using diff file

Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/28363.diff

Using Webrev

Link to Webrev Comment

@bridgekeeper
Copy link

bridgekeeper bot commented Nov 17, 2025

👋 Welcome back jiangli! A progress list of the required criteria for merging this PR into master will be added to the body of your pull request. There are additional pull request commands available for use with this pull request.

@jianglizhou
Copy link
Contributor Author

/contributor [email protected]
/contributor [email protected]

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

❗ This change is not yet ready to be integrated.
See the Progress checklist in the description for automated requirements.

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou Syntax: /contributor (add|remove) [@user | openjdk-user | Full Name <email@address>]. For example:

  • /contributor add @openjdk-bot
  • /contributor add duke
  • /contributor add J. Duke <[email protected]>

User names can only be used for users in the census associated with this repository. For other contributors you need to supply the full name and email address.

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou Syntax: /contributor (add|remove) [@user | openjdk-user | Full Name <email@address>]. For example:

  • /contributor add @openjdk-bot
  • /contributor add duke
  • /contributor add J. Duke <[email protected]>

User names can only be used for users in the census associated with this repository. For other contributors you need to supply the full name and email address.

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou The following labels will be automatically applied to this pull request:

  • hotspot-compiler
  • security

When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing lists. If you would like to change these labels, use the /label pull request command.

@jianglizhou
Copy link
Contributor Author

/contributor Thomas Holenstein [email protected]
/contributor Lukas Zobernig [email protected]

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou Syntax: /contributor (add|remove) [@user | openjdk-user | Full Name <email@address>]. For example:

  • /contributor add @openjdk-bot
  • /contributor add duke
  • /contributor add J. Duke <[email protected]>

User names can only be used for users in the census associated with this repository. For other contributors you need to supply the full name and email address.

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou Syntax: /contributor (add|remove) [@user | openjdk-user | Full Name <email@address>]. For example:

  • /contributor add @openjdk-bot
  • /contributor add duke
  • /contributor add J. Duke <[email protected]>

User names can only be used for users in the census associated with this repository. For other contributors you need to supply the full name and email address.

@openjdk openjdk bot added the rfr Pull request is ready for review label Nov 17, 2025
@jianglizhou
Copy link
Contributor Author

/contributor add Thomas Holenstein [email protected]
/contributor add Lukas Zobernig [email protected]

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou
Contributor Thomas Holenstein <[email protected]> successfully added.

@openjdk
Copy link

openjdk bot commented Nov 17, 2025

@jianglizhou
Contributor Lukas Zobernig <[email protected]> successfully added.

@mlbridge
Copy link

mlbridge bot commented Nov 17, 2025


public class TestAesGcmIntrinsic {

static final SecureRandom SECURE_RANDOM = newDefaultSecureRandom();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drive-by comment: Java code should use 4x whitespace indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@TobiHartmann, thanks! Fixed.

Copy link
Member

@shipilev shipilev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! Some stylistic comments for the product fix, and suggestions for the test.


__ bind(MESG_BELOW_32_BLKS);
__ subl(len, 16 * 16);
__ cmpl(len, 256);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the stylistic logic, this should be written as 16 * 16, to match the surrounding subl and addl.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the detailed review, @shipilev! Fixed.

public static void main(String[] args) throws Exception {
TestAesGcmIntrinsic test = new TestAesGcmIntrinsic();
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < 60 * 1000) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get that you want a stress test. But time-limiting puts the test into weird condition: it can have different number of iterations, depending on auxiliary load on the machine. These tests are running in parallel with lots of other tests, so it is not uncommon. Do you even need to repeat jitFunc() call multiple times? Looks like it traverses the interesting configurations in one go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did some testing today. For 200 runs, removing the time-limited loop, there is 89 runs out of 200 fail. So I changed to use an iteration of three runs, all 200 runs fail without the fix.

for (int messageSize = SPLIT_LEN; messageSize < SPLIT_LEN + 300; messageSize++) {
byte[] message = randBytes(messageSize);
try {
byte[] ciphertext = gcmEncrypt(key, message, aad);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it makes sense to check that round-trip is successful, e.g. that decrypt(encrypt(message)) == message. Currently we implicitly rely on exceptions being thrown from the incorrectly executing code, which is IMO too weak -- in the boundary conditions like these, there might be bugs that do not manifest in visible exceptions, and just the encryption is subtly broken.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea. I added decrypt part and the check as suggested.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the changes, there were more common parts in the test. I moved common code into helper methods.

import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class TestAesGcmIntrinsic {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like TestGCMSplitBound or some such; it is not a generic test for AES/GCM intrinsic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I renamed to TestAesGcmIntrinsic name, when converting the original test into the jtreg test. TestGCMSplitBound SGTM. Changed.

throw new RuntimeException("ciphertext is null");
}
}
for (int messageSize = SPLIT_LEN; messageSize < SPLIT_LEN + 300; messageSize++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[SPLIT_LEN - 300; SPLIT_LEN + 300] for completeness, perhaps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


public class TestAesGcmIntrinsic {

static final SecureRandom SECURE_RANDOM = newDefaultSecureRandom();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you really need a SecureRandom here? Random RANDOM = Utils.getRandomInstance(); gets you the pre-seeded random instance, which can be used to repeatably reproduce failures.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kept the SecureRandom without changing. I think that could be more related to what the original reproducible.

- Rename test to TestGCMSplitBound.java
- Change test range to [SPLIT_LEN - 300; SPLIT_LEN + 300].
- Replace time-bound loop with an iteration of three runs.
- Add encrypt part and check to make sure the encrypted message is the same as the original.
@openjdk openjdk bot removed the rfr Pull request is ready for review label Nov 20, 2025
@openjdk openjdk bot added the rfr Pull request is ready for review label Nov 20, 2025
Comment on lines 86 to 89
byte[] nonce = randBytes(IV_SIZE_IN_BYTES);
System.arraycopy(ciphertext, 0, nonce, 0, IV_SIZE_IN_BYTES);
Cipher cipher = getCipher(key, aad, nonce);
return cipher.doFinal(ciphertext, IV_SIZE_IN_BYTES, ciphertext.length - IV_SIZE_IN_BYTES);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indenting is still 2-space here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed. Fixed, thanks.

AlgorithmParameterSpec params =
new GCMParameterSpec(8 * TAG_SIZE_IN_BYTES, nonce, 0, nonce.length);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keySpec, params);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Er. This is used from gcmDecrypt? How does it work without Cipher.DECRYPT_MODE?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Interestingly the test passed for me on my local machine. Fixed to use Cipher.DECRYPT_MODE when doing gcmDecrypt.

Also an interesting new finding, with the decrypted message verification, I see there are 2 failures out of 200 runs with AVX512. I'm filing a new issue on the specifically, so it can be investigated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@openjdk
Copy link

openjdk bot commented Nov 21, 2025

⚠️ @jianglizhou This pull request contains merges that bring in commits not present in the target repository. Since this is not a "merge style" pull request, these changes will be squashed when this pull request in integrated. If this is your intention, then please ignore this message. If you want to preserve the commit structure, you must change the title of this pull request to Merge <project>:<branch> where <project> is the name of another project in the OpenJDK organization (for example Merge jdk:master).

Comment on lines 3527 to +3531

__ bind(MESG_BELOW_32_BLKS);
__ subl(len, 16 * 16);
__ cmpl(len, 16 * 16);
__ jcc(Assembler::lessEqual, ENC_DEC_DONE);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the fix should instead be to just move the addl to pos before the MESG_BELOW_32_BLKS, as below:

+  __ addl(pos, 16 * 16);
   __ bind(MESG_BELOW_32_BLKS);
   __ subl(len, 16 * 16);
-  __ addl(pos, 16 * 16);

This is because on fall through path addl is needed but not while coming from line 3479 via jcc. For the latter, the addl has already been done on line 3477.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

4 participants