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;

Reply via email to