Skip to content

Check that integer representation of message is smaller than modulus#1252

Open
KostasTsiounis wants to merge 1 commit intoIBM:mainfrom
KostasTsiounis:rsa_check
Open

Check that integer representation of message is smaller than modulus#1252
KostasTsiounis wants to merge 1 commit intoIBM:mainfrom
KostasTsiounis:rsa_check

Conversation

@KostasTsiounis
Copy link
Copy Markdown
Member

In RSA cipher operations, the message is converted into an integer that needs to be smaller than the public key's modulus.

A check is added to fail early with the proper message, instead of failing during the actual operation with a not so helpful message.

An additional test to verify that behaviour is introduced as well.

Signed-off-by: Kostas Tsiounis kostas.tsiounis@ibm.com

Comment thread src/main/java/com/ibm/crypto/plus/provider/RSA.java Outdated
Comment thread src/main/java/com/ibm/crypto/plus/provider/RSA.java Outdated
Comment thread src/main/java/com/ibm/crypto/plus/provider/RSA.java
Comment thread src/test/java/ibm/jceplus/junit/base/BaseTestRSA.java Outdated
Comment thread src/main/java/com/ibm/crypto/plus/provider/RSA.java Outdated
this.msgBuffer.put(paddedInput);
this.msgLength = paddedInput.length;
if (this.padding.isPadding(RSAPadding.RSAPAD_NONE)) {
BigInteger m = new BigInteger(1, this.msgBuffer.array());
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I wonder if this could impact performance creating a new BigInteger on each doFinal.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

That is a possibility, but I'm not sure what we can do. I would think we need this check regardless. Do you think we might wanna skip checking here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess i cant come up with a better idea here. Maybe we can just run the RSACipherBenchmark.java just in case its significant.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would be just so we know what the impact is not that I can think of doing something better here as doing our own bit math here for comparison is unlikely to be faster then just doing the m.compareTo(n) just below this.

if (this.padding.isPadding(RSAPadding.RSAPAD_NONE)) {
BigInteger m = new BigInteger(1, this.msgBuffer.array());
BigInteger n = this.rsaPub.getModulus();
if (m.compareTo(n) >= 0) {
Copy link
Copy Markdown
Collaborator

@JinhangZhang JinhangZhang Mar 30, 2026

Choose a reason for hiding this comment

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

If I understand correctly, based on the following new test in the BaseTestRSA, when a 2048-bit rsa public key is generated, the size of this.msgBuffer will be 256. The this.msgBuffer.array() returns the full backing array (e.g., 256 bytes for a 2048-bit key), regardless of msgLength. If a user encrypts a short 5-byte message, it sits at the beginning of the buffer, followed by 251 trailing zeros (0x00).

From my understanding, for a 2048-bit RSA key, the modulus n has a length of 256 bytes. To guarantee that it is genuinely a 2048-bit number (rather than 2047 bits), the most significant bit of its first byte should be set to 1. That's being said, the first byte of any valid RSA modulus will inherently fall between 0x80 and 0xFF.

In the BigInteger.CompareTo method, it has an internal method called compareMagnitude, as you can see, it actually compares the integer bytes by bytes.

So, I was thinking a scenario, let assume, If a user inputs a valid short message whose first byte happens to be 0xFF (e.g., [0xFF, 0x00, 0x00, 0x00, 0x00]), maybe at this moment, the RSA public modulus starts with ([0x80, 0xFF, 0xFF, 0xFF, 0x80). When m.compareTo(n) is called, the underlying JDK implementation (Integer.compareUnsigned) compares the int[] mag arrays from left to right. It may evaluate m>n, and incorrectly throw the BadPaddingException for a perfectly valid short plaintext.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Maybe we can add a test to verify this?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, you are right. I thought creating a BigInteger would cover that but it only strips leading zeroes, not ones coming later on.

I added a test to verify it (it originally failed). The issue was fixed by moving the check further down after the input has been copied to the end of the backing array, making the zeroes leading, and eventually being removed during the BigInteger instantiation.

In RSA cipher operations, the message is converted into an integer
that needs to be smaller than the public key's modulus.

A check is added to fail early with the proper message, instead of
failing during the actual operation with a not so helpful message.

Additional tests to verify that behaviour are introduced as well.

Signed-off-by: Kostas Tsiounis <kostas.tsiounis@ibm.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants