Crypto: Use constant-time comparison in ElG decrypt and HMAC verification

check for zero output in X25519 DH as recommmended by RFC 7748

reported by: bottomlineit.co.za
This commit is contained in:
zzz
2026-04-13 08:09:49 -04:00
parent 624df2d275
commit 5ba9ad218c
4 changed files with 8 additions and 3 deletions
@@ -471,6 +471,7 @@ public final class Curve25519 {
* @param publicKey The public key to use in the evaluation, or null
* MUST have MSB high bit cleared, i.e. publicKey[31] & 0x80 == 0
* if the base point of the curve should be used.
* @throws IllegalArgumentException on low-order input see RFC 7748
*/
public static void eval(byte[] result, int offset, byte[] privateKey, byte[] publicKey)
{
@@ -518,6 +519,7 @@ public final class Curve25519 {
state.mul(state.x_2, state.x_2, state.z_3);
// Convert x_2 into little-endian in the result buffer.
byte b = 0;
for (int index = 0; index < 32; ++index) {
int bit = (index * 8) % 26;
int word = (index * 8) / 26;
@@ -525,7 +527,10 @@ public final class Curve25519 {
result[offset + index] = (byte)(state.x_2[word] >> bit);
else
result[offset + index] = (byte)((state.x_2[word] >> bit) | (state.x_2[word + 1] << (26 - bit)));
b |= result[offset + index];
}
if (b == 0)
throw new IllegalArgumentException("low order input RFC 7748");
} finally {
// Clean up all temporary state before we exit.
state.destroy();
@@ -246,7 +246,7 @@ public final class ElGamalEngine {
// we reuse buf here for the calculated hash
_context.sha().calculateHash(rv, 0, payloadLen, buf, 0);
boolean ok = DataHelper.eq(buf, 0, val, i + 1, Hash.HASH_LENGTH);
boolean ok = DataHelper.eqCT(buf, 0, val, i + 1, Hash.HASH_LENGTH);
SimpleByteCache.release(buf);
long end = _context.clock().now();
@@ -90,7 +90,7 @@ public final class HMAC256Generator extends HMACGenerator {
byte origMAC[], int origMACOffset, int origMACLength) {
byte calc[] = acquireTmp();
calculate(key, curData, curOffset, curLength, calc, 0);
boolean eq = DataHelper.eq(calc, 0, origMAC, origMACOffset, origMACLength);
boolean eq = DataHelper.eqCT(calc, 0, origMAC, origMACOffset, origMACLength);
releaseTmp(calc);
return eq;
}
@@ -24,7 +24,7 @@ public class X25519DH {
*
* @param pub MUST have MSB high bit cleared, i.e. pub.getData()[31] &amp; 0x80 == 0
* @return ECIES_X25519
* @throws IllegalArgumentException if not ECIES_X25519
* @throws IllegalArgumentException if not ECIES_X25519 or on low-order input see RFC 7748
*/
public static SessionKey dh(PrivateKey priv, PublicKey pub) {
if (priv.getType() != TYPE || pub.getType() != TYPE)