You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2026/02/23 09:14:50 UTC
(camel) branch 23054 created (now 888617546452)
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a change to branch 23054
in repository https://gitbox.apache.org/repos/asf/camel.git
at 888617546452 CAMEL-23054 - Camel-PQC: Add hybrid cryptography support
This branch includes the following new commits:
new 888617546452 CAMEL-23054 - Camel-PQC: Add hybrid cryptography support
The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(camel) 01/01: CAMEL-23054 - Camel-PQC: Add hybrid cryptography support
Posted by ac...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch 23054
in repository https://gitbox.apache.org/repos/asf/camel.git
commit 88861754645249baef2d13813d2113ee4f96e578
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Mon Feb 23 10:13:10 2026 +0100
CAMEL-23054 - Camel-PQC: Add hybrid cryptography support
Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
.../component/pqc/PQCComponentConfigurer.java | 38 ++-
.../camel/component/pqc/PQCEndpointConfigurer.java | 38 ++-
.../camel/component/pqc/PQCEndpointUriFactory.java | 8 +-
.../org/apache/camel/component/pqc/pqc.json | 74 +++--
.../camel-pqc/src/main/docs/pqc-component.adoc | 200 +++++++++++++
.../component/pqc/PQCClassicalKEMAlgorithms.java | 101 +++++++
.../pqc/PQCClassicalSignatureAlgorithms.java | 108 +++++++
.../apache/camel/component/pqc/PQCComponent.java | 110 +++++++
.../camel/component/pqc/PQCConfiguration.java | 95 ++++++
.../apache/camel/component/pqc/PQCConstants.java | 25 ++
.../apache/camel/component/pqc/PQCOperations.java | 14 +
.../apache/camel/component/pqc/PQCProducer.java | 234 +++++++++++++++
.../component/pqc/crypto/hybrid/HybridKEM.java | 325 +++++++++++++++++++++
.../pqc/crypto/hybrid/HybridSignature.java | 231 +++++++++++++++
.../crypto/hybrid/PQCDefaultECDHMLKEMMaterial.java | 84 ++++++
.../hybrid/PQCDefaultECDSAMLDSAMaterial.java | 83 ++++++
.../hybrid/PQCDefaultEd25519MLDSAMaterial.java | 79 +++++
.../hybrid/PQCDefaultX25519MLKEMMaterial.java | 89 ++++++
.../pqc/crypto/hybrid/PQCHybridKEMMaterial.java | 92 ++++++
.../crypto/hybrid/PQCHybridSignatureMaterial.java | 90 ++++++
.../component/pqc/PQCHybridKEMECDHMLKEMTest.java | 113 +++++++
.../component/pqc/PQCHybridKEMX25519MLKEMTest.java | 122 ++++++++
.../pqc/PQCHybridSignatureECDSAMLDSATest.java | 107 +++++++
.../pqc/PQCHybridSignatureEd25519MLDSATest.java | 97 ++++++
.../component/pqc/crypto/hybrid/HybridKEMTest.java | 189 ++++++++++++
.../pqc/crypto/hybrid/HybridSignatureTest.java | 171 +++++++++++
26 files changed, 2887 insertions(+), 30 deletions(-)
diff --git a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
index 3776524360eb..6017b9fcb364 100644
--- a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
+++ b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCComponentConfigurer.java
@@ -32,11 +32,23 @@ public class PQCComponentConfigurer extends PropertyConfigurerSupport implements
switch (ignoreCase ? name.toLowerCase() : name) {
case "autowiredenabled":
case "autowiredEnabled": target.setAutowiredEnabled(property(camelContext, boolean.class, value)); return true;
+ case "classicalkemalgorithm":
+ case "classicalKEMAlgorithm": getOrCreateConfiguration(target).setClassicalKEMAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
+ case "classicalkeyagreement":
+ case "classicalKeyAgreement": getOrCreateConfiguration(target).setClassicalKeyAgreement(property(camelContext, javax.crypto.KeyAgreement.class, value)); return true;
+ case "classicalkeypair":
+ case "classicalKeyPair": getOrCreateConfiguration(target).setClassicalKeyPair(property(camelContext, java.security.KeyPair.class, value)); return true;
+ case "classicalsignaturealgorithm":
+ case "classicalSignatureAlgorithm": getOrCreateConfiguration(target).setClassicalSignatureAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
+ case "classicalsigner":
+ case "classicalSigner": getOrCreateConfiguration(target).setClassicalSigner(property(camelContext, java.security.Signature.class, value)); return true;
case "configuration": target.setConfiguration(property(camelContext, org.apache.camel.component.pqc.PQCConfiguration.class, value)); return true;
case "healthcheckconsumerenabled":
case "healthCheckConsumerEnabled": target.setHealthCheckConsumerEnabled(property(camelContext, boolean.class, value)); return true;
case "healthcheckproducerenabled":
case "healthCheckProducerEnabled": target.setHealthCheckProducerEnabled(property(camelContext, boolean.class, value)); return true;
+ case "hybridkdfalgorithm":
+ case "hybridKdfAlgorithm": getOrCreateConfiguration(target).setHybridKdfAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
case "keyencapsulationalgorithm":
case "keyEncapsulationAlgorithm": getOrCreateConfiguration(target).setKeyEncapsulationAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
case "keygenerator":
@@ -67,7 +79,7 @@ public class PQCComponentConfigurer extends PropertyConfigurerSupport implements
@Override
public String[] getAutowiredNames() {
- return new String[]{"keyGenerator", "keyPair", "keyStore", "signer"};
+ return new String[]{"classicalKeyAgreement", "classicalKeyPair", "classicalSigner", "keyGenerator", "keyPair", "keyStore", "signer"};
}
@Override
@@ -75,11 +87,23 @@ public class PQCComponentConfigurer extends PropertyConfigurerSupport implements
switch (ignoreCase ? name.toLowerCase() : name) {
case "autowiredenabled":
case "autowiredEnabled": return boolean.class;
+ case "classicalkemalgorithm":
+ case "classicalKEMAlgorithm": return java.lang.String.class;
+ case "classicalkeyagreement":
+ case "classicalKeyAgreement": return javax.crypto.KeyAgreement.class;
+ case "classicalkeypair":
+ case "classicalKeyPair": return java.security.KeyPair.class;
+ case "classicalsignaturealgorithm":
+ case "classicalSignatureAlgorithm": return java.lang.String.class;
+ case "classicalsigner":
+ case "classicalSigner": return java.security.Signature.class;
case "configuration": return org.apache.camel.component.pqc.PQCConfiguration.class;
case "healthcheckconsumerenabled":
case "healthCheckConsumerEnabled": return boolean.class;
case "healthcheckproducerenabled":
case "healthCheckProducerEnabled": return boolean.class;
+ case "hybridkdfalgorithm":
+ case "hybridKdfAlgorithm": return java.lang.String.class;
case "keyencapsulationalgorithm":
case "keyEncapsulationAlgorithm": return java.lang.String.class;
case "keygenerator":
@@ -114,11 +138,23 @@ public class PQCComponentConfigurer extends PropertyConfigurerSupport implements
switch (ignoreCase ? name.toLowerCase() : name) {
case "autowiredenabled":
case "autowiredEnabled": return target.isAutowiredEnabled();
+ case "classicalkemalgorithm":
+ case "classicalKEMAlgorithm": return getOrCreateConfiguration(target).getClassicalKEMAlgorithm();
+ case "classicalkeyagreement":
+ case "classicalKeyAgreement": return getOrCreateConfiguration(target).getClassicalKeyAgreement();
+ case "classicalkeypair":
+ case "classicalKeyPair": return getOrCreateConfiguration(target).getClassicalKeyPair();
+ case "classicalsignaturealgorithm":
+ case "classicalSignatureAlgorithm": return getOrCreateConfiguration(target).getClassicalSignatureAlgorithm();
+ case "classicalsigner":
+ case "classicalSigner": return getOrCreateConfiguration(target).getClassicalSigner();
case "configuration": return target.getConfiguration();
case "healthcheckconsumerenabled":
case "healthCheckConsumerEnabled": return target.isHealthCheckConsumerEnabled();
case "healthcheckproducerenabled":
case "healthCheckProducerEnabled": return target.isHealthCheckProducerEnabled();
+ case "hybridkdfalgorithm":
+ case "hybridKdfAlgorithm": return getOrCreateConfiguration(target).getHybridKdfAlgorithm();
case "keyencapsulationalgorithm":
case "keyEncapsulationAlgorithm": return getOrCreateConfiguration(target).getKeyEncapsulationAlgorithm();
case "keygenerator":
diff --git a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
index 6123056a470f..6b006728cb64 100644
--- a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
+++ b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointConfigurer.java
@@ -23,6 +23,18 @@ public class PQCEndpointConfigurer extends PropertyConfigurerSupport implements
public boolean configure(CamelContext camelContext, Object obj, String name, Object value, boolean ignoreCase) {
PQCEndpoint target = (PQCEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "classicalkemalgorithm":
+ case "classicalKEMAlgorithm": target.getConfiguration().setClassicalKEMAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
+ case "classicalkeyagreement":
+ case "classicalKeyAgreement": target.getConfiguration().setClassicalKeyAgreement(property(camelContext, javax.crypto.KeyAgreement.class, value)); return true;
+ case "classicalkeypair":
+ case "classicalKeyPair": target.getConfiguration().setClassicalKeyPair(property(camelContext, java.security.KeyPair.class, value)); return true;
+ case "classicalsignaturealgorithm":
+ case "classicalSignatureAlgorithm": target.getConfiguration().setClassicalSignatureAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
+ case "classicalsigner":
+ case "classicalSigner": target.getConfiguration().setClassicalSigner(property(camelContext, java.security.Signature.class, value)); return true;
+ case "hybridkdfalgorithm":
+ case "hybridKdfAlgorithm": target.getConfiguration().setHybridKdfAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
case "keyencapsulationalgorithm":
case "keyEncapsulationAlgorithm": target.getConfiguration().setKeyEncapsulationAlgorithm(property(camelContext, java.lang.String.class, value)); return true;
case "keygenerator":
@@ -53,12 +65,24 @@ public class PQCEndpointConfigurer extends PropertyConfigurerSupport implements
@Override
public String[] getAutowiredNames() {
- return new String[]{"keyGenerator", "keyPair", "keyStore", "signer"};
+ return new String[]{"classicalKeyAgreement", "classicalKeyPair", "classicalSigner", "keyGenerator", "keyPair", "keyStore", "signer"};
}
@Override
public Class<?> getOptionType(String name, boolean ignoreCase) {
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "classicalkemalgorithm":
+ case "classicalKEMAlgorithm": return java.lang.String.class;
+ case "classicalkeyagreement":
+ case "classicalKeyAgreement": return javax.crypto.KeyAgreement.class;
+ case "classicalkeypair":
+ case "classicalKeyPair": return java.security.KeyPair.class;
+ case "classicalsignaturealgorithm":
+ case "classicalSignatureAlgorithm": return java.lang.String.class;
+ case "classicalsigner":
+ case "classicalSigner": return java.security.Signature.class;
+ case "hybridkdfalgorithm":
+ case "hybridKdfAlgorithm": return java.lang.String.class;
case "keyencapsulationalgorithm":
case "keyEncapsulationAlgorithm": return java.lang.String.class;
case "keygenerator":
@@ -91,6 +115,18 @@ public class PQCEndpointConfigurer extends PropertyConfigurerSupport implements
public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
PQCEndpoint target = (PQCEndpoint) obj;
switch (ignoreCase ? name.toLowerCase() : name) {
+ case "classicalkemalgorithm":
+ case "classicalKEMAlgorithm": return target.getConfiguration().getClassicalKEMAlgorithm();
+ case "classicalkeyagreement":
+ case "classicalKeyAgreement": return target.getConfiguration().getClassicalKeyAgreement();
+ case "classicalkeypair":
+ case "classicalKeyPair": return target.getConfiguration().getClassicalKeyPair();
+ case "classicalsignaturealgorithm":
+ case "classicalSignatureAlgorithm": return target.getConfiguration().getClassicalSignatureAlgorithm();
+ case "classicalsigner":
+ case "classicalSigner": return target.getConfiguration().getClassicalSigner();
+ case "hybridkdfalgorithm":
+ case "hybridKdfAlgorithm": return target.getConfiguration().getHybridKdfAlgorithm();
case "keyencapsulationalgorithm":
case "keyEncapsulationAlgorithm": return target.getConfiguration().getKeyEncapsulationAlgorithm();
case "keygenerator":
diff --git a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
index b01c443775ae..7cd7770f07b0 100644
--- a/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
+++ b/components/camel-pqc/src/generated/java/org/apache/camel/component/pqc/PQCEndpointUriFactory.java
@@ -23,7 +23,13 @@ public class PQCEndpointUriFactory extends org.apache.camel.support.component.En
private static final Set<String> SECRET_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
- Set<String> props = new HashSet<>(14);
+ Set<String> props = new HashSet<>(20);
+ props.add("classicalKEMAlgorithm");
+ props.add("classicalKeyAgreement");
+ props.add("classicalKeyPair");
+ props.add("classicalSignatureAlgorithm");
+ props.add("classicalSigner");
+ props.add("hybridKdfAlgorithm");
props.add("keyEncapsulationAlgorithm");
props.add("keyGenerator");
props.add("keyPair");
diff --git a/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json b/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
index 28917d43b6af..3fbc016cd7cc 100644
--- a/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
+++ b/components/camel-pqc/src/generated/resources/META-INF/org/apache/camel/component/pqc/pqc.json
@@ -26,21 +26,27 @@
"componentProperties": {
"configuration": { "index": 0, "kind": "property", "displayName": "Configuration", "group": "producer", "label": "", "required": false, "type": "object", "javaType": "org.apache.camel.component.pqc.PQCConfiguration", "deprecated": false, "autowired": false, "secret": false, "description": "Component configuration" },
"lazyStartProducer": { "index": 1, "kind": "property", "displayName": "Lazy Start Producer", "group": "producer", "label": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a producer may otherwise fail [...]
- "operation": { "index": 2, "kind": "property", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.pqc.PQCOperations", "enum": [ "sign", "verify", "generateSecretKeyEncapsulation", "extractSecretKeyEncapsulation", "extractSecretKeyFromEncapsulation", "getRemainingSignatures", "getKeyState", "deleteKeyState", "generateKeyPair", "exportKey", "importKey", "rotateKey", "getKeyMetadata", "listKeys", "expir [...]
+ "operation": { "index": 2, "kind": "property", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.pqc.PQCOperations", "enum": [ "sign", "verify", "hybridSign", "hybridVerify", "generateSecretKeyEncapsulation", "extractSecretKeyEncapsulation", "extractSecretKeyFromEncapsulation", "hybridGenerateSecretKeyEncapsulation", "hybridExtractSecretKeyEncapsulation", "hybridExtractSecretKeyFromEncapsulation", " [...]
"autowiredEnabled": { "index": 3, "kind": "property", "displayName": "Autowired Enabled", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Whether autowiring is enabled. This is used for automatic autowiring options (the option must be marked as autowired) by looking up in the registry to find if there is a single instance of matching t [...]
- "keyEncapsulationAlgorithm": { "index": 4, "kind": "property", "displayName": "Key Encapsulation Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLKEM", "BIKE", "HQC", "CMCE", "SABER", "FRODO", "NTRU", "NTRULPRime", "SNTRUPrime", "KYBER" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configur [...]
- "keyGenerator": { "index": 5, "kind": "property", "displayName": "Key Generator", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "javax.crypto.KeyGenerator", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Key Generator to be used in encapsulation and extraction" },
- "keyPair": { "index": 6, "kind": "property", "displayName": "Key Pair", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyPair", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyPair to be used" },
- "keyPairAlias": { "index": 7, "kind": "property", "displayName": "Key Pair Alias", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyPair alias to use in combination with KeyStore parameter" },
- "keyStore": { "index": 8, "kind": "property", "displayName": "Key Store", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyStore", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyStore where we could get Cryptographic material" },
- "keyStorePassword": { "index": 9, "kind": "property", "displayName": "Key Store Password", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyStore password to use in combination with KeyStore Parameter" },
- "signatureAlgorithm": { "index": 10, "kind": "property", "displayName": "Signature Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", "SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", "SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "c [...]
- "signer": { "index": 11, "kind": "property", "displayName": "Signer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.Signature", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Signer to be used" },
- "storeExtractedSecretKeyAsHeader": { "index": 12, "kind": "property", "displayName": "Store Extracted Secret Key As Header", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "In the context of extractSec [...]
- "symmetricKeyAlgorithm": { "index": 13, "kind": "property", "displayName": "Symmetric Key Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "co [...]
- "symmetricKeyLength": { "index": 14, "kind": "property", "displayName": "Symmetric Key Length", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The required length of the symmetric key used" },
- "healthCheckConsumerEnabled": { "index": 15, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
- "healthCheckProducerEnabled": { "index": 16, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
+ "classicalKEMAlgorithm": { "index": 4, "kind": "property", "displayName": "Classical KEMAlgorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "ECDH_P256", "ECDH_P384", "ECDH_P521", "X25519", "X448" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "T [...]
+ "classicalKeyAgreement": { "index": 5, "kind": "property", "displayName": "Classical Key Agreement", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "javax.crypto.KeyAgreement", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The classical KeyAgreement instance to be used in hybrid KE [...]
+ "classicalKeyPair": { "index": 6, "kind": "property", "displayName": "Classical Key Pair", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyPair", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The classical KeyPair to be used in hybrid operations" },
+ "classicalSignatureAlgorithm": { "index": 7, "kind": "property", "displayName": "Classical Signature Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "ECDSA_P256", "ECDSA_P384", "ECDSA_P521", "ED25519", "ED448", "RSA_2048", "RSA_3072", "RSA_4096" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "c [...]
+ "classicalSigner": { "index": 8, "kind": "property", "displayName": "Classical Signer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.Signature", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The classical Signature instance to be used in hybrid signature operations" },
+ "hybridKdfAlgorithm": { "index": 9, "kind": "property", "displayName": "Hybrid Kdf Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "HKDF-SHA256", "HKDF-SHA384", "HKDF-SHA512" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "HKDF-SHA256", "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "de [...]
+ "keyEncapsulationAlgorithm": { "index": 10, "kind": "property", "displayName": "Key Encapsulation Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLKEM", "BIKE", "HQC", "CMCE", "SABER", "FRODO", "NTRU", "NTRULPRime", "SNTRUPrime", "KYBER" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configu [...]
+ "keyGenerator": { "index": 11, "kind": "property", "displayName": "Key Generator", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "javax.crypto.KeyGenerator", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Key Generator to be used in encapsulation and extraction" },
+ "keyPair": { "index": 12, "kind": "property", "displayName": "Key Pair", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyPair", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyPair to be used" },
+ "keyPairAlias": { "index": 13, "kind": "property", "displayName": "Key Pair Alias", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyPair alias to use in combination with KeyStore parameter" },
+ "keyStore": { "index": 14, "kind": "property", "displayName": "Key Store", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyStore", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyStore where we could get Cryptographic material" },
+ "keyStorePassword": { "index": 15, "kind": "property", "displayName": "Key Store Password", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyStore password to use in combination with KeyStore Parameter" },
+ "signatureAlgorithm": { "index": 16, "kind": "property", "displayName": "Signature Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", "SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", "SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "c [...]
+ "signer": { "index": 17, "kind": "property", "displayName": "Signer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.Signature", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Signer to be used" },
+ "storeExtractedSecretKeyAsHeader": { "index": 18, "kind": "property", "displayName": "Store Extracted Secret Key As Header", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "In the context of extractSec [...]
+ "symmetricKeyAlgorithm": { "index": 19, "kind": "property", "displayName": "Symmetric Key Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "co [...]
+ "symmetricKeyLength": { "index": 20, "kind": "property", "displayName": "Symmetric Key Length", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The required length of the symmetric key used" },
+ "healthCheckConsumerEnabled": { "index": 21, "kind": "property", "displayName": "Health Check Consumer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all consumer based health checks from this component" },
+ "healthCheckProducerEnabled": { "index": 22, "kind": "property", "displayName": "Health Check Producer Enabled", "group": "health", "label": "health", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": true, "description": "Used for enabling or disabling all producer based health checks from this component. Notice: Camel has by default disabled all producer based health-checks. You can turn on produce [...]
},
"headers": {
"CamelPQCOperation": { "index": 0, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The operation we want to perform", "constantName": "org.apache.camel.component.pqc.PQCConstants#OPERATION" },
@@ -57,22 +63,36 @@
"CamelPQCKeyList": { "index": 11, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "java.util.List", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "List of key metadata", "constantName": "org.apache.camel.component.pqc.PQCConstants#KEY_LIST" },
"CamelPQCAlgorithm": { "index": 12, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The algorithm for key generation", "constantName": "org.apache.camel.component.pqc.PQCConstants#ALGORITHM" },
"CamelPQCIncludePrivate": { "index": 13, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Include private key in export", "constantName": "org.apache.camel.component.pqc.PQCConstants#INCLUDE_PRIVATE" },
- "CamelPQCRevocationReason": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Revocation reason", "constantName": "org.apache.camel.component.pqc.PQCConstants#REVOCATION_REASON" }
+ "CamelPQCRevocationReason": { "index": 14, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "Revocation reason", "constantName": "org.apache.camel.component.pqc.PQCConstants#REVOCATION_REASON" },
+ "CamelPQCHybridSignature": { "index": 15, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "byte[]", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The hybrid signature combining both classical and PQC signatures", "constantName": "org.apache.camel.component.pqc.PQCConstants#HYBRID_SIGNATURE" },
+ "CamelPQCClassicalSignature": { "index": 16, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "byte[]", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The classical signature component of a hybrid signature", "constantName": "org.apache.camel.component.pqc.PQCConstants#CLASSICAL_SIGNATURE" },
+ "CamelPQCPqcSignature": { "index": 17, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "byte[]", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The PQC signature component of a hybrid signature", "constantName": "org.apache.camel.component.pqc.PQCConstants#PQC_SIGNATURE" },
+ "CamelPQCClassicalEncapsulation": { "index": 18, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "byte[]", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The classical encapsulation component of a hybrid KEM", "constantName": "org.apache.camel.component.pqc.PQCConstants#CLASSICAL_ENCAPSULATION" },
+ "CamelPQCPqcEncapsulation": { "index": 19, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "byte[]", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The PQC encapsulation component of a hybrid KEM", "constantName": "org.apache.camel.component.pqc.PQCConstants#PQC_ENCAPSULATION" },
+ "CamelPQCHybridSecretKey": { "index": 20, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "javax.crypto.SecretKey", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The combined secret key from hybrid KEM operation", "constantName": "org.apache.camel.component.pqc.PQCConstants#HYBRID_SECRET_KEY" },
+ "CamelPQCHybridEncapsulation": { "index": 21, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "byte[]", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The hybrid encapsulation combining both classical and PQC encapsulations", "constantName": "org.apache.camel.component.pqc.PQCConstants#HYBRID_ENCAPSULATION" },
+ "CamelPQCHybridVerification": { "index": 22, "kind": "header", "displayName": "", "group": "producer", "label": "", "required": false, "javaType": "Boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "description": "The verification result of hybrid signature (both must pass)", "constantName": "org.apache.camel.component.pqc.PQCConstants#HYBRID_VERIFY" }
},
"properties": {
"label": { "index": 0, "kind": "path", "displayName": "Label", "group": "producer", "label": "", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "Logical name" },
- "operation": { "index": 1, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.pqc.PQCOperations", "enum": [ "sign", "verify", "generateSecretKeyEncapsulation", "extractSecretKeyEncapsulation", "extractSecretKeyFromEncapsulation", "getRemainingSignatures", "getKeyState", "deleteKeyState", "generateKeyPair", "exportKey", "importKey", "rotateKey", "getKeyMetadata", "listKeys", "expi [...]
+ "operation": { "index": 1, "kind": "parameter", "displayName": "Operation", "group": "producer", "label": "", "required": true, "type": "enum", "javaType": "org.apache.camel.component.pqc.PQCOperations", "enum": [ "sign", "verify", "hybridSign", "hybridVerify", "generateSecretKeyEncapsulation", "extractSecretKeyEncapsulation", "extractSecretKeyFromEncapsulation", "hybridGenerateSecretKeyEncapsulation", "hybridExtractSecretKeyEncapsulation", "hybridExtractSecretKeyFromEncapsulation", [...]
"lazyStartProducer": { "index": 2, "kind": "parameter", "displayName": "Lazy Start Producer", "group": "producer (advanced)", "label": "producer,advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": false, "secret": false, "defaultValue": false, "description": "Whether the producer should be started lazy (on the first message). By starting lazy you can use this to allow CamelContext and routes to startup in situations where a produc [...]
- "keyEncapsulationAlgorithm": { "index": 3, "kind": "parameter", "displayName": "Key Encapsulation Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLKEM", "BIKE", "HQC", "CMCE", "SABER", "FRODO", "NTRU", "NTRULPRime", "SNTRUPrime", "KYBER" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configu [...]
- "keyGenerator": { "index": 4, "kind": "parameter", "displayName": "Key Generator", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "javax.crypto.KeyGenerator", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Key Generator to be used in encapsulation and extraction" },
- "keyPair": { "index": 5, "kind": "parameter", "displayName": "Key Pair", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyPair", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyPair to be used" },
- "keyPairAlias": { "index": 6, "kind": "parameter", "displayName": "Key Pair Alias", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyPair alias to use in combination with KeyStore parameter" },
- "keyStore": { "index": 7, "kind": "parameter", "displayName": "Key Store", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyStore", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyStore where we could get Cryptographic material" },
- "keyStorePassword": { "index": 8, "kind": "parameter", "displayName": "Key Store Password", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyStore password to use in combination with KeyStore Parameter" },
- "signatureAlgorithm": { "index": 9, "kind": "parameter", "displayName": "Signature Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", "SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", "SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "c [...]
- "signer": { "index": 10, "kind": "parameter", "displayName": "Signer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.Signature", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Signer to be used" },
- "storeExtractedSecretKeyAsHeader": { "index": 11, "kind": "parameter", "displayName": "Store Extracted Secret Key As Header", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "In the context of extractSe [...]
- "symmetricKeyAlgorithm": { "index": 12, "kind": "parameter", "displayName": "Symmetric Key Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "c [...]
- "symmetricKeyLength": { "index": 13, "kind": "parameter", "displayName": "Symmetric Key Length", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The required length of the symmetric key used" }
+ "classicalKEMAlgorithm": { "index": 3, "kind": "parameter", "displayName": "Classical KEMAlgorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "ECDH_P256", "ECDH_P384", "ECDH_P521", "X25519", "X448" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": " [...]
+ "classicalKeyAgreement": { "index": 4, "kind": "parameter", "displayName": "Classical Key Agreement", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "javax.crypto.KeyAgreement", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The classical KeyAgreement instance to be used in hybrid K [...]
+ "classicalKeyPair": { "index": 5, "kind": "parameter", "displayName": "Classical Key Pair", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyPair", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The classical KeyPair to be used in hybrid operations" },
+ "classicalSignatureAlgorithm": { "index": 6, "kind": "parameter", "displayName": "Classical Signature Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "ECDSA_P256", "ECDSA_P384", "ECDSA_P521", "ED25519", "ED448", "RSA_2048", "RSA_3072", "RSA_4096" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", " [...]
+ "classicalSigner": { "index": 7, "kind": "parameter", "displayName": "Classical Signer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.Signature", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The classical Signature instance to be used in hybrid signature operations" },
+ "hybridKdfAlgorithm": { "index": 8, "kind": "parameter", "displayName": "Hybrid Kdf Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "HKDF-SHA256", "HKDF-SHA384", "HKDF-SHA512" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "HKDF-SHA256", "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "d [...]
+ "keyEncapsulationAlgorithm": { "index": 9, "kind": "parameter", "displayName": "Key Encapsulation Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLKEM", "BIKE", "HQC", "CMCE", "SABER", "FRODO", "NTRU", "NTRULPRime", "SNTRUPrime", "KYBER" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configu [...]
+ "keyGenerator": { "index": 10, "kind": "parameter", "displayName": "Key Generator", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "javax.crypto.KeyGenerator", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Key Generator to be used in encapsulation and extraction" },
+ "keyPair": { "index": 11, "kind": "parameter", "displayName": "Key Pair", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyPair", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyPair to be used" },
+ "keyPairAlias": { "index": 12, "kind": "parameter", "displayName": "Key Pair Alias", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyPair alias to use in combination with KeyStore parameter" },
+ "keyStore": { "index": 13, "kind": "parameter", "displayName": "Key Store", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.KeyStore", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "A KeyStore where we could get Cryptographic material" },
+ "keyStorePassword": { "index": 14, "kind": "parameter", "displayName": "Key Store Password", "group": "advanced", "label": "advanced", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": true, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The KeyStore password to use in combination with KeyStore Parameter" },
+ "signatureAlgorithm": { "index": 15, "kind": "parameter", "displayName": "Signature Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "MLDSA", "SLHDSA", "LMS", "HSS", "XMSS", "XMSSMT", "DILITHIUM", "FALCON", "PICNIC", "SNOVA", "MAYO", "SPHINCSPLUS" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", " [...]
+ "signer": { "index": 16, "kind": "parameter", "displayName": "Signer", "group": "advanced", "label": "advanced", "required": false, "type": "object", "javaType": "java.security.Signature", "deprecated": false, "deprecationNote": "", "autowired": true, "secret": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The Signer to be used" },
+ "storeExtractedSecretKeyAsHeader": { "index": 17, "kind": "parameter", "displayName": "Store Extracted Secret Key As Header", "group": "advanced", "label": "advanced", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": false, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "In the context of extractSe [...]
+ "symmetricKeyAlgorithm": { "index": 18, "kind": "parameter", "displayName": "Symmetric Key Algorithm", "group": "advanced", "label": "advanced", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "AES", "ARIA", "RC2", "RC5", "CAMELLIA", "CAST5", "CAST6", "CHACHA7539", "DSTU7624", "GOST28147", "GOST3412_2015", "GRAIN128", "HC128", "HC256", "SALSA20", "SEED", "SM4", "DESEDE" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "c [...]
+ "symmetricKeyLength": { "index": 19, "kind": "parameter", "displayName": "Symmetric Key Length", "group": "advanced", "label": "advanced", "required": false, "type": "integer", "javaType": "int", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": 128, "configurationClass": "org.apache.camel.component.pqc.PQCConfiguration", "configurationField": "configuration", "description": "The required length of the symmetric key used" }
}
}
diff --git a/components/camel-pqc/src/main/docs/pqc-component.adoc b/components/camel-pqc/src/main/docs/pqc-component.adoc
index 1ef61422c394..d5e1fbeaf1d3 100644
--- a/components/camel-pqc/src/main/docs/pqc-component.adoc
+++ b/components/camel-pqc/src/main/docs/pqc-component.adoc
@@ -1822,6 +1822,206 @@ for (KeyMetadata metadata : keys) {
logger.info("Migrated {} keys to file-based storage", keys.size());
--------------------------------------------------------------------------------
+== Hybrid Cryptography
+
+Hybrid cryptography combines classical (pre-quantum) algorithms with post-quantum algorithms to provide defense-in-depth during the transition to quantum-resistant cryptography. This approach is recommended by NIST and other security organizations because:
+
+1. **Defense in depth**: If either algorithm is broken, the other still provides protection
+2. **Backward compatibility**: Systems can validate the classical signature even if they don't support PQC
+3. **"Harvest now, decrypt later" protection**: Prevents adversaries from storing encrypted data now to decrypt with future quantum computers
+
+=== Hybrid Signature Operations
+
+The component supports hybrid signatures that combine a classical signature (e.g., ECDSA, Ed25519, RSA) with a PQC signature (e.g., ML-DSA).
+
+**Supported Classical Signature Algorithms:**
+
+- `ECDSA_P256` - ECDSA with NIST P-256 curve (SHA-256)
+- `ECDSA_P384` - ECDSA with NIST P-384 curve (SHA-384)
+- `ECDSA_P521` - ECDSA with NIST P-521 curve (SHA-512)
+- `ED25519` - Edwards curve Ed25519
+- `ED448` - Edwards curve Ed448
+- `RSA_2048` - RSA 2048-bit (SHA-256)
+- `RSA_3072` - RSA 3072-bit (SHA-384)
+- `RSA_4096` - RSA 4096-bit (SHA-512)
+
+**Hybrid Signature Operations:**
+
+- `hybridSign` - Create a hybrid signature using both classical and PQC algorithms
+- `hybridVerify` - Verify a hybrid signature (both components must be valid)
+
+**Example - Hybrid Signature with ECDSA P-256 + ML-DSA:**
+
+[source,java]
+--------------------------------------------------------------------------------
+from("direct:sign")
+ .to("pqc:hybrid?operation=hybridSign"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ECDSA_P256")
+ .to("mock:signed");
+
+from("direct:verify")
+ .to("pqc:hybrid?operation=hybridVerify"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ECDSA_P256")
+ .to("mock:verified");
+--------------------------------------------------------------------------------
+
+**Example - Hybrid Signature with Ed25519 + ML-DSA:**
+
+[source,java]
+--------------------------------------------------------------------------------
+from("direct:sign")
+ .to("pqc:hybrid?operation=hybridSign"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ED25519")
+ .to("mock:signed");
+--------------------------------------------------------------------------------
+
+**Hybrid Signature Wire Format:**
+
+The hybrid signature is encoded as: `[4 bytes: classical sig length][classical sig][pqc sig]`
+
+**Headers set by hybrid signature operations:**
+
+- `CamelPQCHybridSignature` - The complete hybrid signature
+- `CamelPQCClassicalSignature` - The classical signature component
+- `CamelPQCPqcSignature` - The PQC signature component
+- `CamelPQCHybridVerification` - Verification result (true if both pass)
+
+=== Hybrid KEM Operations
+
+The component supports hybrid Key Encapsulation Mechanisms that combine classical key agreement (e.g., ECDH, X25519) with PQC KEM (e.g., ML-KEM). The shared secrets from both algorithms are combined using HKDF.
+
+**Supported Classical KEM Algorithms:**
+
+- `ECDH_P256` - ECDH with NIST P-256 curve
+- `ECDH_P384` - ECDH with NIST P-384 curve
+- `ECDH_P521` - ECDH with NIST P-521 curve
+- `X25519` - X25519 key agreement (recommended)
+- `X448` - X448 key agreement
+
+**Hybrid KEM Operations:**
+
+- `hybridGenerateSecretKeyEncapsulation` - Generate hybrid encapsulation and shared secret
+- `hybridExtractSecretKeyEncapsulation` - Extract shared secret from hybrid encapsulation
+- `hybridExtractSecretKeyFromEncapsulation` - Extract the secret key for downstream use
+
+**Supported KDF Algorithms for Hybrid KEM:**
+
+- `HKDF-SHA256` (default)
+- `HKDF-SHA384`
+- `HKDF-SHA512`
+
+**Example - Hybrid KEM with X25519 + ML-KEM:**
+
+[source,java]
+--------------------------------------------------------------------------------
+from("direct:encapsulate")
+ .to("pqc:hybridkem?operation=hybridGenerateSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=X25519"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=256")
+ .to("mock:encapsulated");
+
+from("direct:extract")
+ .to("pqc:hybridkem?operation=hybridExtractSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=X25519"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=256")
+ .to("mock:extracted");
+--------------------------------------------------------------------------------
+
+**Example - Hybrid KEM with ECDH P-256 + ML-KEM:**
+
+[source,java]
+--------------------------------------------------------------------------------
+from("direct:encapsulate")
+ .to("pqc:hybridkem?operation=hybridGenerateSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=ECDH_P256"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=128"
+ + "&hybridKdfAlgorithm=HKDF-SHA256")
+ .to("mock:encapsulated");
+--------------------------------------------------------------------------------
+
+**Hybrid KEM Wire Format:**
+
+The hybrid encapsulation is encoded as: `[4 bytes: classical encap length][classical encap][pqc encap]`
+
+**Headers set by hybrid KEM operations:**
+
+- `CamelPQCHybridEncapsulation` - The complete hybrid encapsulation
+- `CamelPQCClassicalEncapsulation` - The classical encapsulation component
+- `CamelPQCPqcEncapsulation` - The PQC encapsulation component
+- `CamelPQCHybridSecretKey` - The combined shared secret key
+
+=== Recommended Algorithm Combinations
+
+Based on NIST recommendations for the transition period:
+
+**For Signatures:**
+
+|===
+|Classical Algorithm |PQC Algorithm |Security Level |Use Case
+
+|ECDSA_P256
+|MLDSA (ML-DSA-65)
+|128-bit
+|General purpose, TLS
+
+|ED25519
+|MLDSA (ML-DSA-65)
+|128-bit
+|High-performance signing
+
+|ECDSA_P384
+|MLDSA (ML-DSA-87)
+|192-bit
+|Higher security requirements
+
+|RSA_3072
+|MLDSA (ML-DSA-65)
+|128-bit
+|Legacy system compatibility
+|===
+
+**For Key Encapsulation:**
+
+|===
+|Classical Algorithm |PQC Algorithm |Security Level |Use Case
+
+|X25519
+|MLKEM (ML-KEM-768)
+|128-bit
+|TLS 1.3, general purpose (recommended)
+
+|ECDH_P256
+|MLKEM (ML-KEM-768)
+|128-bit
+|Legacy ECDH compatibility
+
+|X448
+|MLKEM (ML-KEM-1024)
+|192-bit
+|Higher security requirements
+|===
+
+=== Security Considerations for Hybrid Cryptography
+
+1. **Both algorithms must succeed**: For hybrid verification, both the classical and PQC signatures must be valid. For hybrid KEM, both shared secrets are combined.
+
+2. **Key management**: You need to manage two sets of keys (classical and PQC). Consider using the Key Lifecycle Manager to handle both.
+
+3. **Performance**: Hybrid operations are slower than single-algorithm operations because they perform two cryptographic operations. ML-DSA signatures are larger than classical signatures.
+
+4. **Wire format compatibility**: The hybrid signature and encapsulation formats are specific to this implementation. Ensure both parties use compatible formats.
+
+5. **Algorithm agility**: Design your system to allow algorithm upgrades as standards evolve.
+
== PQC DataFormat
The PQC component also provides a DataFormat for quantum-resistant encryption and decryption of message payloads using Key Encapsulation Mechanisms (KEM).
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCClassicalKEMAlgorithms.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCClassicalKEMAlgorithms.java
new file mode 100644
index 000000000000..a60d03956f16
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCClassicalKEMAlgorithms.java
@@ -0,0 +1,101 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+/**
+ * Classical (pre-quantum) key encapsulation/agreement algorithms for use in hybrid cryptography. These algorithms are
+ * combined with PQC KEM algorithms to provide defense-in-depth during the transition to post-quantum cryptography.
+ */
+public enum PQCClassicalKEMAlgorithms {
+
+ // ECDH variants
+ ECDH_P256("ECDH", "secp256r1", 256),
+ ECDH_P384("ECDH", "secp384r1", 384),
+ ECDH_P521("ECDH", "secp521r1", 521),
+
+ // X25519/X448 key agreement
+ X25519("X25519", null, 256),
+ X448("X448", null, 448);
+
+ private final String algorithm;
+ private final String curveSpec;
+ private final int keySize;
+
+ PQCClassicalKEMAlgorithms(String algorithm, String curveSpec, int keySize) {
+ this.algorithm = algorithm;
+ this.curveSpec = curveSpec;
+ this.keySize = keySize;
+ }
+
+ /**
+ * Gets the key agreement algorithm name (e.g., "ECDH", "X25519").
+ */
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Gets the curve specification (e.g., "secp256r1", or null for X25519/X448).
+ */
+ public String getCurveSpec() {
+ return curveSpec;
+ }
+
+ /**
+ * Gets the key size in bits.
+ */
+ public int getKeySize() {
+ return keySize;
+ }
+
+ /**
+ * Checks if this algorithm uses standard ECDH with named curves.
+ */
+ public boolean isECDH() {
+ return "ECDH".equals(algorithm);
+ }
+
+ /**
+ * Checks if this algorithm uses X25519 or X448.
+ */
+ public boolean isXDH() {
+ return "X25519".equals(algorithm) || "X448".equals(algorithm);
+ }
+
+ /**
+ * Gets the key algorithm for key pair generation.
+ */
+ public String getKeyAlgorithm() {
+ if (isXDH()) {
+ return algorithm;
+ }
+ return "EC";
+ }
+
+ /**
+ * Gets the expected shared secret size in bytes.
+ */
+ public int getSharedSecretSize() {
+ return switch (this) {
+ case X25519 -> 32;
+ case X448 -> 56;
+ case ECDH_P256 -> 32;
+ case ECDH_P384 -> 48;
+ case ECDH_P521 -> 66;
+ };
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCClassicalSignatureAlgorithms.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCClassicalSignatureAlgorithms.java
new file mode 100644
index 000000000000..3420e962433f
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCClassicalSignatureAlgorithms.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+/**
+ * Classical (pre-quantum) signature algorithms for use in hybrid cryptography. These algorithms are combined with PQC
+ * algorithms to provide defense-in-depth during the transition to post-quantum cryptography.
+ */
+public enum PQCClassicalSignatureAlgorithms {
+
+ // ECDSA variants
+ ECDSA_P256("SHA256withECDSA", "EC", "secp256r1"),
+ ECDSA_P384("SHA384withECDSA", "EC", "secp384r1"),
+ ECDSA_P521("SHA512withECDSA", "EC", "secp521r1"),
+
+ // Edwards curve signatures
+ ED25519("Ed25519", "Ed25519", null),
+ ED448("Ed448", "Ed448", null),
+
+ // RSA variants
+ RSA_2048("SHA256withRSA", "RSA", "2048"),
+ RSA_3072("SHA384withRSA", "RSA", "3072"),
+ RSA_4096("SHA512withRSA", "RSA", "4096");
+
+ private final String algorithm;
+ private final String keyAlgorithm;
+ private final String parameterSpec;
+
+ PQCClassicalSignatureAlgorithms(String algorithm, String keyAlgorithm, String parameterSpec) {
+ this.algorithm = algorithm;
+ this.keyAlgorithm = keyAlgorithm;
+ this.parameterSpec = parameterSpec;
+ }
+
+ /**
+ * Gets the signature algorithm name (e.g., "SHA256withECDSA").
+ */
+ public String getAlgorithm() {
+ return algorithm;
+ }
+
+ /**
+ * Gets the key algorithm name (e.g., "EC", "RSA", "Ed25519").
+ */
+ public String getKeyAlgorithm() {
+ return keyAlgorithm;
+ }
+
+ /**
+ * Gets the parameter specification (e.g., "secp256r1", "2048", or null for Ed25519/Ed448).
+ */
+ public String getParameterSpec() {
+ return parameterSpec;
+ }
+
+ /**
+ * Checks if this algorithm uses elliptic curves.
+ */
+ public boolean isEllipticCurve() {
+ return "EC".equals(keyAlgorithm) || "Ed25519".equals(keyAlgorithm) || "Ed448".equals(keyAlgorithm);
+ }
+
+ /**
+ * Checks if this algorithm uses RSA.
+ */
+ public boolean isRSA() {
+ return "RSA".equals(keyAlgorithm);
+ }
+
+ /**
+ * Gets the key size in bits for RSA algorithms, or curve bit size for EC algorithms.
+ */
+ public int getKeySize() {
+ if (parameterSpec == null) {
+ if ("Ed25519".equals(keyAlgorithm)) {
+ return 256;
+ } else if ("Ed448".equals(keyAlgorithm)) {
+ return 448;
+ }
+ return 0;
+ }
+
+ if (isRSA()) {
+ return Integer.parseInt(parameterSpec);
+ }
+
+ return switch (parameterSpec) {
+ case "secp256r1" -> 256;
+ case "secp384r1" -> 384;
+ case "secp521r1" -> 521;
+ default -> 0;
+ };
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java
index c434b939936f..6734fc1eb1d3 100644
--- a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCComponent.java
@@ -21,6 +21,7 @@ import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.Endpoint;
import org.apache.camel.component.pqc.crypto.*;
+import org.apache.camel.component.pqc.crypto.hybrid.*;
import org.apache.camel.component.pqc.crypto.kem.*;
import org.apache.camel.spi.Metadata;
import org.apache.camel.spi.annotations.Component;
@@ -147,9 +148,118 @@ public class PQCComponent extends HealthCheckComponent {
}
}
+ // Auto-configure hybrid signature materials
+ configureHybridSignatureMaterial(configuration);
+
+ // Auto-configure hybrid KEM materials
+ configureHybridKEMMaterial(configuration);
+
return endpoint;
}
+ /**
+ * Auto-configures hybrid signature materials based on classical and PQC algorithm settings.
+ */
+ private void configureHybridSignatureMaterial(PQCConfiguration configuration) {
+ // Only configure if hybrid signature operations and classical algorithm is specified
+ if (configuration.getOperation() != PQCOperations.hybridSign
+ && configuration.getOperation() != PQCOperations.hybridVerify) {
+ return;
+ }
+
+ // Configure PQC signature material if not already set
+ if (ObjectHelper.isEmpty(configuration.getSigner()) && ObjectHelper.isEmpty(configuration.getKeyPair())) {
+ if (ObjectHelper.isNotEmpty(configuration.getSignatureAlgorithm())) {
+ switch (configuration.getSignatureAlgorithm()) {
+ case "MLDSA":
+ configuration.setSigner(PQCDefaultMLDSAMaterial.signer);
+ configuration.setKeyPair(PQCDefaultMLDSAMaterial.keyPair);
+ break;
+ case "SLHDSA":
+ configuration.setSigner(PQCDefaultSLHDSAMaterial.signer);
+ configuration.setKeyPair(PQCDefaultSLHDSAMaterial.keyPair);
+ break;
+ case "DILITHIUM":
+ configuration.setSigner(PQCDefaultDILITHIUMMaterial.signer);
+ configuration.setKeyPair(PQCDefaultDILITHIUMMaterial.keyPair);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Configure classical signature material if not already set
+ if (ObjectHelper.isEmpty(configuration.getClassicalSigner())
+ && ObjectHelper.isEmpty(configuration.getClassicalKeyPair())) {
+ if (ObjectHelper.isNotEmpty(configuration.getClassicalSignatureAlgorithm())) {
+ String classicalAlg = configuration.getClassicalSignatureAlgorithm();
+ String pqcAlg = configuration.getSignatureAlgorithm();
+
+ // Use pre-built hybrid materials for common combinations
+ if ("ECDSA_P256".equals(classicalAlg) && "MLDSA".equals(pqcAlg)) {
+ configuration.setClassicalSigner(PQCDefaultECDSAMLDSAMaterial.classicalSigner);
+ configuration.setClassicalKeyPair(PQCDefaultECDSAMLDSAMaterial.classicalKeyPair);
+ configuration.setSigner(PQCDefaultECDSAMLDSAMaterial.pqcSigner);
+ configuration.setKeyPair(PQCDefaultECDSAMLDSAMaterial.pqcKeyPair);
+ } else if ("ED25519".equals(classicalAlg) && "MLDSA".equals(pqcAlg)) {
+ configuration.setClassicalSigner(PQCDefaultEd25519MLDSAMaterial.classicalSigner);
+ configuration.setClassicalKeyPair(PQCDefaultEd25519MLDSAMaterial.classicalKeyPair);
+ configuration.setSigner(PQCDefaultEd25519MLDSAMaterial.pqcSigner);
+ configuration.setKeyPair(PQCDefaultEd25519MLDSAMaterial.pqcKeyPair);
+ }
+ }
+ }
+ }
+
+ /**
+ * Auto-configures hybrid KEM materials based on classical and PQC algorithm settings.
+ */
+ private void configureHybridKEMMaterial(PQCConfiguration configuration) {
+ // Only configure if hybrid KEM operations and classical algorithm is specified
+ if (configuration.getOperation() != PQCOperations.hybridGenerateSecretKeyEncapsulation
+ && configuration.getOperation() != PQCOperations.hybridExtractSecretKeyEncapsulation
+ && configuration.getOperation() != PQCOperations.hybridExtractSecretKeyFromEncapsulation) {
+ return;
+ }
+
+ // Configure PQC KEM material if not already set
+ if (ObjectHelper.isEmpty(configuration.getKeyGenerator()) && ObjectHelper.isEmpty(configuration.getKeyPair())) {
+ if (ObjectHelper.isNotEmpty(configuration.getKeyEncapsulationAlgorithm())) {
+ switch (configuration.getKeyEncapsulationAlgorithm()) {
+ case "MLKEM":
+ configuration.setKeyGenerator(PQCDefaultMLKEMMaterial.keyGenerator);
+ configuration.setKeyPair(PQCDefaultMLKEMMaterial.keyPair);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ // Configure classical KEM material if not already set
+ if (ObjectHelper.isEmpty(configuration.getClassicalKeyAgreement())
+ && ObjectHelper.isEmpty(configuration.getClassicalKeyPair())) {
+ if (ObjectHelper.isNotEmpty(configuration.getClassicalKEMAlgorithm())) {
+ String classicalAlg = configuration.getClassicalKEMAlgorithm();
+ String pqcAlg = configuration.getKeyEncapsulationAlgorithm();
+
+ // Use pre-built hybrid materials for common combinations
+ if ("X25519".equals(classicalAlg) && "MLKEM".equals(pqcAlg)) {
+ configuration.setClassicalKeyAgreement(PQCDefaultX25519MLKEMMaterial.classicalKeyAgreement);
+ configuration.setClassicalKeyPair(PQCDefaultX25519MLKEMMaterial.classicalKeyPair);
+ configuration.setKeyGenerator(PQCDefaultX25519MLKEMMaterial.pqcKeyGenerator);
+ configuration.setKeyPair(PQCDefaultX25519MLKEMMaterial.pqcKeyPair);
+ } else if ("ECDH_P256".equals(classicalAlg) && "MLKEM".equals(pqcAlg)) {
+ configuration.setClassicalKeyAgreement(PQCDefaultECDHMLKEMMaterial.classicalKeyAgreement);
+ configuration.setClassicalKeyPair(PQCDefaultECDHMLKEMMaterial.classicalKeyPair);
+ configuration.setKeyGenerator(PQCDefaultECDHMLKEMMaterial.pqcKeyGenerator);
+ configuration.setKeyPair(PQCDefaultECDHMLKEMMaterial.pqcKeyPair);
+ }
+ }
+ }
+ }
+
public PQCConfiguration getConfiguration() {
return configuration;
}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
index 531be884017f..87ace93b481d 100644
--- a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConfiguration.java
@@ -20,6 +20,7 @@ import java.security.KeyPair;
import java.security.KeyStore;
import java.security.Signature;
+import javax.crypto.KeyAgreement;
import javax.crypto.KeyGenerator;
import org.apache.camel.RuntimeCamelException;
@@ -71,6 +72,34 @@ public class PQCConfiguration implements Cloneable {
@Metadata(label = "advanced", secret = true)
private String keyStorePassword;
+ // Hybrid cryptography configuration
+ @UriParam(enums = "ECDSA_P256,ECDSA_P384,ECDSA_P521,ED25519,ED448,RSA_2048,RSA_3072,RSA_4096",
+ description = "The classical signature algorithm to use in hybrid operations")
+ @Metadata(label = "advanced")
+ private String classicalSignatureAlgorithm;
+
+ @UriParam(enums = "ECDH_P256,ECDH_P384,ECDH_P521,X25519,X448",
+ description = "The classical key agreement algorithm to use in hybrid KEM operations")
+ @Metadata(label = "advanced")
+ private String classicalKEMAlgorithm;
+
+ @UriParam(description = "The classical KeyPair to be used in hybrid operations")
+ @Metadata(label = "advanced", autowired = true)
+ private KeyPair classicalKeyPair;
+
+ @UriParam(description = "The classical Signature instance to be used in hybrid signature operations")
+ @Metadata(label = "advanced", autowired = true)
+ private Signature classicalSigner;
+
+ @UriParam(description = "The classical KeyAgreement instance to be used in hybrid KEM operations")
+ @Metadata(label = "advanced", autowired = true)
+ private KeyAgreement classicalKeyAgreement;
+
+ @UriParam(defaultValue = "HKDF-SHA256", enums = "HKDF-SHA256,HKDF-SHA384,HKDF-SHA512",
+ description = "The KDF algorithm to use for combining secrets in hybrid KEM operations")
+ @Metadata(label = "advanced")
+ private String hybridKdfAlgorithm = "HKDF-SHA256";
+
public PQCOperations getOperation() {
return operation;
}
@@ -204,6 +233,72 @@ public class PQCConfiguration implements Cloneable {
this.keyPairAlias = keyPairAlias;
}
+ public String getClassicalSignatureAlgorithm() {
+ return classicalSignatureAlgorithm;
+ }
+
+ /**
+ * The classical signature algorithm to use in hybrid operations
+ */
+ public void setClassicalSignatureAlgorithm(String classicalSignatureAlgorithm) {
+ this.classicalSignatureAlgorithm = classicalSignatureAlgorithm;
+ }
+
+ public String getClassicalKEMAlgorithm() {
+ return classicalKEMAlgorithm;
+ }
+
+ /**
+ * The classical key agreement algorithm to use in hybrid KEM operations
+ */
+ public void setClassicalKEMAlgorithm(String classicalKEMAlgorithm) {
+ this.classicalKEMAlgorithm = classicalKEMAlgorithm;
+ }
+
+ public KeyPair getClassicalKeyPair() {
+ return classicalKeyPair;
+ }
+
+ /**
+ * The classical KeyPair to be used in hybrid operations
+ */
+ public void setClassicalKeyPair(KeyPair classicalKeyPair) {
+ this.classicalKeyPair = classicalKeyPair;
+ }
+
+ public Signature getClassicalSigner() {
+ return classicalSigner;
+ }
+
+ /**
+ * The classical Signature instance to be used in hybrid signature operations
+ */
+ public void setClassicalSigner(Signature classicalSigner) {
+ this.classicalSigner = classicalSigner;
+ }
+
+ public KeyAgreement getClassicalKeyAgreement() {
+ return classicalKeyAgreement;
+ }
+
+ /**
+ * The classical KeyAgreement instance to be used in hybrid KEM operations
+ */
+ public void setClassicalKeyAgreement(KeyAgreement classicalKeyAgreement) {
+ this.classicalKeyAgreement = classicalKeyAgreement;
+ }
+
+ public String getHybridKdfAlgorithm() {
+ return hybridKdfAlgorithm;
+ }
+
+ /**
+ * The KDF algorithm to use for combining secrets in hybrid KEM operations
+ */
+ public void setHybridKdfAlgorithm(String hybridKdfAlgorithm) {
+ this.hybridKdfAlgorithm = hybridKdfAlgorithm;
+ }
+
// *************************************************
//
// *************************************************
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConstants.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConstants.java
index c56532472b6e..f99a57a23abf 100644
--- a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConstants.java
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCConstants.java
@@ -68,4 +68,29 @@ public interface PQCConstants {
@Metadata(description = "Revocation reason", javaType = "String")
String REVOCATION_REASON = "CamelPQCRevocationReason";
+
+ // Hybrid cryptography headers
+ @Metadata(description = "The hybrid signature combining both classical and PQC signatures", javaType = "byte[]")
+ String HYBRID_SIGNATURE = "CamelPQCHybridSignature";
+
+ @Metadata(description = "The classical signature component of a hybrid signature", javaType = "byte[]")
+ String CLASSICAL_SIGNATURE = "CamelPQCClassicalSignature";
+
+ @Metadata(description = "The PQC signature component of a hybrid signature", javaType = "byte[]")
+ String PQC_SIGNATURE = "CamelPQCPqcSignature";
+
+ @Metadata(description = "The classical encapsulation component of a hybrid KEM", javaType = "byte[]")
+ String CLASSICAL_ENCAPSULATION = "CamelPQCClassicalEncapsulation";
+
+ @Metadata(description = "The PQC encapsulation component of a hybrid KEM", javaType = "byte[]")
+ String PQC_ENCAPSULATION = "CamelPQCPqcEncapsulation";
+
+ @Metadata(description = "The combined secret key from hybrid KEM operation", javaType = "javax.crypto.SecretKey")
+ String HYBRID_SECRET_KEY = "CamelPQCHybridSecretKey";
+
+ @Metadata(description = "The hybrid encapsulation combining both classical and PQC encapsulations", javaType = "byte[]")
+ String HYBRID_ENCAPSULATION = "CamelPQCHybridEncapsulation";
+
+ @Metadata(description = "The verification result of hybrid signature (both must pass)", javaType = "Boolean")
+ String HYBRID_VERIFY = "CamelPQCHybridVerification";
}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCOperations.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCOperations.java
index fd4da0b79b50..00afd1eb82b9 100644
--- a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCOperations.java
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCOperations.java
@@ -17,11 +17,25 @@
package org.apache.camel.component.pqc;
public enum PQCOperations {
+ // Standard PQC signature operations
sign,
verify,
+
+ // Hybrid signature operations (classical + PQC combined)
+ hybridSign,
+ hybridVerify,
+
+ // Standard PQC KEM operations
generateSecretKeyEncapsulation,
extractSecretKeyEncapsulation,
extractSecretKeyFromEncapsulation,
+
+ // Hybrid KEM operations (classical + PQC combined)
+ hybridGenerateSecretKeyEncapsulation,
+ hybridExtractSecretKeyEncapsulation,
+ hybridExtractSecretKeyFromEncapsulation,
+
+ // Key lifecycle operations
getRemainingSignatures,
getKeyState,
deleteKeyState,
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
index 21b652656773..fcdb77d397e6 100644
--- a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java
@@ -19,6 +19,7 @@ package org.apache.camel.component.pqc;
import java.security.*;
import java.security.cert.Certificate;
+import javax.crypto.KeyAgreement;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
@@ -26,6 +27,8 @@ import javax.crypto.spec.SecretKeySpec;
import org.apache.camel.Endpoint;
import org.apache.camel.Exchange;
import org.apache.camel.InvalidPayloadException;
+import org.apache.camel.component.pqc.crypto.hybrid.HybridKEM;
+import org.apache.camel.component.pqc.crypto.hybrid.HybridSignature;
import org.apache.camel.support.DefaultProducer;
import org.apache.camel.util.ObjectHelper;
import org.bouncycastle.jcajce.SecretKeyWithEncapsulation;
@@ -41,6 +44,11 @@ public class PQCProducer extends DefaultProducer {
private KeyGenerator keyGenerator;
private KeyPair keyPair;
+ // Hybrid cryptography fields
+ private Signature classicalSigner;
+ private KeyAgreement classicalKeyAgreement;
+ private KeyPair classicalKeyPair;
+
public PQCProducer(Endpoint endpoint) {
super(endpoint);
}
@@ -54,6 +62,12 @@ public class PQCProducer extends DefaultProducer {
case verify:
verification(exchange);
break;
+ case hybridSign:
+ hybridSignature(exchange);
+ break;
+ case hybridVerify:
+ hybridVerification(exchange);
+ break;
case generateSecretKeyEncapsulation:
generateEncapsulation(exchange);
break;
@@ -63,6 +77,15 @@ public class PQCProducer extends DefaultProducer {
case extractSecretKeyFromEncapsulation:
extractSecretKeyFromEncapsulation(exchange);
break;
+ case hybridGenerateSecretKeyEncapsulation:
+ hybridGenerateEncapsulation(exchange);
+ break;
+ case hybridExtractSecretKeyEncapsulation:
+ hybridExtractEncapsulation(exchange);
+ break;
+ case hybridExtractSecretKeyFromEncapsulation:
+ hybridExtractSecretKeyFromEncapsulation(exchange);
+ break;
default:
throw new IllegalArgumentException("Unsupported operation");
}
@@ -122,6 +145,55 @@ public class PQCProducer extends DefaultProducer {
} else {
keyPair = getConfiguration().getKeyPair();
}
+
+ // Initialize hybrid signature operations
+ if (getConfiguration().getOperation().equals(PQCOperations.hybridSign)
+ || getConfiguration().getOperation().equals(PQCOperations.hybridVerify)) {
+ // Initialize PQC signer
+ signer = getEndpoint().getConfiguration().getSigner();
+ if (ObjectHelper.isEmpty(signer) && ObjectHelper.isNotEmpty(getConfiguration().getSignatureAlgorithm())) {
+ PQCSignatureAlgorithms sigAlg = PQCSignatureAlgorithms.valueOf(getConfiguration().getSignatureAlgorithm());
+ signer = Signature.getInstance(sigAlg.getAlgorithm(), sigAlg.getBcProvider());
+ }
+
+ // Initialize classical signer
+ classicalSigner = getEndpoint().getConfiguration().getClassicalSigner();
+ if (ObjectHelper.isEmpty(classicalSigner)
+ && ObjectHelper.isNotEmpty(getConfiguration().getClassicalSignatureAlgorithm())) {
+ PQCClassicalSignatureAlgorithms classAlg
+ = PQCClassicalSignatureAlgorithms.valueOf(getConfiguration().getClassicalSignatureAlgorithm());
+ classicalSigner = Signature.getInstance(classAlg.getAlgorithm());
+ }
+
+ // Initialize classical key pair
+ classicalKeyPair = getConfiguration().getClassicalKeyPair();
+ }
+
+ // Initialize hybrid KEM operations
+ if (getConfiguration().getOperation().equals(PQCOperations.hybridGenerateSecretKeyEncapsulation)
+ || getConfiguration().getOperation().equals(PQCOperations.hybridExtractSecretKeyEncapsulation)
+ || getConfiguration().getOperation().equals(PQCOperations.hybridExtractSecretKeyFromEncapsulation)) {
+ // Initialize PQC KEM
+ keyGenerator = getEndpoint().getConfiguration().getKeyGenerator();
+ if (ObjectHelper.isEmpty(keyGenerator)
+ && ObjectHelper.isNotEmpty(getConfiguration().getKeyEncapsulationAlgorithm())) {
+ PQCKeyEncapsulationAlgorithms kemAlg
+ = PQCKeyEncapsulationAlgorithms.valueOf(getConfiguration().getKeyEncapsulationAlgorithm());
+ keyGenerator = KeyGenerator.getInstance(kemAlg.getAlgorithm(), kemAlg.getBcProvider());
+ }
+
+ // Initialize classical key agreement
+ classicalKeyAgreement = getEndpoint().getConfiguration().getClassicalKeyAgreement();
+ if (ObjectHelper.isEmpty(classicalKeyAgreement)
+ && ObjectHelper.isNotEmpty(getConfiguration().getClassicalKEMAlgorithm())) {
+ PQCClassicalKEMAlgorithms classKemAlg
+ = PQCClassicalKEMAlgorithms.valueOf(getConfiguration().getClassicalKEMAlgorithm());
+ classicalKeyAgreement = KeyAgreement.getInstance(classKemAlg.getAlgorithm());
+ }
+
+ // Initialize classical key pair
+ classicalKeyPair = getConfiguration().getClassicalKeyPair();
+ }
}
private void signature(Exchange exchange)
@@ -205,4 +277,166 @@ public class PQCProducer extends DefaultProducer {
}
}
+ // ========== Hybrid Signature Operations ==========
+
+ private void hybridSignature(Exchange exchange)
+ throws InvalidPayloadException, InvalidKeyException, SignatureException {
+ String payload = exchange.getMessage().getMandatoryBody(String.class);
+ byte[] data = payload.getBytes();
+
+ if (classicalSigner == null || classicalKeyPair == null) {
+ throw new IllegalStateException(
+ "Classical signer and key pair must be configured for hybrid signature operations");
+ }
+ if (signer == null || keyPair == null) {
+ throw new IllegalStateException("PQC signer and key pair must be configured for hybrid signature operations");
+ }
+
+ // Create hybrid signature
+ byte[] hybridSig = HybridSignature.sign(
+ data,
+ classicalKeyPair.getPrivate(),
+ classicalSigner,
+ keyPair.getPrivate(),
+ signer);
+
+ // Parse to get individual signatures for headers
+ HybridSignature.HybridSignatureComponents components = HybridSignature.parse(hybridSig);
+
+ exchange.getMessage().setHeader(PQCConstants.HYBRID_SIGNATURE, hybridSig);
+ exchange.getMessage().setHeader(PQCConstants.CLASSICAL_SIGNATURE, components.classicalSignature());
+ exchange.getMessage().setHeader(PQCConstants.PQC_SIGNATURE, components.pqcSignature());
+ }
+
+ private void hybridVerification(Exchange exchange)
+ throws InvalidPayloadException, InvalidKeyException, SignatureException {
+ String payload = exchange.getMessage().getMandatoryBody(String.class);
+ byte[] data = payload.getBytes();
+
+ byte[] hybridSig = exchange.getMessage().getHeader(PQCConstants.HYBRID_SIGNATURE, byte[].class);
+ if (hybridSig == null) {
+ throw new IllegalArgumentException("Hybrid signature not found in header: " + PQCConstants.HYBRID_SIGNATURE);
+ }
+
+ if (classicalSigner == null || classicalKeyPair == null) {
+ throw new IllegalStateException(
+ "Classical signer and key pair must be configured for hybrid verification operations");
+ }
+ if (signer == null || keyPair == null) {
+ throw new IllegalStateException("PQC signer and key pair must be configured for hybrid verification operations");
+ }
+
+ // Verify hybrid signature (both must pass)
+ boolean valid = HybridSignature.verify(
+ data,
+ hybridSig,
+ classicalKeyPair.getPublic(),
+ classicalSigner,
+ keyPair.getPublic(),
+ signer);
+
+ exchange.getMessage().setHeader(PQCConstants.HYBRID_VERIFY, valid);
+ exchange.getMessage().setHeader(PQCConstants.VERIFY, valid);
+ }
+
+ // ========== Hybrid KEM Operations ==========
+
+ private void hybridGenerateEncapsulation(Exchange exchange) throws Exception {
+ if (classicalKeyAgreement == null || classicalKeyPair == null) {
+ throw new IllegalStateException(
+ "Classical key agreement and key pair must be configured for hybrid KEM operations");
+ }
+ if (keyGenerator == null || keyPair == null) {
+ throw new IllegalStateException("PQC key generator and key pair must be configured for hybrid KEM operations");
+ }
+ if (ObjectHelper.isEmpty(getConfiguration().getSymmetricKeyAlgorithm())) {
+ throw new IllegalArgumentException("Symmetric Algorithm needs to be specified");
+ }
+
+ String symmetricAlgorithm = getConfiguration().getSymmetricKeyAlgorithm();
+ int keyLength = getConfiguration().getSymmetricKeyLength();
+ String kdfAlgorithm = getConfiguration().getHybridKdfAlgorithm();
+
+ // Generate hybrid encapsulation
+ HybridKEM.HybridEncapsulationResult result = HybridKEM.encapsulate(
+ classicalKeyPair.getPublic(),
+ keyPair.getPublic(),
+ classicalKeyAgreement,
+ keyGenerator,
+ symmetricAlgorithm,
+ keyLength,
+ kdfAlgorithm);
+
+ // Set results
+ exchange.getMessage().setBody(result.sharedSecret(), SecretKey.class);
+ exchange.getMessage().setHeader(PQCConstants.HYBRID_ENCAPSULATION, result.encapsulation());
+ exchange.getMessage().setHeader(PQCConstants.HYBRID_SECRET_KEY, result.sharedSecret());
+
+ // Parse for individual encapsulations
+ HybridKEM.HybridEncapsulationComponents components = HybridKEM.parse(result.encapsulation());
+ exchange.getMessage().setHeader(PQCConstants.CLASSICAL_ENCAPSULATION, components.classicalEncapsulation());
+ exchange.getMessage().setHeader(PQCConstants.PQC_ENCAPSULATION, components.pqcEncapsulation());
+ }
+
+ private void hybridExtractEncapsulation(Exchange exchange) throws Exception {
+ byte[] hybridEncapsulation = exchange.getMessage().getHeader(PQCConstants.HYBRID_ENCAPSULATION, byte[].class);
+ if (hybridEncapsulation == null) {
+ throw new IllegalArgumentException(
+ "Hybrid encapsulation not found in header: " + PQCConstants.HYBRID_ENCAPSULATION);
+ }
+
+ if (classicalKeyAgreement == null || classicalKeyPair == null) {
+ throw new IllegalStateException(
+ "Classical key agreement and key pair must be configured for hybrid KEM extraction");
+ }
+ if (keyGenerator == null || keyPair == null) {
+ throw new IllegalStateException("PQC key generator and key pair must be configured for hybrid KEM extraction");
+ }
+ if (ObjectHelper.isEmpty(getConfiguration().getSymmetricKeyAlgorithm())) {
+ throw new IllegalArgumentException("Symmetric Algorithm needs to be specified");
+ }
+
+ String symmetricAlgorithm = getConfiguration().getSymmetricKeyAlgorithm();
+ int keyLength = getConfiguration().getSymmetricKeyLength();
+ String kdfAlgorithm = getConfiguration().getHybridKdfAlgorithm();
+
+ // Extract shared secret from hybrid encapsulation
+ SecretKey sharedSecret = HybridKEM.extract(
+ hybridEncapsulation,
+ classicalKeyPair.getPrivate(),
+ keyPair.getPrivate(),
+ classicalKeyAgreement,
+ keyGenerator,
+ symmetricAlgorithm,
+ keyLength,
+ kdfAlgorithm);
+
+ exchange.getMessage().setBody(sharedSecret, SecretKey.class);
+ exchange.getMessage().setHeader(PQCConstants.HYBRID_SECRET_KEY, sharedSecret);
+ }
+
+ private void hybridExtractSecretKeyFromEncapsulation(Exchange exchange) throws Exception {
+ // Get the hybrid secret key from header or body
+ SecretKey hybridSecretKey = exchange.getMessage().getHeader(PQCConstants.HYBRID_SECRET_KEY, SecretKey.class);
+ if (hybridSecretKey == null) {
+ hybridSecretKey = exchange.getMessage().getBody(SecretKey.class);
+ }
+ if (hybridSecretKey == null) {
+ throw new IllegalArgumentException("Hybrid secret key not found in header or body");
+ }
+
+ if (ObjectHelper.isEmpty(getConfiguration().getSymmetricKeyAlgorithm())) {
+ throw new IllegalArgumentException("Symmetric Algorithm needs to be specified");
+ }
+
+ // Create a new SecretKeySpec with the correct algorithm
+ SecretKey restoredKey = new SecretKeySpec(hybridSecretKey.getEncoded(), getConfiguration().getSymmetricKeyAlgorithm());
+
+ if (!getConfiguration().isStoreExtractedSecretKeyAsHeader()) {
+ exchange.getMessage().setBody(restoredKey, SecretKey.class);
+ } else {
+ exchange.getMessage().setHeader(PQCConstants.SECRET_KEY, restoredKey);
+ }
+ }
+
}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/HybridKEM.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/HybridKEM.java
new file mode 100644
index 000000000000..34af21c1c30b
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/HybridKEM.java
@@ -0,0 +1,325 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.nio.ByteBuffer;
+import java.security.*;
+import java.security.spec.ECGenParameterSpec;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.bouncycastle.crypto.digests.SHA256Digest;
+import org.bouncycastle.crypto.digests.SHA384Digest;
+import org.bouncycastle.crypto.digests.SHA512Digest;
+import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
+import org.bouncycastle.crypto.params.HKDFParameters;
+import org.bouncycastle.jcajce.SecretKeyWithEncapsulation;
+import org.bouncycastle.jcajce.spec.KEMExtractSpec;
+import org.bouncycastle.jcajce.spec.KEMGenerateSpec;
+
+/**
+ * Utility class for hybrid Key Encapsulation Mechanism (KEM) operations combining classical key agreement (e.g., ECDH,
+ * X25519) with post-quantum KEM algorithms (e.g., ML-KEM).
+ * <p>
+ * Hybrid KEM provides defense-in-depth by combining:
+ * <ul>
+ * <li>Classical ECDH/X25519 key agreement for quantum-vulnerable but well-understood security</li>
+ * <li>Post-quantum KEM for quantum-resistant security</li>
+ * </ul>
+ * The shared secrets from both algorithms are combined using HKDF to produce the final shared secret.
+ * <p>
+ * Wire format: [4 bytes: classical encap length][classical encap][pqc encap]
+ */
+public final class HybridKEM {
+
+ private HybridKEM() {
+ // Utility class
+ }
+
+ /**
+ * Generates a hybrid encapsulation using both classical ECDH/XDH and PQC KEM.
+ *
+ * @param classicalPublicKey the recipient's classical public key (EC or XDH)
+ * @param pqcPublicKey the recipient's PQC public key
+ * @param classicalKA the classical key agreement instance
+ * @param pqcKemGenerator the PQC KEM key generator
+ * @param symmetricAlgorithm the symmetric algorithm for the shared secret (e.g., "AES")
+ * @param keyLength the symmetric key length in bits
+ * @param kdfAlgorithm the KDF algorithm (e.g., "HKDF-SHA256")
+ * @return the hybrid encapsulation result containing the combined secret
+ * @throws Exception if encapsulation fails
+ */
+ public static HybridEncapsulationResult encapsulate(
+ PublicKey classicalPublicKey,
+ PublicKey pqcPublicKey,
+ KeyAgreement classicalKA,
+ KeyGenerator pqcKemGenerator,
+ String symmetricAlgorithm,
+ int keyLength,
+ String kdfAlgorithm)
+ throws Exception {
+
+ if (classicalPublicKey == null || pqcPublicKey == null || classicalKA == null
+ || pqcKemGenerator == null || symmetricAlgorithm == null) {
+ throw new IllegalArgumentException("All parameters must be non-null");
+ }
+
+ // Generate ephemeral key pair for classical key agreement
+ KeyPair ephemeralKeyPair = generateEphemeralKeyPair(classicalPublicKey.getAlgorithm());
+
+ // Perform classical key agreement
+ classicalKA.init(ephemeralKeyPair.getPrivate());
+ classicalKA.doPhase(classicalPublicKey, true);
+ byte[] classicalSharedSecret = classicalKA.generateSecret();
+
+ // The classical "encapsulation" is the ephemeral public key
+ byte[] classicalEncapsulation = ephemeralKeyPair.getPublic().getEncoded();
+
+ // Perform PQC KEM encapsulation
+ pqcKemGenerator.init(
+ new KEMGenerateSpec(pqcPublicKey, symmetricAlgorithm, keyLength),
+ new SecureRandom());
+ SecretKeyWithEncapsulation pqcResult = (SecretKeyWithEncapsulation) pqcKemGenerator.generateKey();
+ byte[] pqcSharedSecret = pqcResult.getEncoded();
+ byte[] pqcEncapsulation = pqcResult.getEncapsulation();
+
+ // Combine shared secrets using HKDF
+ byte[] combinedSecret = combineSecrets(
+ classicalSharedSecret,
+ pqcSharedSecret,
+ kdfAlgorithm,
+ keyLength / 8,
+ symmetricAlgorithm);
+
+ SecretKey hybridSecretKey = new SecretKeySpec(combinedSecret, symmetricAlgorithm);
+
+ // Combine encapsulations
+ byte[] hybridEncapsulation = combineEncapsulations(classicalEncapsulation, pqcEncapsulation);
+
+ return new HybridEncapsulationResult(
+ hybridEncapsulation,
+ hybridSecretKey,
+ classicalSharedSecret,
+ pqcSharedSecret);
+ }
+
+ /**
+ * Extracts the shared secret from a hybrid encapsulation.
+ *
+ * @param hybridEncapsulation the hybrid encapsulation to extract from
+ * @param classicalPrivateKey the recipient's classical private key
+ * @param pqcPrivateKey the recipient's PQC private key
+ * @param classicalKA the classical key agreement instance
+ * @param pqcKemGenerator the PQC KEM key generator
+ * @param symmetricAlgorithm the symmetric algorithm for the shared secret
+ * @param keyLength the symmetric key length in bits
+ * @param kdfAlgorithm the KDF algorithm
+ * @return the extracted shared secret key
+ * @throws Exception if extraction fails
+ */
+ public static SecretKey extract(
+ byte[] hybridEncapsulation,
+ PrivateKey classicalPrivateKey,
+ PrivateKey pqcPrivateKey,
+ KeyAgreement classicalKA,
+ KeyGenerator pqcKemGenerator,
+ String symmetricAlgorithm,
+ int keyLength,
+ String kdfAlgorithm)
+ throws Exception {
+
+ if (hybridEncapsulation == null || classicalPrivateKey == null || pqcPrivateKey == null
+ || classicalKA == null || pqcKemGenerator == null || symmetricAlgorithm == null) {
+ throw new IllegalArgumentException("All parameters must be non-null");
+ }
+
+ // Parse the hybrid encapsulation
+ HybridEncapsulationComponents components = parse(hybridEncapsulation);
+
+ // Reconstruct the ephemeral public key from classical encapsulation
+ PublicKey ephemeralPublicKey = reconstructPublicKey(
+ components.classicalEncapsulation(),
+ classicalPrivateKey.getAlgorithm());
+
+ // Perform classical key agreement
+ classicalKA.init(classicalPrivateKey);
+ classicalKA.doPhase(ephemeralPublicKey, true);
+ byte[] classicalSharedSecret = classicalKA.generateSecret();
+
+ // Perform PQC KEM extraction
+ pqcKemGenerator.init(
+ new KEMExtractSpec(pqcPrivateKey, components.pqcEncapsulation(), symmetricAlgorithm, keyLength),
+ new SecureRandom());
+ SecretKeyWithEncapsulation pqcResult = (SecretKeyWithEncapsulation) pqcKemGenerator.generateKey();
+ byte[] pqcSharedSecret = pqcResult.getEncoded();
+
+ // Combine shared secrets using HKDF
+ byte[] combinedSecret = combineSecrets(
+ classicalSharedSecret,
+ pqcSharedSecret,
+ kdfAlgorithm,
+ keyLength / 8,
+ symmetricAlgorithm);
+
+ return new SecretKeySpec(combinedSecret, symmetricAlgorithm);
+ }
+
+ /**
+ * Parses a hybrid encapsulation into its component parts.
+ *
+ * @param hybridEncapsulation the hybrid encapsulation to parse
+ * @return the parsed components
+ * @throws IllegalArgumentException if the format is invalid
+ */
+ public static HybridEncapsulationComponents parse(byte[] hybridEncapsulation) {
+ if (hybridEncapsulation == null || hybridEncapsulation.length < 5) {
+ throw new IllegalArgumentException("Invalid hybrid encapsulation: too short");
+ }
+
+ ByteBuffer buffer = ByteBuffer.wrap(hybridEncapsulation);
+
+ // Read classical encapsulation length
+ int classicalLength = buffer.getInt();
+ if (classicalLength <= 0 || classicalLength > hybridEncapsulation.length - 4) {
+ throw new IllegalArgumentException("Invalid hybrid encapsulation: invalid classical length");
+ }
+
+ // Read classical encapsulation
+ byte[] classicalEncapsulation = new byte[classicalLength];
+ buffer.get(classicalEncapsulation);
+
+ // Read PQC encapsulation (remaining bytes)
+ int pqcLength = buffer.remaining();
+ if (pqcLength <= 0) {
+ throw new IllegalArgumentException("Invalid hybrid encapsulation: missing PQC encapsulation");
+ }
+ byte[] pqcEncapsulation = new byte[pqcLength];
+ buffer.get(pqcEncapsulation);
+
+ return new HybridEncapsulationComponents(classicalEncapsulation, pqcEncapsulation);
+ }
+
+ /**
+ * Combines classical and PQC encapsulations into a hybrid encapsulation.
+ */
+ public static byte[] combineEncapsulations(byte[] classicalEncapsulation, byte[] pqcEncapsulation) {
+ ByteBuffer buffer = ByteBuffer.allocate(4 + classicalEncapsulation.length + pqcEncapsulation.length);
+ buffer.putInt(classicalEncapsulation.length);
+ buffer.put(classicalEncapsulation);
+ buffer.put(pqcEncapsulation);
+ return buffer.array();
+ }
+
+ /**
+ * Combines two shared secrets using HKDF.
+ */
+ private static byte[] combineSecrets(
+ byte[] secret1,
+ byte[] secret2,
+ String kdfAlgorithm,
+ int outputLength,
+ String info)
+ throws Exception {
+
+ // Concatenate the secrets as input key material
+ byte[] ikm = new byte[secret1.length + secret2.length];
+ System.arraycopy(secret1, 0, ikm, 0, secret1.length);
+ System.arraycopy(secret2, 0, ikm, secret1.length, secret2.length);
+
+ // Use HKDF to derive the final key
+ HKDFBytesGenerator hkdf = createHKDF(kdfAlgorithm);
+ hkdf.init(new HKDFParameters(ikm, null, info.getBytes()));
+
+ byte[] output = new byte[outputLength];
+ hkdf.generateBytes(output, 0, outputLength);
+
+ return output;
+ }
+
+ /**
+ * Creates an HKDF instance based on the algorithm name.
+ */
+ private static HKDFBytesGenerator createHKDF(String algorithm) {
+ return switch (algorithm) {
+ case "HKDF-SHA256" -> new HKDFBytesGenerator(new SHA256Digest());
+ case "HKDF-SHA384" -> new HKDFBytesGenerator(new SHA384Digest());
+ case "HKDF-SHA512" -> new HKDFBytesGenerator(new SHA512Digest());
+ default -> new HKDFBytesGenerator(new SHA256Digest());
+ };
+ }
+
+ /**
+ * Generates an ephemeral key pair for the given algorithm.
+ */
+ private static KeyPair generateEphemeralKeyPair(String algorithm) throws Exception {
+ KeyPairGenerator kpg;
+
+ if ("EC".equals(algorithm)) {
+ kpg = KeyPairGenerator.getInstance("EC");
+ // Default to P-256
+ kpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ } else if ("X25519".equals(algorithm) || "XDH".equals(algorithm)) {
+ kpg = KeyPairGenerator.getInstance("X25519");
+ } else if ("X448".equals(algorithm)) {
+ kpg = KeyPairGenerator.getInstance("X448");
+ } else {
+ // For other algorithms, try to use the same algorithm
+ kpg = KeyPairGenerator.getInstance(algorithm);
+ }
+
+ return kpg.generateKeyPair();
+ }
+
+ /**
+ * Reconstructs a public key from encoded bytes.
+ */
+ private static PublicKey reconstructPublicKey(byte[] encoded, String algorithm) throws Exception {
+ java.security.KeyFactory kf;
+
+ if ("EC".equals(algorithm) || "ECDH".equals(algorithm)) {
+ kf = java.security.KeyFactory.getInstance("EC");
+ } else if ("X25519".equals(algorithm) || "XDH".equals(algorithm)) {
+ kf = java.security.KeyFactory.getInstance("X25519");
+ } else if ("X448".equals(algorithm)) {
+ kf = java.security.KeyFactory.getInstance("X448");
+ } else {
+ kf = java.security.KeyFactory.getInstance(algorithm);
+ }
+
+ java.security.spec.X509EncodedKeySpec keySpec = new java.security.spec.X509EncodedKeySpec(encoded);
+ return kf.generatePublic(keySpec);
+ }
+
+ /**
+ * Record holding the result of a hybrid encapsulation operation.
+ */
+ public record HybridEncapsulationResult(
+ byte[] encapsulation,
+ SecretKey sharedSecret,
+ byte[] classicalSharedSecret,
+ byte[] pqcSharedSecret) {
+ }
+
+ /**
+ * Record holding the parsed components of a hybrid encapsulation.
+ */
+ public record HybridEncapsulationComponents(byte[] classicalEncapsulation, byte[] pqcEncapsulation) {
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/HybridSignature.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/HybridSignature.java
new file mode 100644
index 000000000000..281d99ace36d
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/HybridSignature.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.nio.ByteBuffer;
+import java.security.*;
+
+/**
+ * Utility class for hybrid signature operations combining classical and post-quantum cryptography algorithms.
+ * <p>
+ * Hybrid signatures provide defense-in-depth by combining a classical signature (e.g., ECDSA, RSA) with a post-quantum
+ * signature (e.g., ML-DSA, Dilithium). Both signatures must verify for the hybrid signature to be valid, ensuring
+ * security even if one algorithm is compromised.
+ * <p>
+ * The wire format is: [4 bytes: classical sig length][classical sig][pqc sig]
+ */
+public final class HybridSignature {
+
+ private HybridSignature() {
+ // Utility class
+ }
+
+ /**
+ * Creates a hybrid signature by signing data with both classical and PQC algorithms.
+ *
+ * @param data the data to sign
+ * @param classicalPrivateKey the classical private key (e.g., ECDSA, RSA)
+ * @param classicalSigner the classical signature instance
+ * @param pqcPrivateKey the PQC private key (e.g., ML-DSA, Dilithium)
+ * @param pqcSigner the PQC signature instance
+ * @return the hybrid signature containing both signatures
+ * @throws InvalidKeyException if a key is invalid
+ * @throws SignatureException if signing fails
+ * @throws IllegalArgumentException if any parameter is null
+ */
+ public static byte[] sign(
+ byte[] data,
+ PrivateKey classicalPrivateKey,
+ Signature classicalSigner,
+ PrivateKey pqcPrivateKey,
+ Signature pqcSigner)
+ throws InvalidKeyException, SignatureException {
+
+ if (data == null || classicalPrivateKey == null || classicalSigner == null
+ || pqcPrivateKey == null || pqcSigner == null) {
+ throw new IllegalArgumentException("All parameters must be non-null");
+ }
+
+ // Create classical signature
+ classicalSigner.initSign(classicalPrivateKey);
+ classicalSigner.update(data);
+ byte[] classicalSignature = classicalSigner.sign();
+
+ // Create PQC signature
+ pqcSigner.initSign(pqcPrivateKey);
+ pqcSigner.update(data);
+ byte[] pqcSignature = pqcSigner.sign();
+
+ // Combine: [4 bytes length][classical sig][pqc sig]
+ return combineSignatures(classicalSignature, pqcSignature);
+ }
+
+ /**
+ * Verifies a hybrid signature - BOTH signatures must be valid for verification to succeed.
+ *
+ * @param data the original data that was signed
+ * @param hybridSignature the hybrid signature to verify
+ * @param classicalPublicKey the classical public key
+ * @param classicalSigner the classical signature instance
+ * @param pqcPublicKey the PQC public key
+ * @param pqcSigner the PQC signature instance
+ * @return true if both signatures are valid, false otherwise
+ * @throws InvalidKeyException if a key is invalid
+ * @throws SignatureException if verification fails unexpectedly
+ */
+ public static boolean verify(
+ byte[] data,
+ byte[] hybridSignature,
+ PublicKey classicalPublicKey,
+ Signature classicalSigner,
+ PublicKey pqcPublicKey,
+ Signature pqcSigner)
+ throws InvalidKeyException, SignatureException {
+
+ if (data == null || hybridSignature == null || classicalPublicKey == null
+ || classicalSigner == null || pqcPublicKey == null || pqcSigner == null) {
+ throw new IllegalArgumentException("All parameters must be non-null");
+ }
+
+ // Parse the hybrid signature
+ HybridSignatureComponents components = parse(hybridSignature);
+
+ // Verify classical signature
+ classicalSigner.initVerify(classicalPublicKey);
+ classicalSigner.update(data);
+ boolean classicalValid = classicalSigner.verify(components.classicalSignature());
+
+ // Verify PQC signature
+ pqcSigner.initVerify(pqcPublicKey);
+ pqcSigner.update(data);
+ boolean pqcValid = pqcSigner.verify(components.pqcSignature());
+
+ // Both must be valid
+ return classicalValid && pqcValid;
+ }
+
+ /**
+ * Verifies a hybrid signature and returns detailed results for each component.
+ *
+ * @param data the original data that was signed
+ * @param hybridSignature the hybrid signature to verify
+ * @param classicalPublicKey the classical public key
+ * @param classicalSigner the classical signature instance
+ * @param pqcPublicKey the PQC public key
+ * @param pqcSigner the PQC signature instance
+ * @return verification result with details
+ * @throws InvalidKeyException if a key is invalid
+ * @throws SignatureException if verification fails unexpectedly
+ */
+ public static HybridVerificationResult verifyDetailed(
+ byte[] data,
+ byte[] hybridSignature,
+ PublicKey classicalPublicKey,
+ Signature classicalSigner,
+ PublicKey pqcPublicKey,
+ Signature pqcSigner)
+ throws InvalidKeyException, SignatureException {
+
+ if (data == null || hybridSignature == null || classicalPublicKey == null
+ || classicalSigner == null || pqcPublicKey == null || pqcSigner == null) {
+ throw new IllegalArgumentException("All parameters must be non-null");
+ }
+
+ HybridSignatureComponents components = parse(hybridSignature);
+
+ // Verify classical signature
+ classicalSigner.initVerify(classicalPublicKey);
+ classicalSigner.update(data);
+ boolean classicalValid = classicalSigner.verify(components.classicalSignature());
+
+ // Verify PQC signature
+ pqcSigner.initVerify(pqcPublicKey);
+ pqcSigner.update(data);
+ boolean pqcValid = pqcSigner.verify(components.pqcSignature());
+
+ return new HybridVerificationResult(classicalValid, pqcValid);
+ }
+
+ /**
+ * Parses a hybrid signature into its component parts.
+ *
+ * @param hybridSignature the hybrid signature to parse
+ * @return the parsed components
+ * @throws IllegalArgumentException if the signature format is invalid
+ */
+ public static HybridSignatureComponents parse(byte[] hybridSignature) {
+ if (hybridSignature == null || hybridSignature.length < 5) {
+ throw new IllegalArgumentException("Invalid hybrid signature: too short");
+ }
+
+ ByteBuffer buffer = ByteBuffer.wrap(hybridSignature);
+
+ // Read classical signature length
+ int classicalLength = buffer.getInt();
+ if (classicalLength <= 0 || classicalLength > hybridSignature.length - 4) {
+ throw new IllegalArgumentException("Invalid hybrid signature: invalid classical signature length");
+ }
+
+ // Read classical signature
+ byte[] classicalSignature = new byte[classicalLength];
+ buffer.get(classicalSignature);
+
+ // Read PQC signature (remaining bytes)
+ int pqcLength = buffer.remaining();
+ if (pqcLength <= 0) {
+ throw new IllegalArgumentException("Invalid hybrid signature: missing PQC signature");
+ }
+ byte[] pqcSignature = new byte[pqcLength];
+ buffer.get(pqcSignature);
+
+ return new HybridSignatureComponents(classicalSignature, pqcSignature);
+ }
+
+ /**
+ * Combines classical and PQC signatures into a hybrid signature.
+ *
+ * @param classicalSignature the classical signature bytes
+ * @param pqcSignature the PQC signature bytes
+ * @return the combined hybrid signature
+ */
+ public static byte[] combineSignatures(byte[] classicalSignature, byte[] pqcSignature) {
+ ByteBuffer buffer = ByteBuffer.allocate(4 + classicalSignature.length + pqcSignature.length);
+ buffer.putInt(classicalSignature.length);
+ buffer.put(classicalSignature);
+ buffer.put(pqcSignature);
+ return buffer.array();
+ }
+
+ /**
+ * Record holding the parsed components of a hybrid signature.
+ */
+ public record HybridSignatureComponents(byte[] classicalSignature, byte[] pqcSignature) {
+ }
+
+ /**
+ * Record holding the verification results for a hybrid signature.
+ */
+ public record HybridVerificationResult(boolean classicalValid, boolean pqcValid) {
+
+ /**
+ * Returns true if both signatures are valid.
+ */
+ public boolean isValid() {
+ return classicalValid && pqcValid;
+ }
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultECDHMLKEMMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultECDHMLKEMMaterial.java
new file mode 100644
index 000000000000..2b61a66ac583
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultECDHMLKEMMaterial.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.*;
+import java.security.spec.ECGenParameterSpec;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+
+import org.apache.camel.component.pqc.PQCKeyEncapsulationAlgorithms;
+import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+
+/**
+ * Default hybrid KEM material combining ECDH P-256 with ML-KEM-768. This combination provides compatibility with
+ * existing ECDH-based systems while adding quantum-resistant security from ML-KEM.
+ */
+public class PQCDefaultECDHMLKEMMaterial {
+
+ public static final KeyPair classicalKeyPair;
+ public static final KeyAgreement classicalKeyAgreement;
+ public static final KeyPair pqcKeyPair;
+ public static final KeyGenerator pqcKeyGenerator;
+ public static final PQCHybridKEMMaterial material;
+
+ static {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+
+ try {
+ // Generate ECDH P-256 key pair
+ KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
+ ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ classicalKeyPair = ecKpg.generateKeyPair();
+ classicalKeyAgreement = KeyAgreement.getInstance("ECDH", "BC");
+
+ // Generate ML-KEM-768 key pair
+ KeyPairGenerator mlkemKpg = KeyPairGenerator.getInstance(
+ PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(),
+ PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider());
+ mlkemKpg.initialize(MLKEMParameterSpec.ml_kem_768, new SecureRandom());
+ pqcKeyPair = mlkemKpg.generateKeyPair();
+ pqcKeyGenerator = KeyGenerator.getInstance(
+ PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(),
+ PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider());
+
+ // Create the material container
+ material = new PQCHybridKEMMaterial(
+ classicalKeyPair,
+ classicalKeyAgreement,
+ pqcKeyPair,
+ pqcKeyGenerator,
+ "ECDH_P256",
+ "MLKEM");
+
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize hybrid ECDH + ML-KEM material", e);
+ }
+ }
+
+ private PQCDefaultECDHMLKEMMaterial() {
+ // Static access only
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultECDSAMLDSAMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultECDSAMLDSAMaterial.java
new file mode 100644
index 000000000000..c70e60ac7769
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultECDSAMLDSAMaterial.java
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.*;
+import java.security.spec.ECGenParameterSpec;
+
+import org.apache.camel.component.pqc.PQCSignatureAlgorithms;
+import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+
+/**
+ * Default hybrid signature material combining ECDSA P-256 with ML-DSA-65. This is the recommended hybrid combination
+ * providing both classical security from ECDSA and quantum-resistant security from ML-DSA.
+ * <p>
+ * NIST recommends this combination for the transition period to post-quantum cryptography.
+ */
+public class PQCDefaultECDSAMLDSAMaterial {
+
+ public static final KeyPair classicalKeyPair;
+ public static final Signature classicalSigner;
+ public static final KeyPair pqcKeyPair;
+ public static final Signature pqcSigner;
+ public static final PQCHybridSignatureMaterial material;
+
+ static {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+
+ try {
+ // Generate ECDSA P-256 key pair
+ KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
+ ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ classicalKeyPair = ecKpg.generateKeyPair();
+ classicalSigner = Signature.getInstance("SHA256withECDSA", "BC");
+
+ // Generate ML-DSA-65 key pair
+ KeyPairGenerator mldsaKpg = KeyPairGenerator.getInstance(
+ PQCSignatureAlgorithms.MLDSA.getAlgorithm(),
+ PQCSignatureAlgorithms.MLDSA.getBcProvider());
+ mldsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65, new SecureRandom());
+ pqcKeyPair = mldsaKpg.generateKeyPair();
+ pqcSigner = Signature.getInstance(
+ PQCSignatureAlgorithms.MLDSA.getAlgorithm(),
+ PQCSignatureAlgorithms.MLDSA.getBcProvider());
+
+ // Create the material container
+ material = new PQCHybridSignatureMaterial(
+ classicalKeyPair,
+ classicalSigner,
+ pqcKeyPair,
+ pqcSigner,
+ "ECDSA_P256",
+ "MLDSA");
+
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize hybrid ECDSA + ML-DSA material", e);
+ }
+ }
+
+ private PQCDefaultECDSAMLDSAMaterial() {
+ // Static access only
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultEd25519MLDSAMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultEd25519MLDSAMaterial.java
new file mode 100644
index 000000000000..a5497416fa50
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultEd25519MLDSAMaterial.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.*;
+
+import org.apache.camel.component.pqc.PQCSignatureAlgorithms;
+import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+
+/**
+ * Default hybrid signature material combining Ed25519 with ML-DSA-65. This combination provides fast classical
+ * signatures from Ed25519 combined with quantum-resistant security from ML-DSA.
+ */
+public class PQCDefaultEd25519MLDSAMaterial {
+
+ public static final KeyPair classicalKeyPair;
+ public static final Signature classicalSigner;
+ public static final KeyPair pqcKeyPair;
+ public static final Signature pqcSigner;
+ public static final PQCHybridSignatureMaterial material;
+
+ static {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+
+ try {
+ // Generate Ed25519 key pair
+ KeyPairGenerator edKpg = KeyPairGenerator.getInstance("Ed25519", "BC");
+ classicalKeyPair = edKpg.generateKeyPair();
+ classicalSigner = Signature.getInstance("Ed25519", "BC");
+
+ // Generate ML-DSA-65 key pair
+ KeyPairGenerator mldsaKpg = KeyPairGenerator.getInstance(
+ PQCSignatureAlgorithms.MLDSA.getAlgorithm(),
+ PQCSignatureAlgorithms.MLDSA.getBcProvider());
+ mldsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65, new SecureRandom());
+ pqcKeyPair = mldsaKpg.generateKeyPair();
+ pqcSigner = Signature.getInstance(
+ PQCSignatureAlgorithms.MLDSA.getAlgorithm(),
+ PQCSignatureAlgorithms.MLDSA.getBcProvider());
+
+ // Create the material container
+ material = new PQCHybridSignatureMaterial(
+ classicalKeyPair,
+ classicalSigner,
+ pqcKeyPair,
+ pqcSigner,
+ "ED25519",
+ "MLDSA");
+
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize hybrid Ed25519 + ML-DSA material", e);
+ }
+ }
+
+ private PQCDefaultEd25519MLDSAMaterial() {
+ // Static access only
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultX25519MLKEMMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultX25519MLKEMMaterial.java
new file mode 100644
index 000000000000..8168352f5695
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCDefaultX25519MLKEMMaterial.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.*;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+
+import org.apache.camel.component.pqc.PQCKeyEncapsulationAlgorithms;
+import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+
+/**
+ * Default hybrid KEM material combining X25519 with ML-KEM-768. This is the recommended hybrid combination per NIST
+ * guidelines, providing both classical security from X25519 and quantum-resistant security from ML-KEM.
+ * <p>
+ * X25519 + ML-KEM is recommended for:
+ * <ul>
+ * <li>TLS 1.3 hybrid key exchange</li>
+ * <li>General purpose hybrid key encapsulation</li>
+ * <li>Protection against "harvest now, decrypt later" attacks</li>
+ * </ul>
+ */
+public class PQCDefaultX25519MLKEMMaterial {
+
+ public static final KeyPair classicalKeyPair;
+ public static final KeyAgreement classicalKeyAgreement;
+ public static final KeyPair pqcKeyPair;
+ public static final KeyGenerator pqcKeyGenerator;
+ public static final PQCHybridKEMMaterial material;
+
+ static {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+
+ try {
+ // Generate X25519 key pair
+ KeyPairGenerator x25519Kpg = KeyPairGenerator.getInstance("X25519", "BC");
+ classicalKeyPair = x25519Kpg.generateKeyPair();
+ classicalKeyAgreement = KeyAgreement.getInstance("X25519", "BC");
+
+ // Generate ML-KEM-768 key pair
+ KeyPairGenerator mlkemKpg = KeyPairGenerator.getInstance(
+ PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(),
+ PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider());
+ mlkemKpg.initialize(MLKEMParameterSpec.ml_kem_768, new SecureRandom());
+ pqcKeyPair = mlkemKpg.generateKeyPair();
+ pqcKeyGenerator = KeyGenerator.getInstance(
+ PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(),
+ PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider());
+
+ // Create the material container
+ material = new PQCHybridKEMMaterial(
+ classicalKeyPair,
+ classicalKeyAgreement,
+ pqcKeyPair,
+ pqcKeyGenerator,
+ "X25519",
+ "MLKEM");
+
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to initialize hybrid X25519 + ML-KEM material", e);
+ }
+ }
+
+ private PQCDefaultX25519MLKEMMaterial() {
+ // Static access only
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCHybridKEMMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCHybridKEMMaterial.java
new file mode 100644
index 000000000000..f6185513b43b
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCHybridKEMMaterial.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.KeyPair;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+
+/**
+ * Container class for hybrid KEM cryptographic material. Holds both classical key agreement and PQC KEM materials
+ * needed for hybrid key encapsulation operations.
+ */
+public class PQCHybridKEMMaterial {
+
+ private final KeyPair classicalKeyPair;
+ private final KeyAgreement classicalKeyAgreement;
+ private final KeyPair pqcKeyPair;
+ private final KeyGenerator pqcKeyGenerator;
+ private final String classicalAlgorithm;
+ private final String pqcAlgorithm;
+
+ /**
+ * Creates a new hybrid KEM material.
+ *
+ * @param classicalKeyPair the classical key pair (e.g., ECDH, X25519)
+ * @param classicalKeyAgreement the classical key agreement instance
+ * @param pqcKeyPair the PQC key pair (e.g., ML-KEM)
+ * @param pqcKeyGenerator the PQC KEM key generator
+ * @param classicalAlgorithm the classical algorithm name
+ * @param pqcAlgorithm the PQC algorithm name
+ */
+ public PQCHybridKEMMaterial(
+ KeyPair classicalKeyPair,
+ KeyAgreement classicalKeyAgreement,
+ KeyPair pqcKeyPair,
+ KeyGenerator pqcKeyGenerator,
+ String classicalAlgorithm,
+ String pqcAlgorithm) {
+ this.classicalKeyPair = classicalKeyPair;
+ this.classicalKeyAgreement = classicalKeyAgreement;
+ this.pqcKeyPair = pqcKeyPair;
+ this.pqcKeyGenerator = pqcKeyGenerator;
+ this.classicalAlgorithm = classicalAlgorithm;
+ this.pqcAlgorithm = pqcAlgorithm;
+ }
+
+ public KeyPair getClassicalKeyPair() {
+ return classicalKeyPair;
+ }
+
+ public KeyAgreement getClassicalKeyAgreement() {
+ return classicalKeyAgreement;
+ }
+
+ public KeyPair getPqcKeyPair() {
+ return pqcKeyPair;
+ }
+
+ public KeyGenerator getPqcKeyGenerator() {
+ return pqcKeyGenerator;
+ }
+
+ public String getClassicalAlgorithm() {
+ return classicalAlgorithm;
+ }
+
+ public String getPqcAlgorithm() {
+ return pqcAlgorithm;
+ }
+
+ /**
+ * Returns a description of this hybrid material.
+ */
+ public String getDescription() {
+ return classicalAlgorithm + " + " + pqcAlgorithm;
+ }
+}
diff --git a/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCHybridSignatureMaterial.java b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCHybridSignatureMaterial.java
new file mode 100644
index 000000000000..43d6178aeaed
--- /dev/null
+++ b/components/camel-pqc/src/main/java/org/apache/camel/component/pqc/crypto/hybrid/PQCHybridSignatureMaterial.java
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.KeyPair;
+import java.security.Signature;
+
+/**
+ * Container class for hybrid signature cryptographic material. Holds both classical and PQC key pairs and signature
+ * instances needed for hybrid signature operations.
+ */
+public class PQCHybridSignatureMaterial {
+
+ private final KeyPair classicalKeyPair;
+ private final Signature classicalSigner;
+ private final KeyPair pqcKeyPair;
+ private final Signature pqcSigner;
+ private final String classicalAlgorithm;
+ private final String pqcAlgorithm;
+
+ /**
+ * Creates a new hybrid signature material.
+ *
+ * @param classicalKeyPair the classical key pair (e.g., ECDSA, RSA)
+ * @param classicalSigner the classical signature instance
+ * @param pqcKeyPair the PQC key pair (e.g., ML-DSA, Dilithium)
+ * @param pqcSigner the PQC signature instance
+ * @param classicalAlgorithm the classical algorithm name
+ * @param pqcAlgorithm the PQC algorithm name
+ */
+ public PQCHybridSignatureMaterial(
+ KeyPair classicalKeyPair,
+ Signature classicalSigner,
+ KeyPair pqcKeyPair,
+ Signature pqcSigner,
+ String classicalAlgorithm,
+ String pqcAlgorithm) {
+ this.classicalKeyPair = classicalKeyPair;
+ this.classicalSigner = classicalSigner;
+ this.pqcKeyPair = pqcKeyPair;
+ this.pqcSigner = pqcSigner;
+ this.classicalAlgorithm = classicalAlgorithm;
+ this.pqcAlgorithm = pqcAlgorithm;
+ }
+
+ public KeyPair getClassicalKeyPair() {
+ return classicalKeyPair;
+ }
+
+ public Signature getClassicalSigner() {
+ return classicalSigner;
+ }
+
+ public KeyPair getPqcKeyPair() {
+ return pqcKeyPair;
+ }
+
+ public Signature getPqcSigner() {
+ return pqcSigner;
+ }
+
+ public String getClassicalAlgorithm() {
+ return classicalAlgorithm;
+ }
+
+ public String getPqcAlgorithm() {
+ return pqcAlgorithm;
+ }
+
+ /**
+ * Returns a description of this hybrid material.
+ */
+ public String getDescription() {
+ return classicalAlgorithm + " + " + pqcAlgorithm;
+ }
+}
diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridKEMECDHMLKEMTest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridKEMECDHMLKEMTest.java
new file mode 100644
index 000000000000..6c498afc4eaa
--- /dev/null
+++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridKEMECDHMLKEMTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+import java.security.Security;
+
+import javax.crypto.SecretKey;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Test for hybrid KEM using ECDH P-256 + ML-KEM.
+ */
+public class PQCHybridKEMECDHMLKEMTest extends CamelTestSupport {
+
+ @EndpointInject("mock:encapsulated")
+ protected MockEndpoint resultEncapsulate;
+
+ @EndpointInject("mock:extracted")
+ protected MockEndpoint resultExtract;
+
+ @Produce("direct:encapsulate")
+ protected ProducerTemplate templateEncapsulate;
+
+ @BeforeAll
+ public static void startup() {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:encapsulate")
+ .to("pqc:hybridkem?operation=hybridGenerateSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=ECDH_P256"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=128")
+ .to("mock:encapsulated")
+ .to("pqc:hybridkem?operation=hybridExtractSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=ECDH_P256"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=128")
+ .to("mock:extracted");
+ }
+ };
+ }
+
+ @Test
+ void testHybridKEMWithECDH() throws Exception {
+ resultEncapsulate.expectedMessageCount(1);
+ resultExtract.expectedMessageCount(1);
+
+ templateEncapsulate.sendBody("trigger");
+
+ resultEncapsulate.assertIsSatisfied();
+ resultExtract.assertIsSatisfied();
+
+ // Check that hybrid encapsulation was created
+ byte[] hybridEncap = resultEncapsulate.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_ENCAPSULATION, byte[].class);
+ assertNotNull(hybridEncap);
+ assertTrue(hybridEncap.length > 0);
+
+ // Check that shared secret was created and has correct length (128 bits = 16 bytes)
+ SecretKey encapSecret = resultEncapsulate.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_SECRET_KEY, SecretKey.class);
+ assertNotNull(encapSecret);
+ assertEquals("AES", encapSecret.getAlgorithm());
+ assertEquals(16, encapSecret.getEncoded().length);
+
+ // Check that extracted secret matches
+ SecretKey extractedSecret = resultExtract.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_SECRET_KEY, SecretKey.class);
+ assertNotNull(extractedSecret);
+
+ // The secrets should be identical
+ assertArrayEquals(encapSecret.getEncoded(), extractedSecret.getEncoded());
+ }
+}
diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridKEMX25519MLKEMTest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridKEMX25519MLKEMTest.java
new file mode 100644
index 000000000000..76722d7dd24b
--- /dev/null
+++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridKEMX25519MLKEMTest.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+import java.security.Security;
+
+import javax.crypto.SecretKey;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * Test for hybrid KEM using X25519 + ML-KEM.
+ */
+public class PQCHybridKEMX25519MLKEMTest extends CamelTestSupport {
+
+ @EndpointInject("mock:encapsulated")
+ protected MockEndpoint resultEncapsulate;
+
+ @EndpointInject("mock:extracted")
+ protected MockEndpoint resultExtract;
+
+ @Produce("direct:encapsulate")
+ protected ProducerTemplate templateEncapsulate;
+
+ @BeforeAll
+ public static void startup() {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:encapsulate")
+ .to("pqc:hybridkem?operation=hybridGenerateSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=X25519"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=256")
+ .to("mock:encapsulated")
+ .to("pqc:hybridkem?operation=hybridExtractSecretKeyEncapsulation"
+ + "&keyEncapsulationAlgorithm=MLKEM"
+ + "&classicalKEMAlgorithm=X25519"
+ + "&symmetricKeyAlgorithm=AES"
+ + "&symmetricKeyLength=256")
+ .to("mock:extracted");
+ }
+ };
+ }
+
+ @Test
+ void testHybridKEMEncapsulateAndExtract() throws Exception {
+ resultEncapsulate.expectedMessageCount(1);
+ resultExtract.expectedMessageCount(1);
+
+ templateEncapsulate.sendBody("trigger");
+
+ resultEncapsulate.assertIsSatisfied();
+ resultExtract.assertIsSatisfied();
+
+ // Check that hybrid encapsulation was created
+ byte[] hybridEncap = resultEncapsulate.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_ENCAPSULATION, byte[].class);
+ assertNotNull(hybridEncap);
+ assertTrue(hybridEncap.length > 0);
+
+ // Check that classical encapsulation component exists
+ byte[] classicalEncap = resultEncapsulate.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.CLASSICAL_ENCAPSULATION, byte[].class);
+ assertNotNull(classicalEncap);
+
+ // Check that PQC encapsulation component exists
+ byte[] pqcEncap = resultEncapsulate.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.PQC_ENCAPSULATION, byte[].class);
+ assertNotNull(pqcEncap);
+
+ // Check that shared secret was created
+ SecretKey encapSecret = resultEncapsulate.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_SECRET_KEY, SecretKey.class);
+ assertNotNull(encapSecret);
+ assertEquals("AES", encapSecret.getAlgorithm());
+
+ // Check that extracted secret matches
+ SecretKey extractedSecret = resultExtract.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_SECRET_KEY, SecretKey.class);
+ assertNotNull(extractedSecret);
+
+ // The secrets should be identical
+ assertArrayEquals(encapSecret.getEncoded(), extractedSecret.getEncoded());
+ }
+}
diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridSignatureECDSAMLDSATest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridSignatureECDSAMLDSATest.java
new file mode 100644
index 000000000000..a45f6397a22d
--- /dev/null
+++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridSignatureECDSAMLDSATest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+import java.security.Security;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test for hybrid signature using ECDSA P-256 + ML-DSA.
+ */
+public class PQCHybridSignatureECDSAMLDSATest extends CamelTestSupport {
+
+ @EndpointInject("mock:signed")
+ protected MockEndpoint resultSign;
+
+ @EndpointInject("mock:verified")
+ protected MockEndpoint resultVerify;
+
+ @Produce("direct:sign")
+ protected ProducerTemplate templateSign;
+
+ @BeforeAll
+ public static void startup() {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:sign")
+ .to("pqc:hybridsign?operation=hybridSign"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ECDSA_P256")
+ .to("mock:signed")
+ .to("pqc:hybridverify?operation=hybridVerify"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ECDSA_P256")
+ .to("mock:verified");
+ }
+ };
+ }
+
+ @Test
+ void testHybridSignAndVerify() throws Exception {
+ resultSign.expectedMessageCount(1);
+ resultVerify.expectedMessageCount(1);
+
+ templateSign.sendBody("Hello, hybrid cryptography!");
+
+ resultSign.assertIsSatisfied();
+ resultVerify.assertIsSatisfied();
+
+ // Check that hybrid signature was created
+ byte[] hybridSig = resultSign.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_SIGNATURE, byte[].class);
+ assertNotNull(hybridSig);
+ assertTrue(hybridSig.length > 0);
+
+ // Check that classical signature component exists
+ byte[] classicalSig = resultSign.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.CLASSICAL_SIGNATURE, byte[].class);
+ assertNotNull(classicalSig);
+
+ // Check that PQC signature component exists
+ byte[] pqcSig = resultSign.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.PQC_SIGNATURE, byte[].class);
+ assertNotNull(pqcSig);
+
+ // Check verification passed
+ assertTrue(resultVerify.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_VERIFY, Boolean.class));
+ }
+}
diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridSignatureEd25519MLDSATest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridSignatureEd25519MLDSATest.java
new file mode 100644
index 000000000000..32215b9fff01
--- /dev/null
+++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/PQCHybridSignatureEd25519MLDSATest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc;
+
+import java.security.Security;
+
+import org.apache.camel.EndpointInject;
+import org.apache.camel.Produce;
+import org.apache.camel.ProducerTemplate;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.apache.camel.test.junit5.CamelTestSupport;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Test for hybrid signature using Ed25519 + ML-DSA.
+ */
+public class PQCHybridSignatureEd25519MLDSATest extends CamelTestSupport {
+
+ @EndpointInject("mock:signed")
+ protected MockEndpoint resultSign;
+
+ @EndpointInject("mock:verified")
+ protected MockEndpoint resultVerify;
+
+ @Produce("direct:sign")
+ protected ProducerTemplate templateSign;
+
+ @BeforeAll
+ public static void startup() {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ @Override
+ protected RouteBuilder createRouteBuilder() {
+ return new RouteBuilder() {
+ @Override
+ public void configure() {
+ from("direct:sign")
+ .to("pqc:hybridsign?operation=hybridSign"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ED25519")
+ .to("mock:signed")
+ .to("pqc:hybridverify?operation=hybridVerify"
+ + "&signatureAlgorithm=MLDSA"
+ + "&classicalSignatureAlgorithm=ED25519")
+ .to("mock:verified");
+ }
+ };
+ }
+
+ @Test
+ void testHybridSignAndVerifyWithEd25519() throws Exception {
+ resultSign.expectedMessageCount(1);
+ resultVerify.expectedMessageCount(1);
+
+ templateSign.sendBody("Hello, Ed25519 + ML-DSA hybrid!");
+
+ resultSign.assertIsSatisfied();
+ resultVerify.assertIsSatisfied();
+
+ // Check that hybrid signature was created
+ byte[] hybridSig = resultSign.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_SIGNATURE, byte[].class);
+ assertNotNull(hybridSig);
+ assertTrue(hybridSig.length > 0);
+
+ // Check verification passed
+ assertTrue(resultVerify.getExchanges().get(0).getMessage()
+ .getHeader(PQCConstants.HYBRID_VERIFY, Boolean.class));
+ }
+}
diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/crypto/hybrid/HybridKEMTest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/crypto/hybrid/HybridKEMTest.java
new file mode 100644
index 000000000000..f895a35dbfdd
--- /dev/null
+++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/crypto/hybrid/HybridKEMTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.*;
+import java.security.spec.ECGenParameterSpec;
+
+import javax.crypto.KeyAgreement;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+
+import org.bouncycastle.jcajce.spec.MLKEMParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HybridKEMTest {
+
+ @BeforeAll
+ static void setup() {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ @Test
+ void testEncapsulateAndExtractWithX25519AndMLKEM() throws Exception {
+ // Generate X25519 key pair (recipient)
+ KeyPairGenerator x25519Kpg = KeyPairGenerator.getInstance("X25519", "BC");
+ KeyPair x25519KeyPair = x25519Kpg.generateKeyPair();
+ KeyAgreement x25519KA = KeyAgreement.getInstance("X25519", "BC");
+
+ // Generate ML-KEM key pair (recipient)
+ KeyPairGenerator mlkemKpg = KeyPairGenerator.getInstance("ML-KEM", "BC");
+ mlkemKpg.initialize(MLKEMParameterSpec.ml_kem_768, new SecureRandom());
+ KeyPair mlkemKeyPair = mlkemKpg.generateKeyPair();
+ KeyGenerator mlkemKg = KeyGenerator.getInstance("ML-KEM", "BC");
+
+ // Sender: Create encapsulation
+ KeyAgreement senderKA = KeyAgreement.getInstance("X25519", "BC");
+ KeyGenerator senderKg = KeyGenerator.getInstance("ML-KEM", "BC");
+
+ HybridKEM.HybridEncapsulationResult encapResult = HybridKEM.encapsulate(
+ x25519KeyPair.getPublic(),
+ mlkemKeyPair.getPublic(),
+ senderKA,
+ senderKg,
+ "AES",
+ 256,
+ "HKDF-SHA256");
+
+ assertNotNull(encapResult);
+ assertNotNull(encapResult.encapsulation());
+ assertNotNull(encapResult.sharedSecret());
+ assertTrue(encapResult.encapsulation().length > 0);
+
+ // Recipient: Extract shared secret
+ SecretKey extractedSecret = HybridKEM.extract(
+ encapResult.encapsulation(),
+ x25519KeyPair.getPrivate(),
+ mlkemKeyPair.getPrivate(),
+ x25519KA,
+ mlkemKg,
+ "AES",
+ 256,
+ "HKDF-SHA256");
+
+ assertNotNull(extractedSecret);
+ // The extracted secret should match the encapsulated secret
+ assertArrayEquals(encapResult.sharedSecret().getEncoded(), extractedSecret.getEncoded());
+ }
+
+ @Test
+ void testEncapsulateAndExtractWithECDHAndMLKEM() throws Exception {
+ // Generate ECDH P-256 key pair (recipient)
+ KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
+ ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ KeyPair ecKeyPair = ecKpg.generateKeyPair();
+ KeyAgreement ecdhKA = KeyAgreement.getInstance("ECDH", "BC");
+
+ // Generate ML-KEM key pair (recipient)
+ KeyPairGenerator mlkemKpg = KeyPairGenerator.getInstance("ML-KEM", "BC");
+ mlkemKpg.initialize(MLKEMParameterSpec.ml_kem_768, new SecureRandom());
+ KeyPair mlkemKeyPair = mlkemKpg.generateKeyPair();
+ KeyGenerator mlkemKg = KeyGenerator.getInstance("ML-KEM", "BC");
+
+ // Sender: Create encapsulation
+ KeyAgreement senderKA = KeyAgreement.getInstance("ECDH", "BC");
+ KeyGenerator senderKg = KeyGenerator.getInstance("ML-KEM", "BC");
+
+ HybridKEM.HybridEncapsulationResult encapResult = HybridKEM.encapsulate(
+ ecKeyPair.getPublic(),
+ mlkemKeyPair.getPublic(),
+ senderKA,
+ senderKg,
+ "AES",
+ 128,
+ "HKDF-SHA256");
+
+ assertNotNull(encapResult);
+ assertNotNull(encapResult.encapsulation());
+ assertNotNull(encapResult.sharedSecret());
+
+ // Recipient: Extract shared secret
+ SecretKey extractedSecret = HybridKEM.extract(
+ encapResult.encapsulation(),
+ ecKeyPair.getPrivate(),
+ mlkemKeyPair.getPrivate(),
+ ecdhKA,
+ mlkemKg,
+ "AES",
+ 128,
+ "HKDF-SHA256");
+
+ assertNotNull(extractedSecret);
+ assertArrayEquals(encapResult.sharedSecret().getEncoded(), extractedSecret.getEncoded());
+ }
+
+ @Test
+ void testParseHybridEncapsulation() {
+ byte[] classicalEncap = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 };
+ byte[] pqcEncap = new byte[] { 10, 20, 30, 40, 50, 60, 70, 80, 90 };
+
+ byte[] combined = HybridKEM.combineEncapsulations(classicalEncap, pqcEncap);
+
+ HybridKEM.HybridEncapsulationComponents components = HybridKEM.parse(combined);
+
+ assertArrayEquals(classicalEncap, components.classicalEncapsulation());
+ assertArrayEquals(pqcEncap, components.pqcEncapsulation());
+ }
+
+ @Test
+ void testInvalidEncapsulationFormat() {
+ byte[] invalidEncap = new byte[] { 0, 0, 0, 0 }; // Length 0 for classical encap
+
+ assertThrows(IllegalArgumentException.class, () -> HybridKEM.parse(invalidEncap));
+ }
+
+ @Test
+ void testDifferentKDFAlgorithms() throws Exception {
+ // Generate key pairs
+ KeyPairGenerator x25519Kpg = KeyPairGenerator.getInstance("X25519", "BC");
+ KeyPair x25519KeyPair = x25519Kpg.generateKeyPair();
+
+ KeyPairGenerator mlkemKpg = KeyPairGenerator.getInstance("ML-KEM", "BC");
+ mlkemKpg.initialize(MLKEMParameterSpec.ml_kem_512, new SecureRandom());
+ KeyPair mlkemKeyPair = mlkemKpg.generateKeyPair();
+
+ String[] kdfAlgorithms = { "HKDF-SHA256", "HKDF-SHA384", "HKDF-SHA512" };
+
+ for (String kdf : kdfAlgorithms) {
+ KeyAgreement senderKA = KeyAgreement.getInstance("X25519", "BC");
+ KeyGenerator senderKg = KeyGenerator.getInstance("ML-KEM", "BC");
+
+ HybridKEM.HybridEncapsulationResult result = HybridKEM.encapsulate(
+ x25519KeyPair.getPublic(),
+ mlkemKeyPair.getPublic(),
+ senderKA,
+ senderKg,
+ "AES",
+ 256,
+ kdf);
+
+ assertNotNull(result.sharedSecret());
+ assertEquals("AES", result.sharedSecret().getAlgorithm());
+ assertEquals(32, result.sharedSecret().getEncoded().length); // 256 bits = 32 bytes
+ }
+ }
+}
diff --git a/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/crypto/hybrid/HybridSignatureTest.java b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/crypto/hybrid/HybridSignatureTest.java
new file mode 100644
index 000000000000..ce5914f253fc
--- /dev/null
+++ b/components/camel-pqc/src/test/java/org/apache/camel/component/pqc/crypto/hybrid/HybridSignatureTest.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.pqc.crypto.hybrid;
+
+import java.security.*;
+import java.security.spec.ECGenParameterSpec;
+
+import org.bouncycastle.jcajce.spec.MLDSAParameterSpec;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.pqc.jcajce.provider.BouncyCastlePQCProvider;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class HybridSignatureTest {
+
+ @BeforeAll
+ static void setup() {
+ if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastleProvider());
+ }
+ if (Security.getProvider(BouncyCastlePQCProvider.PROVIDER_NAME) == null) {
+ Security.addProvider(new BouncyCastlePQCProvider());
+ }
+ }
+
+ @Test
+ void testSignAndVerifyWithECDSAAndMLDSA() throws Exception {
+ // Generate ECDSA key pair
+ KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
+ ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ KeyPair ecKeyPair = ecKpg.generateKeyPair();
+ Signature ecSigner = Signature.getInstance("SHA256withECDSA", "BC");
+
+ // Generate ML-DSA key pair
+ KeyPairGenerator mldsaKpg = KeyPairGenerator.getInstance("ML-DSA", "BC");
+ mldsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65, new SecureRandom());
+ KeyPair mldsaKeyPair = mldsaKpg.generateKeyPair();
+ Signature mldsaSigner = Signature.getInstance("ML-DSA", "BC");
+
+ byte[] data = "Hello, hybrid cryptography!".getBytes();
+
+ // Sign
+ byte[] hybridSig = HybridSignature.sign(
+ data,
+ ecKeyPair.getPrivate(), ecSigner,
+ mldsaKeyPair.getPrivate(), mldsaSigner);
+
+ assertNotNull(hybridSig);
+ assertTrue(hybridSig.length > 0);
+
+ // Verify with same keys
+ Signature ecVerifier = Signature.getInstance("SHA256withECDSA", "BC");
+ Signature mldsaVerifier = Signature.getInstance("ML-DSA", "BC");
+
+ boolean valid = HybridSignature.verify(
+ data,
+ hybridSig,
+ ecKeyPair.getPublic(), ecVerifier,
+ mldsaKeyPair.getPublic(), mldsaVerifier);
+
+ assertTrue(valid);
+ }
+
+ @Test
+ void testVerifyFailsWithWrongData() throws Exception {
+ // Generate key pairs
+ KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
+ ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ KeyPair ecKeyPair = ecKpg.generateKeyPair();
+ Signature ecSigner = Signature.getInstance("SHA256withECDSA", "BC");
+
+ KeyPairGenerator mldsaKpg = KeyPairGenerator.getInstance("ML-DSA", "BC");
+ mldsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65, new SecureRandom());
+ KeyPair mldsaKeyPair = mldsaKpg.generateKeyPair();
+ Signature mldsaSigner = Signature.getInstance("ML-DSA", "BC");
+
+ byte[] data = "Original data".getBytes();
+ byte[] tamperedData = "Tampered data".getBytes();
+
+ // Sign original data
+ byte[] hybridSig = HybridSignature.sign(
+ data,
+ ecKeyPair.getPrivate(), ecSigner,
+ mldsaKeyPair.getPrivate(), mldsaSigner);
+
+ // Verify with tampered data
+ Signature ecVerifier = Signature.getInstance("SHA256withECDSA", "BC");
+ Signature mldsaVerifier = Signature.getInstance("ML-DSA", "BC");
+
+ boolean valid = HybridSignature.verify(
+ tamperedData,
+ hybridSig,
+ ecKeyPair.getPublic(), ecVerifier,
+ mldsaKeyPair.getPublic(), mldsaVerifier);
+
+ assertFalse(valid);
+ }
+
+ @Test
+ void testParseHybridSignature() throws Exception {
+ // Create a simple hybrid signature manually
+ byte[] classicalSig = new byte[] { 1, 2, 3, 4, 5 };
+ byte[] pqcSig = new byte[] { 10, 20, 30, 40, 50, 60 };
+
+ byte[] combined = HybridSignature.combineSignatures(classicalSig, pqcSig);
+
+ HybridSignature.HybridSignatureComponents components = HybridSignature.parse(combined);
+
+ assertArrayEquals(classicalSig, components.classicalSignature());
+ assertArrayEquals(pqcSig, components.pqcSignature());
+ }
+
+ @Test
+ void testDetailedVerification() throws Exception {
+ // Generate key pairs
+ KeyPairGenerator ecKpg = KeyPairGenerator.getInstance("EC", "BC");
+ ecKpg.initialize(new ECGenParameterSpec("secp256r1"), new SecureRandom());
+ KeyPair ecKeyPair = ecKpg.generateKeyPair();
+ Signature ecSigner = Signature.getInstance("SHA256withECDSA", "BC");
+
+ KeyPairGenerator mldsaKpg = KeyPairGenerator.getInstance("ML-DSA", "BC");
+ mldsaKpg.initialize(MLDSAParameterSpec.ml_dsa_65, new SecureRandom());
+ KeyPair mldsaKeyPair = mldsaKpg.generateKeyPair();
+ Signature mldsaSigner = Signature.getInstance("ML-DSA", "BC");
+
+ byte[] data = "Test data".getBytes();
+
+ // Sign
+ byte[] hybridSig = HybridSignature.sign(
+ data,
+ ecKeyPair.getPrivate(), ecSigner,
+ mldsaKeyPair.getPrivate(), mldsaSigner);
+
+ // Verify with detailed results
+ Signature ecVerifier = Signature.getInstance("SHA256withECDSA", "BC");
+ Signature mldsaVerifier = Signature.getInstance("ML-DSA", "BC");
+
+ HybridSignature.HybridVerificationResult result = HybridSignature.verifyDetailed(
+ data,
+ hybridSig,
+ ecKeyPair.getPublic(), ecVerifier,
+ mldsaKeyPair.getPublic(), mldsaVerifier);
+
+ assertTrue(result.classicalValid());
+ assertTrue(result.pqcValid());
+ assertTrue(result.isValid());
+ }
+
+ @Test
+ void testInvalidSignatureFormat() {
+ byte[] invalidSig = new byte[] { 0, 0, 0, 0 }; // Length 0 for classical sig
+
+ assertThrows(IllegalArgumentException.class, () -> HybridSignature.parse(invalidSig));
+ }
+}