Skip to content

Conversation

@karen-avetisyan-mc
Copy link
Contributor

@karen-avetisyan-mc karen-avetisyan-mc commented Nov 11, 2025

PR checklist

  • [x ] An issue/feature request has been created for this PR
  • [x ] Pull Request title clearly describes the work in the pull request and the Pull Request description provides details about how to validate the work. Missing information here may result in a delayed response.
  • [x ] File the PR against the main branch
  • [x ] The code in this PR is covered by unit tests

Description

Add AES-CBC HMAC Authentication Support for JWE (A128CBC-HS256)

📋 Summary

This PR implements HMAC authentication tag verification for AES-CBC encrypted payloads (A128CBC-HS256) in JWE, providing enhanced security and compliance with RFC 7516 (JSON Web Encryption) specification. The feature is opt-in and disabled by default to maintain backward compatibility with existing systems.


🔧 Changes

Core Implementation

1. AESCBC (src/main/java/com/mastercard/developer/encryption/aes/AESCBC.java)

  • ✨ Added enableHmacVerification parameter to decrypt() method
  • ✨ Implemented proper HMAC-SHA256 computation following JWE spec:
    • Splits 256-bit CEK into 128-bit HMAC key (first half) and 128-bit AES key (second half)
    • Computes HMAC over: AAD || IV || Ciphertext || AL (where AL = AAD length in bits as 64-bit big-endian)
    • Verifies authentication tag (first 128 bits of HMAC output) before decryption
  • ✨ Added computeAuthTag() private method for HMAC computation
  • ⚠️ Throws EncryptionException when authentication tag verification fails

2. EncryptionConfig (src/main/java/com/mastercard/developer/encryption/EncryptionConfig.java)

  • ✨ Added enableCbcHmacVerification field (default: false)
  • ✨ Added getEnableCbcHmacVerification() getter method
  • 📝 Comprehensive JavaDoc explaining when to enable HMAC verification

3. EncryptionConfigBuilder (src/main/java/com/mastercard/developer/encryption/EncryptionConfigBuilder.java)

  • ✨ Added enableCbcHmacVerification protected field (default: false)

4. JweConfigBuilder (src/main/java/com/mastercard/developer/encryption/JweConfigBuilder.java)

  • ✨ Added withEnableCbcHmacVerification(Boolean) builder method
  • 📝 Includes JavaDoc with clear guidance on when to enable

5. JweObject (src/main/java/com/mastercard/developer/encryption/jwe/JweObject.java)

  • 🔄 Updated decrypt() method to pass enableCbcHmacVerification flag to AESCBC
  • ✅ Applies verification only for A128CBC-HS256 encryption method

🧪 Testing

AESCBCTest (src/test/java/com/mastercard/developer/encryption/aes/AESCBCTest.java)

Added comprehensive test coverage (5 tests total):

Test | Description | Status -- | -- | -- testDecrypt_ShouldDecryptSuccessfully_WhenHmacVerificationIsEnabledAndTagIsValid | Creates properly encrypted JWE with correct HMAC tag, verifies successful decryption | ✅ Pass testDecrypt_ShouldThrowException_WhenHmacVerificationIsEnabledAndTagIsInvalid | Tests rejection of invalid authentication tags | ✅ Pass testDecrypt_ShouldDecryptWithoutVerification_WhenHmacVerificationIsDisabled | Verifies backward compatibility (decryption succeeds even with wrong tags) | ✅ Pass testDecrypt_ShouldUseCorrectKeySplit_WhenDecrypting | Validates proper CEK splitting (HMAC key vs AES key) | ✅ Pass testDecrypt_ShouldComputeCorrectHmac_WhenVerificationIsEnabled | End-to-end HMAC computation verification | ✅ Pass
  • RFC 7516 - JSON Web Encryption (JWE)
  • RFC 2104 - HMAC: Keyed-Hashing for Message Authentication
  • NIST SP 800-38D - Recommendation for Block Cipher Modes of Operation

📝 Files Changed

src/main/java/com/mastercard/developer/encryption/aes/AESCBC.java src/main/java/com/mastercard/developer/encryption/EncryptionConfig.java src/main/java/com/mastercard/developer/encryption/EncryptionConfigBuilder.java src/main/java/com/mastercard/developer/encryption/JweConfigBuilder.java src/main/java/com/mastercard/developer/encryption/jwe/JweObject.java src/test/java/com/mastercard/developer/encryption/aes/AESCBCTest.java src/test/java/com/mastercard/developer/encryption/JweConfigBuilderTest.java README.md

Author: Development Team
Date: November 11, 2025
Type: Feature Enhancement
Breaking Changes: None
Migration Required: None

Add AES-CBC HMAC Authentication Support for JWE (A128CBC-HS256) 📋 Summary This PR implements HMAC authentication tag verification for AES-CBC encrypted payloads (A128CBC-HS256) in JWE, providing enhanced security and compliance with RFC 7516 (JSON Web Encryption) specification. The feature is opt-in and disabled by default to maintain backward compatibility with existing systems.

