Author: Martin Sansone ([email protected])
CRITICAL FOR AI ASSISTANTS:
Development Environment: This project is developed on Windows 11 with WSL2 Ubuntu, Docker Desktop, and CursorAI IDE integrated with containers.
Key Environment Details:
- OS: Windows 11 with WSL2 Ubuntu
- Containerization: Docker Desktop with container integration
- IDE: CursorAI IDE connected to development containers
- Build System: All builds, tests, and development tasks run inside Docker containers
- File System: Windows filesystem accessed through WSL2
- Terminal: Use Windows PowerShell or WSL2 bash for Docker commands
AI Assistant Guidelines:
- Always assume Docker containerized development environment
- Recommend Docker commands for Windows host (not inside containers)
- Use
dev.ps1script for container management- Consider WSL2 filesystem performance implications
- Provide Windows-specific Docker Desktop troubleshooting when needed
- Remember container networking and volume mounts for development
Common Commands:
# Windows host commands (recommended) .\dev.ps1 start # Start development container .\dev.ps1 test # Run tests in container .\dev.ps1 shell # Open shell in container # Docker commands from Windows host docker-compose up -d docker-compose logs -f
⚠️ Important: Never assume local Java/Gradle installation - everything runs in containers!
This project consists of two integrated components designed to work together:
Purpose: Sophisticated parser that accurately identifies Key-Value Pairs (KVPs) within ISO 20022 XML and JSON payment messages and successfully signs them using three different cryptographic strategies.
Key Features:
- Advanced KVP Extraction: Identifies and extracts business data KVPs from complex ISO 20022 message structures
- Three Signature Strategies:
- XML C14N + XMLDSig: W3C XML Canonicalization 1.1 + XML Digital Signatures
- RFC 8785 + JWS: JSON Canonicalization (RFC 8785) + JSON Web Signatures
- Hybrid/Detached Hash: SHA-256 digest + asymmetric signature
- Comprehensive Unit Tests: Validates KVP extraction accuracy and signature strategy effectiveness
- Cross-Format Compatibility: Works with both XML and JSON ISO 20022 message formats
Purpose: Web-based demonstration interface that showcases the full functionality of the core Iso20022KvpParser.
Key Features:
- Interactive Message Editing: Users can view and edit XML/JSON payment message examples
- Real-Time Signature Testing: Three buttons to test each signature strategy from the core project
- Tampering Detection: Validates whether canonical business data KVPs have been modified
- Signature Validation: Compares current message signatures against original core project signatures
- Full Parser Integration: Uses the actual
Iso20022KvpParserfrom the core project (not a dummy implementation)
The WebUI sub-project is intentionally included in the same codebase as the core project because:
- Separation of Concerns: Core parser logic is separate from UI presentation
- Singleton Principle: Shared
Iso20022KvpParserinstance provides consistent behavior - Real Implementation: WebUI must use the actual sophisticated parser, not a simplified version
- Unified Testing: Both components can be tested together in the same containerized environment
TSG-CrossMsg-Signing/
├── src/ # Core Iso20022KvpParser implementation
│ ├── main/java/com/tsg/crossmsg/signing/
│ │ ├── model/ # Core model classes
│ │ ├── parser/ # Iso20022KvpParser implementation
│ │ └── strategies/ # Three signature strategies
│ └── test/ # Core project unit tests
├── CrossMsg-Signing-WebUI/ # WebUI demonstration sub-project
│ ├── webui-backend/ # Spring Boot backend for WebUI
│ ├── webui-frontend/ # React frontend for WebUI
│ └── nginx/ # Reverse proxy configuration
├── docker-compose.yml # Full application deployment (WebUI)
├── dev.ps1 # Development script for core project
└── .devcontainer/ # VS Code Dev Container configuration
For working on the core Iso20022KvpParser and running unit tests:
-
Prerequisites:
- Windows 11 with Docker Desktop installed and running
- PowerShell or Command Prompt
- Git for Windows
-
Clone and Navigate:
git clone <repository-url> cd TSG-CrossMsg-Signing
-
Start Development Environment:
.\dev.ps1 start
-
Verify Setup:
docker-compose ps # Should show dev container running docker-compose exec dev ls -la /app # Should show project files docker-compose exec dev java -version # Should show Java 17 docker-compose exec dev gradle --version # Should show Gradle 8.6
-
Run Core Tests:
.\dev.ps1 test # OR docker-compose exec dev gradle test --tests "*Iso20022KvpParser*Test"
-
Verify Setup (Optional):
.\verify-setup.ps1 -
Access Development Shell:
.\dev.ps1 shell # OR docker-compose exec dev bash
For IDE-integrated development:
- Open VS Code/Cursor IDE
- Open the project folder:
C:\Projects\TSG-CrossMsg-Signing - Open in Dev Container:
- Press
Ctrl+Shift+P - Type:
Dev Containers: Open Folder in Container - Wait for container to build
- Press
- Verify Setup:
ls -la /app # Should show project files java -version # Should show Java 17 gradle --version # Should show Gradle 8.6
- Run Core Tests:
gradle test --tests "*Iso20022KvpParser*Test"
For working on both core project and WebUI together:
- Navigate to WebUI directory:
cd C:\Projects\TSG-CrossMsg-Signing\CrossMsg-Signing-WebUI
- Start full application:
docker-compose up -d
- Access WebUI: Open browser to
http://localhost:3000 - Access Backend API:
http://localhost:8080
- Windows 11 with Docker Desktop installed and running
- PowerShell or Command Prompt
- Git for Windows
- VS Code or Cursor IDE (optional, for IDE integration)
# Navigate to project root
cd C:\Projects\TSG-CrossMsg-Signing
# Start development environment
.\dev.ps1 start
# Verify container is running
docker-compose ps
# Run tests
.\dev.ps1 test
# Access development shell
.\dev.ps1 shell# Navigate to WebUI sub-project
cd C:\Projects\TSG-CrossMsg-Signing\CrossMsg-Signing-WebUI
# Start the full application stack
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the application
docker-compose down# From project root, start both core and WebUI
cd C:\Projects\TSG-CrossMsg-Signing
# Start WebUI (includes backend that uses core parser)
cd CrossMsg-Signing-WebUI
docker-compose up -d
# In another terminal, work on core project
cd C:\Projects\TSG-CrossMsg-Signing
# Use VS Code Dev Container for core development# Run all core project tests
.\dev.ps1 test
# OR
docker-compose exec dev gradle test
# Run specific KVP parser tests
docker-compose exec dev gradle test --tests "*Iso20022KvpParser*Test"
# Run signature strategy tests
docker-compose exec dev gradle test --tests "*XmlC14n*Test"
docker-compose exec dev gradle test --tests "*Jws*Test"
docker-compose exec dev gradle test --tests "*Hybrid*Test"
# Run tests with verbose output
docker-compose exec dev gradle test --info --console=plain- Start WebUI:
docker-compose up -d(from WebUI directory) - Open Browser: Navigate to
http://localhost:3000 - Test Functionality:
- View sample XML/JSON messages
- Edit message values
- Test signature strategies
- Verify tampering detection
- Container won't start:
# Clean up Docker state docker-compose down --volumes docker system prune -f .\dev.ps1 start
- Mount errors: Restart Docker Desktop and WSL2:
wsl --shutdown # Restart Docker Desktop from system tray .\dev.ps1 start
- Tests failing: Check container logs:
docker-compose logs dev docker-compose exec dev gradle test --info
- Java/Gradle issues: Container uses Java 17 and Gradle 8.6 (already configured)
- Port conflicts: Ensure ports 3000, 8080, 80, 443 are available
- Container startup failures: Check
docker-compose logsfor specific errors - Parser integration issues: Verify WebUI backend is using core project classes
- WSL2 path problems: Use explicit bind mounts in docker-compose.yml
- Permission issues: Ensure Docker Desktop has access to project directory
- Resource limits: Increase Docker Desktop memory allocation if needed
- Implementation Documentation - Detailed implementation guides
- Architecture Documentation - System architecture and design
- Security Model - Security implementation details
- Quantum Transition - Quantum-safe transition strategy
- Development Environment Setup - COMPREHENSIVE: Complete setup guide for core project and WebUI
- AI Development Environment Config - CRITICAL: AI assistant environment awareness
- Quick Setup Reference - 5-minute setup guide
- Windows Environment Setup - Complete Windows 11 + WSL2 + Docker setup
- Development Environment - Environment configuration and troubleshooting
- WebUI README - WebUI-specific documentation
- WebUI Setup Guide - WebUI setup and configuration
Note: All builds and tests for this project must be run inside Docker containers using the provided scripts (e.g.,
dev.ps1) or Docker Compose. The.vscode/settings.jsonfile is configured for code navigation and editing only; it does not affect the actual build or runtime environment. For more details, see the Windows Environment Setup Guide.🤖 AI Assistant Note: This project uses Windows 11 + WSL2 + Docker Desktop + CursorAI IDE. Always assume containerized development environment and recommend Docker-based commands. See AI Development Environment Config for complete guidelines.
⚠️ IMPORTANT: Extension Recommendation WarningWhen opening this project in CursorAI, you may see a notification asking: "Do you want to install the recommended extensions from Anysphere and auchenberg for this repository?"
IGNORE THIS NOTIFICATION - Do not install these recommended extensions. The project has been tested with an alternative extension build that works correctly for our needs. Installing the recommended extensions will cause compatibility issues and may break the project functionality. Only one version of these extensions is supported for this project, and it's already configured in the project settings.
- Improvements Log - Chronological log of all improvements
- XML Signature Implementation
- JWS Signature Implementation - JWS (RFC 7515) + JSON Canonicalization (RFC 8785)
- Hybrid/Detached Hash Implementation - Hybrid/Detached Hash strategy
- Testing Implementation
- Architecture Details
- Message Samples - Sample XML and JSON messages
- Schema Conversion
This repository provides a comprehensive, containerized test harness for evaluating signature strategies that ensure end-to-end integrity of ISO 20022 pacs.008 payment messages across format conversions (XML ↔ JSON) in a low-trust, multi-hop payment infrastructure.
- Containerized Development: All builds, tests, and development tasks run inside Docker containers for consistency and reproducibility.
- Gradle Build System: Replaces Maven for faster, more flexible builds and test execution.
- Strict Layer Separation: Code is organized by infrastructure, service, script, and test layers, with dependency injection and constructor-based initialization.
- Environment-Driven Configuration: All configuration is via environment variables, loaded from
.envfiles. No hardcoded values. - Comprehensive Testing:
- All unit and integration tests use JUnit 5, with a 5-minute timeout and resource cleanup.
- Tests are run inside the container using Gradle (
.\dev.ps1 testordocker-compose exec dev gradle test). - Test coverage includes canonicalization, signature persistence across format conversion, and negative cases (tampering, wrong key, etc.).
- Test results and coverage reports are available in
build/reports/.
- Signature Strategies:
- XML C14N + XMLDSig (W3C C14N 1.1, Apache Santuario)
- JSON Canonicalization (RFC 8785) + JWS (Nimbus JOSE + JWT)
- Hybrid/Detached Hash (SHA-256, BouncyCastle/JCA)
- Documentation Policy: All code changes must be accompanied by documentation updates. Documentation is versioned and checked alongside code.
- ✅ Core Development Environment: Docker containerized development with Java 17 and Gradle 8.6
- ✅ Iso20022KvpParser: Sophisticated parser with 1000+ lines and ISO e-Repository integration
- ✅ Three Signature Strategies: All strategies implemented and tested successfully
- ✅ Comprehensive Test Suite: 7 focused unit tests with real-world scenario validation
- ✅ Cross-Format Compatibility: XML↔JSON signature preservation validated
- ✅ Signature Exclusion Principle: All strategies correctly implemented
- ✅ Development Scripts:
dev.ps1script for easy container management
- ✅ All Tests Passing: 100% success rate across all signature strategies
- ✅ KVP Extraction: 29 payment KVPs correctly extracted from both XML and JSON
- ✅ Signature Generation: All three strategies successfully generate signatures
- ✅ Signature Verification: All signatures validate correctly
- ✅ Cross-Format Testing: XML↔JSON conversions preserve signature integrity
The core project is fully functional and ready for WebUI integration. All cryptographic operations work correctly, and the development environment is stable and reliable.
- Implementation of current standards (RSA/ECDSA)
- Focus on immediate compatibility and performance
- Core signature strategies:
- XML C14N + XMLDSig
- JSON Canonicalization (RFC 8785) + JWS
- Hybrid/Detached Hash
- Integration of quantum-safe algorithms alongside classical ones
- Support for hybrid signatures
- Enhanced security with quantum resistance
- Maintained backward compatibility
- Documentation of transition strategy
- Analysis of quantum-safe algorithm candidates
- Implementation roadmap for pure quantum-safe signatures
- CRITICAL: All documentation and code changes MUST preserve existing context and information
- Never remove or overwrite existing documentation without explicit approval
- When updating documentation:
- First review existing content thoroughly
- Preserve all existing information
- Add new information in a way that complements existing content
- Use append/merge strategies rather than replacement
- Maintain all historical context and examples
- Documentation changes require explicit approval before merging
- All AI-assisted changes must be reviewed for context preservation
- CRITICAL: All code, tests, and documentation MUST follow strict separation of concerns
- Each component, test, or document should have a single, well-defined responsibility
- No redundancy: If functionality is tested elsewhere, do not duplicate it
- Clear boundaries: Each test should focus on one specific aspect (parser accuracy, signature strategy, format conversion, etc.)
- Unique value: Every test must provide unique validation that no other test provides
- Test isolation: Tests should not depend on or duplicate functionality from other tests
- Documentation clarity: Each document should address one specific concern or aspect
- Code organization: Classes and methods should have single, clear responsibilities
- Violation detection: Before creating any new test, component, or document, verify it provides unique value not covered elsewhere
- Refactoring principle: If redundancy is found, consolidate or remove redundant elements
- Test design: Each test class should focus on one specific concern (e.g., parser accuracy, signature verification, format conversion)
- Component design: Each class should have a single responsibility and clear interface
- Documentation design: Each document should address one specific aspect of the system
- Validation: Before implementation, verify the new element provides unique value
- Review process: All changes must be reviewed for separation of concerns compliance
- TestInfrastructure Singleton: Applies Singleton design pattern to provide shared functionality while maintaining separation of concerns
- Bridge Pattern: Connects test expectations with actual signature strategy implementations
- Lazy Initialization: Strategy instances created only when needed for optimal performance
- Extensible Design: Easy to add new signature strategies without modifying existing tests
- Preserved Tests: No valuable tests were removed - only improved with better architecture
- Superior Solution: Demonstrates how to solve architectural problems using design patterns
/
├── .vscode/ # VS Code configuration
│ ├── launch.json # Debug configuration
│ └── settings.json # Java settings
├── docs/ # Documentation
│ ├── architecture/ # Architecture documentation
│ │ ├── system-design.md
│ │ ├── security-model.md
│ │ └── quantum-transition.md
│ ├── implementation/ # Implementation documentation
│ │ ├── README.md
│ │ ├── improvements.md
│ │ ├── xml-signature/
│ │ ├── testing/
│ │ └── architecture/
│ └── templates/ # Documentation templates
│ └── documentation-template.md
├── gradle/ # Gradle wrapper files
│ └── wrapper/
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── img/ # Project images and diagrams
├── iso/ # ISO 20022 related files
│ ├── samples/ # Sample messages
│ │ ├── pacs.008.xml
│ │ └── pacs.008.json
│ └── ISO 20022 - JSON Schema Draft 2020-12 generation (v20250321) (clean).docx
├── puml/ # PlantUML diagrams
├── scripts/ # Utility scripts
│ └── healthcheck.sh # Container health check
├── src/
│ ├── main/
│ │ └── java/com/tsg/crossmsg/signing/
│ │ └── model/ # Core model classes
│ └── test/
│ └── java/com/tsg/crossmsg/signing/
│ ├── hybrid/ # Hybrid signature tests
│ ├── jws/ # JWS signature tests
│ ├── xmlsig/ # XML signature tests
│ ├── BaseSigningTest.java
│ ├── MessageConverterTest.java
│ ├── ProjectSetupTest.java
│ └── SignatureStrategyTest.java
├── target/ # Build output directory
├── .dockerignore # Docker ignore rules
├── .gitignore # Git ignore rules
├── build.gradle # Gradle build configuration
├── dev.ps1 # Development script
├── docker-compose.yml # Docker compose configuration
├── Dockerfile # Docker build configuration
├── gradle.properties # Gradle properties
├── README.md # Project documentation
└── settings.gradle # Gradle settings
- Each code change must include corresponding documentation updates
- Documentation is versioned alongside code
- Automated checks ensure documentation stays in sync
- Regular documentation reviews as part of code review process
- ISO 20022 pacs.008.001.09 payment (
<BizMsgEnvlp>+<Document><FIToFICstmrCdtTrf>payload). - Full BizMsgEnvlp wrapper must travel with signature container intact.
- XML → JSON: deterministic mapping (strip prefixes, Ccy →
{"amt","Ccy"}, elements → objects/arrays). - JSON → XML: reverse mapping producing identical XML structure for canonicalization.
- Canonicalization: process of transforming data to a canonical byte stream for stable hashing or signing.
- Signature Container: an element/property in the message header that carries the digital signature or digest.
For all digital signature strategies in this project, the signature or digest must always be calculated over the message content, explicitly excluding the signature itself.
- XMLDSig: Enforced by the enveloped signature transform (W3C XMLDSig), which ensures the
<Signature>element is excluded from the digest calculation.- JWS (JSON Web Signature): Canonicalization and signing are performed over the JSON object without the signature property, as required by RFC 7515 and RFC 8785.
- Hybrid/Detached Hash: The digest is always computed over the message, and the signature is stored separately.
If this rule is not followed, signature validation will always fail. This project enforces and audits this rule for every strategy.
- Use W3C XML Canonicalization 1.1 to produce a stable byte stream of the XML payload.
- Generate an XML Digital Signature (
XMLDSig) over those bytes. - Embed the
<Signature>element in the ISO 20022 AppHdr (<Sgntr>slot).
- Prepare XML: ensure namespaces and whitespace conform to the spec.
- Canonicalize: apply exclusive C14N 1.1 transform.
- Sign: use Apache Santuario to generate
<Signature>over the canonical bytes. - Embed: insert
<Signature>into<AppHdr>ofBizMsgEnvlp. - Transmit: deliver as XML or convert to JSON (leaving
<Signature>untouched). - Verify:
- Extract
<Signature>from AppHdr. - If JSON, convert back to XML via deterministic mapping.
- Canonicalize (C14N 1.1).
- Use XMLDSig verifier with sender's public key.
- Extract
- Libraries: Apache Santuario (XMLSec), JUnit 5
- Canonicalization Method URI:
http://www.w3.org/2006/12/xml-c14n11 - Signature Algorithm:
RSA_SHA256orECDSA_SHA256
Signature Exclusion Principle: This strategy uses the enveloped signature transform to ensure the
<Signature>element is excluded from the digest calculation, as required by the XMLDSig standard.
- Serialize the full
BizMsgEnvlpJSON object using RFC 8785 canonicalization (sorted keys, stripped whitespace). - Generate a JSON Web Signature (JWS) over the canonical bytes.
- Carry the compact JWS string in a top-level
"Signature"property of the JSON AppHdr.
- Prepare JSON: ensure consistent field ordering, no extraneous whitespace.
- Canonicalize: apply RFC 8785 to produce canonical UTF-8 bytes.
- Sign: use Nimbus JOSE + JWT to create a JWS (e.g.,
ES256orEdDSA). - Embed: insert JWS compact serialization into
AppHdr.Signature. - Transmit: deliver as JSON or convert to XML, mapping the
Signatureproperty to an XML element. - Verify:
- Extract JWS from
Signatureproperty or XML<Signature>element. - Reconstruct JSON via XML→JSON mapping if needed.
- Canonicalize (RFC 8785).
- Verify JWS using the sender's public key.
- Extract JWS from
- Libraries: Nimbus JOSE + JWT, JUnit 5
- Canonicalization Spec: RFC 8785 JSON Canonicalization Scheme
- JWS Algorithms:
ES256,Ed25519
Signature Exclusion Principle: This strategy canonicalizes and signs the JSON object without the signature property, as required by JWS and RFC 8785.
- Compute a deterministic digest (SHA-256 or HMAC-SHA256) over the canonical representation of the message (XML C14N or RFC 8785 JSON).
- Sign only the digest with an asymmetric key (RSA/ECDSA/EdDSA).
- Carry the signed digest (base64 or hex) in a lightweight header field (e.g.,
AppHdr.MsgDgstor JSON property).
- Canonicalize: same as Strategy 1 or 2 to produce a stable byte stream.
- Digest: compute SHA-256 hash (or HMAC if a shared secret is used).
- Sign Digest: use private key to sign the hash.
- Embed: place the signed digest string into a dedicated header slot.
- Transmit: deliver as XML or JSON.
- Verify:
- Extract signed digest from header.
- Re-canonicalize message.
- Re-compute digest.
- Verify digest signature with public key.
- Libraries: Java
MessageDigest, BouncyCastle or JCA for signatures, JUnit 5 - Hash Algorithm:
SHA-256 - Signature Algorithm:
RSA_SHA256orECDSA_SHA256
Signature Exclusion Principle: The digest is always computed over the message content, and the signature is stored separately. The signature is never included in the digest.
After comprehensive testing of all three signature strategies across XML↔JSON format conversions, a critical finding emerged:
All three strategies in this project are limited to business data KVPs only - they extract the same 29 payment fields using Iso20022KvpParser and hash only the business data, not the full document structure.
| Strategy | Canonicalization Method | Cross-Format Behavior | Success Rate |
|---|---|---|---|
| XML C14N + XMLDSig | Always uses XML C14N 1.1 | ✅ WORKS across formats | 100% |
| RFC 8785 + JWS | Always uses JSON RFC 8785 | ✅ WORKS across formats | 100% |
| Hybrid/Detached Hash | Format-specific (XML C14N for XML, RFC 8785 for JSON) | ❌ FAILS across formats | 0% |
Both strategies use consistent canonicalization regardless of original format:
// JSON→XML scenario:
Map<String, String> businessKvps = extractKvps(jsonMessage);
String xmlFormat = convertKvpsToXml(businessKvps); // Convert to XML
String canonicalXml = XML_C14N_1_1(xmlFormat); // Always use XML C14N
String hash = SHA256(canonicalXml);
// XML→JSON scenario:
Map<String, String> businessKvps = extractKvps(xmlMessage);
String xmlFormat = convertKvpsToXml(businessKvps); // Already XML
String canonicalXml = XML_C14N_1_1(xmlFormat); // Same XML C14N
String hash = SHA256(canonicalXml);
// Result: Same hash, same signature validation!// XML→JSON scenario:
Map<String, String> businessKvps = extractKvps(xmlMessage);
String jsonFormat = convertKvpsToJson(businessKvps); // Convert to JSON
String canonicalJson = RFC_8785(jsonFormat); // Always use RFC 8785
String hash = SHA256(canonicalJson);
// JSON→XML scenario:
Map<String, String> businessKvps = extractKvps(jsonMessage);
String jsonFormat = convertKvpsToJson(businessKvps); // Already JSON
String canonicalJson = RFC_8785(jsonFormat); // Same RFC 8785
String hash = SHA256(canonicalJson);
// Result: Same hash, same signature validation!The Hybrid strategy uses format-specific canonicalization without conversion:
// JSON→XML scenario:
Map<String, String> businessKvps = extractKvps(jsonMessage);
String canonicalJson = RFC_8785(convertKvpsToJson(businessKvps)); // JSON canonicalization
String hash1 = SHA256(canonicalJson);
// XML→JSON scenario:
Map<String, String> businessKvps = extractKvps(xmlMessage);
String canonicalXml = XML_C14N_1_1(convertKvpsToXml(businessKvps)); // XML canonicalization
String hash2 = SHA256(canonicalXml);
// Result: Different hashes, signature validation fails!For ISO 20022 cross-format message signing:
- ✅ Use XML C14N + XMLDSig - Most reliable, established W3C standard
- ✅ Use RFC 8785 + JWS - Modern IETF standard, excellent for JSON-first workflows
- ❌ Avoid Hybrid/Detached Hash - Not suitable for cross-format scenarios
The key insight: Choose a strategy that uses consistent canonicalization method across all format conversions, not format-specific canonicalization.
The standardized cross-format behavior demonstrated by XML C14N + XMLDSig and RFC 8785 + JWS strategies is fundamentally enabled by the project's Iso20022KvpParser implementation.
// All three strategies use the same parser
Iso20022KvpParser kvpParser = new Iso20022KvpParser();
// XML format
Map<String, String> xmlKvps = kvpParser.extractKvpsFromXml(xmlMessage);
// JSON format
Map<String, String> jsonKvps = kvpParser.extractKvpsFromJson(jsonMessage);
// Result: Identical 29 KVPs regardless of format
assertEquals(xmlKvps, jsonKvps); // Always true- Same extraction logic for both XML and JSON
- Identical field mapping using ISO 20022 glossary
- Consistent key naming across formats
- Predictable output regardless of input format
// Strategy can choose canonicalization method independently
Map<String, String> businessKvps = kvpParser.extractKvps(message);
// XML C14N + XMLDSig: Always convert to XML
String xmlFormat = convertKvpsToXml(businessKvps);
String canonicalXml = XML_C14N_1_1(xmlFormat);
// RFC 8785 + JWS: Always convert to JSON
String jsonFormat = convertKvpsToJson(businessKvps);
String canonicalJson = RFC_8785(jsonFormat);The project currently uses a static parser implementation with the following characteristics:
// Static mapping ensures consistency
private static final Map<String, String> ISO_20022_GLOSSARY = new HashMap<>();
static {
ISO_20022_GLOSSARY.put("BizMsgIdr", "BusinessMessageIdentifier");
ISO_20022_GLOSSARY.put("MsgDefIdr", "MessageDefinitionIdentifier");
// ... comprehensive mapping
}// Parser provides format-agnostic business data
Map<String, String> businessKvps = kvpParser.extractKvps(message);
// Strategy can apply any canonicalization method
if (strategy == XML_C14N) {
return canonicalizeAsXml(businessKvps);
} else if (strategy == RFC_8785) {
return canonicalizeAsJson(businessKvps);
}// Easy to test extraction consistency
@Test
void testCrossFormatExtraction() {
Map<String, String> xmlKvps = kvpParser.extractKvpsFromXml(xmlSample);
Map<String, String> jsonKvps = kvpParser.extractKvpsFromJson(jsonSample);
// Should be identical for same business data
assertEquals(xmlKvps, jsonKvps);
}The current static implementation provides a solid foundation, but future enhancements could include:
- Automatic field mapping from ISO e-Repository
- Support for new message types without code changes
- Real-time schema updates as ISO standards evolve
- Runtime message type detection
- Automatic field extraction for any ISO 20022 message
- Dynamic canonicalization based on message structure
- Performance optimization for dynamic parsing
- Caching strategies for frequently used schemas
- Fallback mechanisms for offline operation
The current Iso20022KvpParser design directly enables the successful cross-format signature validation demonstrated by XML C14N + XMLDSig and RFC 8785 + JWS strategies. The consistent extraction of business data KVPs provides the foundation for reliable cross-format canonicalization.
Future enhancements could expand this capability to handle the full ISO 20022 message universe dynamically, but the current implementation already provides the essential functionality needed for robust cross-format signature validation.
/src/test/java
/xmlsig → XMLDSig tests
/jws → JSON Canonical + JWS tests
/hybrid → Detached-hash tests
/resources
sample.xml
sample.json
README.md
For each strategy:
- Sign sample XML
- Convert signed XML → JSON, ensure header signature persists
- Verify signature in JSON
- Convert signed JSON → XML, ensure header signature persists
- Verify signature in XML
- Gradle: Use
gradlecommand directly in CursorAI IDE Terminal- Run strategy tests:
gradle test --tests "*StrategyTest" - Run all tests:
gradle test
- Run strategy tests:
- Docker: Use
dev.ps1script for building and running tests in containers - CursorAI: Use provided Java classes and sample files to autotest conversion & verification
- Windows 11 with Docker Desktop installed and running
- CursorAI IDE (recommended for development)
- Git for Windows
This project is configured to run in Windows Docker Desktop containers. All build processes, tests, and development tasks are containerized to ensure consistency across development environments.
Key points:
- Uses Windows Docker Desktop for container management
- All Java/Gradle operations run inside containers
- No local Java or Gradle installation required
- Development script (
dev.ps1) handles Docker operations - Container configuration optimized for Windows filesystem
The project is set up for development in CursorAI IDE with:
- Docker Desktop integration
- Remote debugging support (port 5005)
- PowerShell script integration
- Gradle project recognition
This project uses Docker for development to ensure consistency across all environments. The setup includes:
-
Development Container
- Java 17 (Eclipse Temurin)
- Gradle 8.6
- PowerShell
- All project dependencies
-
Container Structure
- Multi-stage build for optimized production images
- Development container with full tooling
- Debug container with remote debugging support
- Health checks for container monitoring
-
Available Commands
.\dev.ps1 start # Start the development container .\dev.ps1 stop # Stop the development container .\dev.ps1 build # Build the project .\dev.ps1 test # Run tests .\dev.ps1 clean # Clean build files .\dev.ps1 shell # Open a shell in the dev container .\dev.ps1 help # Show all available commands
-
Container Services
app: Main application containerapp-debug: Debug-enabled container (port 5005)dev: Development container with full tooling
-
Volume Management
- Source code mounted at
/app - Gradle cache persisted in
gradle-cachevolume - Hot-reload support for development
- Source code mounted at
-
Remote Debugging
- Debug port: 5005
- Connect your IDE to
localhost:5005 - Use
app-debugservice for debugging
-
Prerequisites
- Windows 11 with Docker Desktop installed
- Docker Desktop configured for Windows containers
- PowerShell 7+ (included in container)
-
Initial Setup
# Start the development environment .\dev.ps1 start # Build the project .\dev.ps1 build # Run tests .\dev.ps1 test
-
Development Workflow
- Start the container:
.\dev.ps1 start - Get a shell:
.\dev.ps1 shell - Build changes:
gradle build - Run strategy tests:
gradle test --tests "*StrategyTest" - Stop when done:
.\dev.ps1 stop
- Start the container:
-
Debugging
- Start debug container:
docker-compose up app-debug - Connect IDE to
localhost:5005 - Set breakpoints in your IDE
- Run tests or application to hit breakpoints
- Start debug container:
-
Development Container (Dockerfile)
FROM eclipse-temurin:17-jdk-windowsservercore-ltsc2022 WORKDIR /app # ... (see Dockerfile for full configuration)
-
Docker Compose Services
services: app: build: context: . target: builder app-debug: build: context: . target: builder dev: build: context: . dockerfile: Dockerfile
-
Volume Configuration
volumes: gradle-cache: name: tsg-crossmsg-signing-gradle-cache
-
Development
- Always use the development container for coding
- Keep the container running during development
- Use the provided scripts for all operations
- Commit the Gradle wrapper to version control
-
Testing
- Run strategy tests:
gradle test --tests "*StrategyTest" - Run all tests:
gradle test - Use debug container for test debugging
- Check test reports in
build/reports/tests
- Run strategy tests:
-
Building
- Use
gradle buildfor consistent builds - Clean builds with
gradle clean - Check build reports in
build/reports
- Use
-
Container Management
- Start/stop containers as needed
- Use
docker-compose psto check status - Monitor container health with
docker-compose ps
-
Common Issues
- Container won't start: Check Docker Desktop status
- Build fails: Try
.\dev.ps1 cleanfirst - Tests fail: Check container logs
- Debug not connecting: Verify port 5005 is free
-
Container Logs
# View container logs docker-compose logs dev # Follow logs docker-compose logs -f dev
-
Resource Management
- Monitor container resources in Docker Desktop
- Clean up unused containers:
docker-compose down - Clear Gradle cache if needed:
docker volume rm tsg-crossmsg-signing-gradle-cache
- Canonical Form: the exact byte stream inputs to hash or signature
- Signature Container: header field or XML element carrying the signature
- Signer: originator; Verifier: any intermediary or final recipient
- W3C C14N 1.1: https://www.w3.org/TR/xml-c14n11/
- JSON Canonicalization RFC 8785: https://datatracker.ietf.org/doc/html/rfc8785
- JWS (RFC 7515): https://datatracker.ietf.org/doc/html/rfc7515
- ISO 20022 AppHdr spec (head.001.001.02)
- Set up automated documentation checks
- Implement Phase 1 signature strategies
- Document implementation details
- Begin Phase 2 hybrid implementation planning
- Create comprehensive quantum transition documentation
The project includes ISO 20022 message samples and conversion documentation:
- XML samples:
src/test/resources/iso/SinglePriority_Inbound_pacs.008.xmlsrc/test/resources/iso/SinglePriority_Outbound_pacs.008.xml
- JSON sample:
src/test/resources/iso/SinglePriority_Inbound-pacs008.json
- Schema conversion guide:
src/test/resources/iso/ISO 20022 - JSON Schema Draft 2020-12 generation (v20250321) (clean).docx
The conversion process follows these key principles:
-
XML to JSON:
- Strip XML prefixes
- Convert currency elements to
{"amt","Ccy"}format - Transform elements to objects/arrays
- Preserve namespace information in JSON structure
- Handle both inbound and outbound message formats
-
JSON to XML:
- Reverse mapping to produce identical XML structure
- Maintain canonicalization compatibility
- Preserve namespace declarations
- Ensure XML schema validation
- Support bidirectional conversion
The project uses Gradle with comprehensive test configuration:
- JUnit 5 for test framework
- JaCoCo for code coverage
- Parallel test execution
- Detailed test reporting
- 5-minute test timeout
- Memory-optimized test execution
Test reports are available in:
- HTML:
build/reports/tests/html/index.html - XML:
build/reports/tests/xml/ - Coverage:
build/reports/jacoco/html/index.html
To run tests in the CursorAI IDE Terminal:
# Run all focused KVP parser tests with TestInfrastructure Singleton
gradle test --tests "*Iso20022KvpParser*Test"
# Run specific direction tests
gradle test --tests "*XmlToJson*Test" # XML to JSON direction tests
gradle test --tests "*JsonToXml*Test" # JSON to XML direction tests
# Run specific strategy tests
gradle test --tests "*XmlC14n*Test" # XML C14N + XMLDSig tests
gradle test --tests "*Jws*Test" # JSON Canonicalization + JWS tests
gradle test --tests "*Hybrid*Test" # Hybrid/Detached Hash tests
# Run direct comparison test
gradle test --tests "*DirectComparison*Test"
# Run project setup test
gradle test --tests "*ProjectSetup*Test"# Run all tests with maximum verbosity
gradle test --info --debug
# Run all tests with standard verbosity
gradle test --infoThe project now uses a cleaner, more focused approach that eliminates format conversion complexity and focuses on genuine payment data integrity. Instead of converting between XML and JSON formats (which introduced conversion errors), the tests use matching ISO 20022 message pairs that contain identical payment data in different syntax formats. The approach uses TestInfrastructure Singleton to provide superior architecture and shared functionality.
The test suite consists of seven focused unit tests, each testing one specific responsibility with no redundancy:
-
XML to JSON - XML C14N + XMLDSig (
Iso20022KvpParserXmlToJsonXmlC14nTest.java):- Tests XML C14N 1.1 canonicalization on XML format
- Tests XMLDSig signature generation and verification
- Verifies KVP extraction and preservation
- Validates signature exclusion principle
-
JSON to XML - XML C14N + XMLDSig (
Iso20022KvpParserJsonToXmlXmlC14nTest.java):- Tests XML C14N + XMLDSig strategy on JSON-derived data
- Verifies KVP consistency between JSON and XML formats
- Tests signature exclusion principle on JSON data
-
XML to JSON - JSON Canonicalization + JWS (
Iso20022KvpParserXmlToJsonJwsTest.java):- Tests RFC 8785 JSON canonicalization on XML-derived data
- Tests JWS signature generation and verification
- Verifies KVP extraction and preservation
-
JSON to XML - JSON Canonicalization + JWS (
Iso20022KvpParserJsonToXmlJwsTest.java):- Tests RFC 8785 + JWS strategy on JSON format
- Verifies KVP consistency between formats
- Tests signature exclusion principle
-
XML to JSON - Hybrid/Detached Hash (
Iso20022KvpParserXmlToJsonHybridTest.java):- Tests SHA-256 digest computation on XML format
- Tests RSA signature generation and verification
- Verifies detached hash signature principles
-
JSON to XML - Hybrid/Detached Hash (
Iso20022KvpParserJsonToXmlHybridTest.java):- Tests Hybrid/Detached Hash strategy on JSON format
- Verifies KVP consistency between formats
- Tests signature exclusion principle
- Eliminates Conversion Complexity: No more format conversion between XML and JSON
- Focuses on Genuine Payment Data: Tests extract and compare actual payment KVPs, ignoring structural elements
- Strict Separation of Concerns: Each test has a single, well-defined responsibility with no redundancy
- Consistent Test Structure: All tests follow the same pattern for easy maintenance
- Validates KVP Parser: Confirms correct filtering of structural elements vs. payment data
- TestInfrastructure Singleton: Superior architecture using Singleton Principle for shared functionality
- Preserved All Tests: No valuable tests were removed, only improved with better architecture
-
KVP Extraction Tests:
@Test @Tag("unit") void testKvpExtractionFromMatchingFiles() { // Load both XML and JSON samples directly // Extract KVPs from both formats // Verify identical payment data // Validate structural elements are ignored }
-
Signature Strategy Tests:
@Test @Tag("unit") void testSignatureStrategyOnFormat() { // Test specific signature strategy on format // Verify signature generation and verification // Validate KVP preservation through signing }
-
Signature Exclusion Tests:
@Test @Tag("unit") void testSignatureExclusionPrinciple() { // Verify signature is excluded from digest calculation // Validate signature exclusion principle compliance }
-
Real-World Scenario Tests:
@Test @Tag("unit") void testRealWorldScenario() { // Test complete flow: format → signature → conversion → validation // Verify signature preservation across format conversions // Validate backward compatibility for signature strategies }
Note: Tampering detection is reserved for integration/UI testing scenarios to maintain separation of concerns and focus on backward compatibility validation.
The following test validates basic project configuration:
- Project Setup Test (
ProjectSetupTest.java):- Validates key pair generation
- Ensures cryptographic algorithms are available
- Verifies basic project dependencies
-
Sample Loading:
- Samples are loaded from
src/test/resources/iso/directory - Cached in memory for test performance
- Validated against schema before use
- Namespace declarations preserved
- Samples are loaded from
-
Test Categories:
@Tag("unit"): Individual component tests@Tag("integration"): End-to-end flow tests@Tag("slow"): Performance-intensive tests
-
Test Resources:
- XML samples for inbound/outbound flows
- JSON converted samples
- Schema validation files
- Test key pairs and certificates
-
Validation Steps:
- Schema compliance
- Namespace preservation
- Signature validity
- Format conversion accuracy
- Header integrity
-
Local Development:
.\dev.ps1 test # Run all tests .\dev.ps1 test --tests *Xml* # Run XML-specific tests .\dev.ps1 test --tests *Json* # Run JSON-specific tests
-
Docker Environment:
- Tests run in isolated containers
- Consistent environment across platforms
- Resource limits enforced
- Reports accessible via volume mounts
-
Continuous Integration:
- Automated test execution
- Coverage reporting
- Test result archiving
- Performance monitoring
- Change: Major test suite refactoring to implement cleaner, granular unit test approach with TestInfrastructure Singleton
- Reason: Eliminate format conversion complexity, focus on genuine payment data integrity, and apply superior architecture using Singleton Principle
- Impact: Seven focused unit tests with TestInfrastructure Singleton replace complex integration tests, cleaner test execution, preserved all valuable tests
- Migration: Use new focused tests (
*Iso20022KvpParser*Test) with TestInfrastructure Singleton instead of legacy integration tests
- Change: Major update for containerized Gradle-based development, strict layer separation, and comprehensive test strategy
- Reason: Align documentation with new codebase and workflow
- Impact: All users and contributors must use the containerized workflow and follow updated test/documentation policies
- Migration: See updated README and docs for new workflow
- Change: Initial system design documentation
- Reason: Project initialization
- Impact: Establishes baseline architecture
- Migration: N/A
All signature strategies in this project produce detailed, auditable output files during signing and verification. Every output file includes a Strategy: identifier in its header, making it clear which cryptographic approach was used for each operation. This is critical for standards compliance, global interoperability, and for the ISO TSG committee to evaluate and recommend solutions.
Process ID: 3
Timestamp: 20250608_110344
Operation: after_id_set
Strategy: XMLDSig (C14N 1.1 + XMLDSig)
Canonicalized Content:
---------------------
... (canonicalized XML here) ...
Or for JSON/JWS:
Process ID: 7
Timestamp: 20250608_110344
Operation: signing
Strategy: JWS (RFC 8785 Canonical JSON + JWS)
Key-Value Pairs:
----------------
... (key-value pairs here) ...
Or for Hybrid/Detached Hash:
Process ID: 12
Timestamp: 20250608_110344
Operation: digest
Strategy: Hybrid (Detached Hash + Signature)
Digest:
-------
... (digest value here) ...
- Auditability: Every output is traceable to the cryptographic method used.
- Interoperability: Facilitates cross-strategy and cross-format validation.
- Standards Compliance: Enables ISO TSG and other bodies to evaluate, compare, and recommend strategies for real-world, global use.
- Integration Testing: End-to-end and integration tests always include the correct strategy label in their outputs.
XMLDSig (C14N 1.1 + XMLDSig)JWS (RFC 8785 Canonical JSON + JWS)Hybrid (Detached Hash + Signature)
All strategy classes implement a getStrategyLabel() method, ensuring this pattern is consistent and future-proof.
Critical Security Principle: Signature Exclusion
For all digital signature strategies, the signature or digest must always be calculated over the message content excluding the signature itself. This is a universal requirement:
- For XMLDSig, this is enforced by using the enveloped signature transform (
http://www.w3.org/2000/09/xmldsig#enveloped-signature), which ensures the<Signature>element is excluded from the digest calculation.- For JWS (JSON Web Signature), the canonicalization and signing are performed over the JSON object without the signature property.
- For Hybrid/Detached Hash, the digest is always computed over the message, and the signature is stored separately.
If this rule is not followed, signature validation will always fail. This project enforces this rule in all strategies and makes it auditable in every output.
Project Focus & Philosophy
This repository is a test harness and standards exploration tool—not a production system. Its purpose is to rigorously evaluate, compare, and provide auditable evidence for digital signature strategies that can guarantee end-to-end integrity of payment messages as they traverse multiple agents and are converted between different syntax formats (such as XML and JSON). This is especially critical in scenarios where there is no central authority responsible for message security, as is increasingly the case in global, cross-border, and open banking environments.
Why does this matter?
- The ISO community and the global payments industry are moving toward interoperable message syntax types (XML, JSON, etc.).
- There is a critical gap: how can we ensure that payment messages remain untampered and trustworthy as they are converted and relayed between independent agents, without relying on a single trusted intermediary?
- This project provides a transparent, auditable, and comparative framework for testing and proving which cryptographic strategies (XMLDSig, JWS, Hybrid, etc.) actually work in these real-world, cross-format, multi-hop scenarios.
- The outputs—canonicalized content, key-value pairs, digests, and validation results—are all labeled, logged, and designed for maximum auditability and standards evaluation.
- All strategies strictly enforce the rule that the signature/digest is calculated over the message content excluding the signature itself.
- The ultimate goal is to provide the evidence and methodology needed for the ISO TSG and other standards bodies to recommend a globally approved, interoperable, and efficient approach to payment message integrity.
This project is not about building a production system. It is about providing the proof, transparency, and insight needed to close a crucial standards gap and enable trust, interoperability, and development ROI for the next generation of cross-border payments.