This is an automated email from the ASF dual-hosted git repository.
oscerd pushed a commit to branch camel-4.14.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.14.x by this push:
new d3b442e0fcfb [backport camel-4.14.x] CAMEL-23766: camel-crypto - use
constant-time comparison for HMAC verification in HMACAccumulator
d3b442e0fcfb is described below
commit d3b442e0fcfb6cd7386dd7d23d94801a0d42c053
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Jul 3 10:41:36 2026 +0200
[backport camel-4.14.x] CAMEL-23766: camel-crypto - use constant-time
comparison for HMAC verification in HMACAccumulator
Cherry-pick of #24375 onto camel-4.14.x: constant-time MAC comparison
(MessageDigest.isEqual) in HMACAccumulator.validate().
Closes #24397
---
.../org/apache/camel/converter/crypto/HMACAccumulator.java | 14 +++++++-------
.../apache/camel/converter/crypto/HMACAccumulatorTest.java | 13 +++++++++++++
2 files changed, 20 insertions(+), 7 deletions(-)
diff --git
a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/HMACAccumulator.java
b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/HMACAccumulator.java
index c8423626a113..a1482c3bb0ed 100644
---
a/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/HMACAccumulator.java
+++
b/components/camel-crypto/src/main/java/org/apache/camel/converter/crypto/HMACAccumulator.java
@@ -19,6 +19,7 @@ package org.apache.camel.converter.crypto;
import java.io.IOException;
import java.io.OutputStream;
import java.security.Key;
+import java.security.MessageDigest;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
@@ -98,13 +99,12 @@ public class HMACAccumulator {
public void validate() {
byte[] actual = getCalculatedMac();
byte[] expected = getAppendedMac();
- for (int x = 0; x < actual.length; x++) {
- if (expected[x] != actual[x]) {
- throw new IllegalStateException(
- "Expected mac did not match actual mac\nexpected:"
- +
byteArrayToHexString(expected) + "\n actual:"
- +
byteArrayToHexString(actual));
- }
+ // Use a constant-time comparison to avoid leaking MAC-match progress
through timing (side-channel).
+ if (!MessageDigest.isEqual(expected, actual)) {
+ throw new IllegalStateException(
+ "Expected mac did not match actual mac\nexpected:"
+ + byteArrayToHexString(expected) +
"\n actual:"
+ + byteArrayToHexString(actual));
}
}
diff --git
a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/HMACAccumulatorTest.java
b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/HMACAccumulatorTest.java
index c0a8dec3995a..8a13500236b2 100644
---
a/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/HMACAccumulatorTest.java
+++
b/components/camel-crypto/src/test/java/org/apache/camel/converter/crypto/HMACAccumulatorTest.java
@@ -28,6 +28,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
public class HMACAccumulatorTest {
private byte[] payload = {
@@ -70,6 +71,18 @@ public class HMACAccumulatorTest {
validate(builder);
}
+ @Test
+ void testValidateFailsWhenAppendedMacDoesNotMatch() throws Exception {
+ int buffersize = 256;
+ byte[] buffer = initializeBuffer(buffersize);
+ // Corrupt the first byte of the appended MAC so it no longer matches
the calculated MAC
+ buffer[payload.length] ^= 0x01;
+
+ HMACAccumulator builder = new HMACAccumulator(key, "HmacSHA1", null,
buffersize);
+ builder.decryptUpdate(buffer, 40);
+ assertThrows(IllegalStateException.class, builder::validate);
+ }
+
@Test
void testDecryptionWhereMacOverlaps() throws Exception {
int buffersize = 32;