🔧 Changes
Core Implementation

  1. AESCBC (src/main/java/com/mastercard/developer/encryption/aes/AESCBC.java)
    ✨ Added enableHmacVerification parameter to decrypt() method
    ✨ Implemented proper HMAC-SHA256 computation following JWE spec:
    Splits 256-bit CEK into 128-bit HMAC key (first half) and 128-bit AES key (second half)
    Computes HMAC over: AAD || IV || Ciphertext || AL (where AL = AAD length in bits as 64-bit big-endian)
    Verifies authentication tag (first 128 bits of HMAC output) before decryption
    ✨ Added computeAuthTag() private method for HMAC computation
    ⚠️ Throws EncryptionException when authentication tag verification fails
  2. EncryptionConfig (src/main/java/com/mastercard/developer/encryption/EncryptionConfig.java)
    ✨ Added enableCbcHmacVerification field (default: false)
    ✨ Added getEnableCbcHmacVerification() getter method
    📝 Comprehensive JavaDoc explaining when to enable HMAC verification
  3. EncryptionConfigBuilder (src/main/java/com/mastercard/developer/encryption/EncryptionConfigBuilder.java)
    ✨ Added enableCbcHmacVerification protected field (default: false)
  4. JweConfigBuilder (src/main/java/com/mastercard/developer/encryption/JweConfigBuilder.java)
    ✨ Added withEnableCbcHmacVerification(Boolean) builder method
    📝 Includes JavaDoc with clear guidance on when to enable
  5. JweObject (src/main/java/com/mastercard/developer/encryption/jwe/JweObject.java)
    🔄 Updated decrypt() method to pass enableCbcHmacVerification flag to AESCBC
    ✅ Applies verification only for A128CBC-HS256 encryption method
    🧪 Testing
    AESCBCTest (src/test/java/com/mastercard/developer/encryption/aes/AESCBCTest.java)
    Added comprehensive test coverage (5 tests total):

Test Description Status
testDecrypt_ShouldDecryptSuccessfully_WhenHmacVerificationIsEnabledAndTagIsValid Creates properly encrypted JWE with correct HMAC tag, verifies successful decryption ✅ Pass
testDecrypt_ShouldThrowException_WhenHmacVerificationIsEnabledAndTagIsInvalid Tests rejection of invalid authentication tags ✅ Pass
testDecrypt_ShouldDecryptWithoutVerification_WhenHmacVerificationIsDisabled Verifies backward compatibility (decryption succeeds even with wrong tags) ✅ Pass
testDecrypt_ShouldUseCorrectKeySplit_WhenDecrypting Validates proper CEK splitting (HMAC key vs AES key) ✅ Pass
testDecrypt_ShouldComputeCorrectHmac_WhenVerificationIsEnabled End-to-end HMAC computation verification ✅ Pass
JweConfigBuilderTest (src/test/java/com/mastercard/developer/encryption/JweConfigBuilderTest.java)
Added 3 configuration tests:

✅ Default behavior (HMAC disabled)
✅ Explicitly disabled
✅ Explicitly enabled
📚 Documentation
README.md
Added comprehensive section: "AES-CBC HMAC Authentication (A128CBC-HS256)"

Feature description and purpose
Configuration example with code snippet
When to enable/disable guidance
Technical implementation details
Security best practices
⚡ Backward Compatibility
✅ 100% Backward Compatible

Feature is disabled by default (enableCbcHmacVerification = false)
Existing code continues to work without modifications
No breaking changes to public APIs
Only adds optional enhancement capability
🔒 Security Improvements
When enabled, this feature provides:

Benefit Description
Data Authenticity Verifies data wasn't tampered with
Integrity Protection Detects any modifications to ciphertext
RFC 7516 Compliance Follows JWE specification exactly
Attack Prevention Protection against tampering and replay attacks with modified ciphertext
✅ Test Results
Tests run: 572, Failures: 0, Errors: 0, Skipped: 0
✅ All tests passing
✅ Full test coverage for new functionality
✅ Backward compatibility verified
💡 Usage Example
JweConfig config = JweConfigBuilder.aJweEncryptionConfig()
.withEncryptionCertificate(certificate)
.withDecryptionKey(privateKey)
.withEncryptionPath("$", "$")
.withDecryptionPath("$", "$")
.withEnableCbcHmacVerification(true) // Enable HMAC authentication
.build();
🎯 Recommendation
Scenario Recommendation
New implementations ✅ Enable HMAC verification for enhanced security
Legacy systems ⚠️ Keep disabled until both sides support HMAC properly
Production systems 🔄 Coordinate with all parties before enabling
📖 Related Standards
RFC 7516 - JSON Web Encryption (JWE)
RFC 2104 - HMAC: Keyed-Hashing for Message Authentication
NIST SP 800-38D - Recommendation for Block Cipher Modes of Operation
📝 Files Changed
src/main/java/com/mastercard/developer/encryption/aes/AESCBC.java
src/main/java/com/mastercard/developer/encryption/EncryptionConfig.java
src/main/java/com/mastercard/developer/encryption/EncryptionConfigBuilder.java
src/main/java/com/mastercard/developer/encryption/JweConfigBuilder.java
src/main/java/com/mastercard/developer/encryption/jwe/JweObject.java
src/test/java/com/mastercard/developer/encryption/aes/AESCBCTest.java
src/test/java/com/mastercard/developer/encryption/JweConfigBuilderTest.java
README.md
Author: Development Team
Date: November 11, 2025
Type: Feature Enhancement
Breaking Changes: None
Migration Required: None

…encryption for data at rest, all CaaS clients currently using AES in CBC mode must migrate to AES-CBC + HMAC. From this release forward that support will be added, and will be optional to ensure backward compatibility with the existing clients.
Comment on lines +31 to +32
// For A128CBC-HS256: First 16 bytes are HMAC key, second 16 bytes are AES key
int keyLength = cek.length / 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

We should confirm that cek.length == 32 before using it. The rest of the calculations could work in unexpected ways of cek.length is not 32.

Suggested change
// For A128CBC-HS256: First 16 bytes are HMAC key, second 16 bytes are AES key
int keyLength = cek.length / 2;
if(cek.length != 32) {
throw new IllegalArgumentException("CEK should be of length 32")
}
// For A128CBC-HS256: First 16 bytes are HMAC key, second 16 bytes are AES key
int keyLength = cek.length / 2;

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.

3 participants