PQC Algorithms
Since Camel 4.12
Only producer is supported
The PQC component supports signing and verifying payload using Post Quantum Cryptography algorithms, as well as key lifecycle management for Post-Quantum cryptographic keys.
Features
-
Digital Signatures - Sign and verify data using NIST-standardized and experimental PQC signature algorithms
-
Key Encapsulation - Generate and extract shared secrets using Key Encapsulation Mechanisms (KEM)
-
Key Lifecycle Management - Generate, rotate, expire, revoke, and manage PQC keys
-
Multiple Implementations - File-based and in-memory key storage options
-
Key Export/Import - Convert keys between PEM, DER, PKCS8, and X.509 formats
Prerequisites
URI Format
pqc://label[?options]
You can append query options to the URI in the following format:
?options=value&option2=value&…
Configuring Options
Camel components are configured on two separate levels:
-
component level
-
endpoint level
Configuring Component Options
At the component level, you set general and shared configurations that are, then, inherited by the endpoints. It is the highest configuration level.
For example, a component may have security settings, credentials for authentication, urls for network connection and so forth.
Some components only have a few options, and others may have many. Because components typically have pre-configured defaults that are commonly used, then you may often only need to configure a few options on a component; or none at all.
You can configure components using:
-
the Component DSL.
-
in a configuration file (
application.properties,*.yamlfiles, etc). -
directly in the Java code.
Configuring Endpoint Options
You usually spend more time setting up endpoints because they have many options. These options help you customize what you want the endpoint to do. The options are also categorized into whether the endpoint is used as a consumer (from), as a producer (to), or both.
Configuring endpoints is most often done directly in the endpoint URI as path and query parameters. You can also use the Endpoint DSL and DataFormat DSL as a type safe way of configuring endpoints and data formats in Java.
A good practice when configuring options is to use Property Placeholders.
Property placeholders provide a few benefits:
-
They help prevent using hardcoded urls, port numbers, sensitive information, and other settings.
-
They allow externalizing the configuration from the code.
-
They help the code to become more flexible and reusable.
The following two sections list all the options, firstly for the component followed by the endpoint.
Component Options
The PQC Algorithms component supports 26 options, which are listed below.
| Name | Description | Default | Type |
|---|---|---|---|
Component configuration. | PQCConfiguration | ||
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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
Required The operation to perform. Enum values:
| PQCOperations | ||
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 type, which then gets configured on the component. This can be used for automatic configuring JDBC data sources, JMS connection factories, AWS Clients, etc. | true | boolean | |
The classical key agreement algorithm to use in hybrid KEM operations. Enum values:
| String | ||
Autowired The classical KeyAgreement instance to be used in hybrid KEM operations. | KeyAgreement | ||
Autowired The classical KeyPair to be used in hybrid operations. | KeyPair | ||
The classical signature algorithm to use in hybrid operations. Enum values:
| String | ||
Autowired The classical Signature instance to be used in hybrid signature operations. | Signature | ||
The KDF algorithm to use for combining secrets in hybrid KEM operations. Enum values:
| HKDF-SHA256 | String | |
In case there is no keyGenerator, we specify an algorithm to build the KeyGenerator. Enum values:
| String | ||
Autowired The Key Generator to be used in encapsulation and extraction. | KeyGenerator | ||
Autowired The KeyLifecycleManager to use for key lifecycle operations such as generation, rotation, import/export, expiration, and revocation. | KeyLifecycleManager | ||
Autowired The KeyPair to be used. | KeyPair | ||
A KeyPair alias to use in combination with KeyStore parameter. | String | ||
Autowired A KeyStore where we could get Cryptographic material. | KeyStore | ||
The KeyStore password to use in combination with KeyStore Parameter. | String | ||
In case there is no signer, we specify an algorithm to build the KeyPair or the Signer. Enum values:
| String | ||
Autowired The Signer to be used. | Signature | ||
The warning threshold for stateful key exhaustion as a fraction of total signatures (0.0 to 1.0). When the remaining signatures for a stateful key (XMSS, XMSSMT, LMS/HSS) drop below this fraction of the total capacity, a WARN log is emitted. When remaining signatures reach zero, an exception is thrown to prevent key reuse. Set to 0 to disable warnings. | 0.1 | double | |
In the context of extractSecretKeyFromEncapsulation operation, this option define if we want to have the key set as header. | false | boolean | |
Whether to enforce key status checks before cryptographic operations. When enabled, REVOKED keys are rejected for all operations, EXPIRED keys are rejected for signing/encapsulation but allowed for verification/extraction, and DEPRECATED keys produce a warning but still function. Requires a KeyLifecycleManager and a CamelPQCKeyId header to be set. | true | boolean | |
In case we are using KEM operations, we need a Symmetric algorithm to be defined for the flow to work. Enum values:
| String | ||
The required length of the symmetric key used. | 128 | int | |
Used for enabling or disabling all consumer based health checks from this component. | true | boolean | |
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 producer checks globally by setting camel.health.producersEnabled=true. | true | boolean |
Endpoint Options
The PQC Algorithms endpoint is configured using URI syntax:
pqc:label
With the following path and query parameters:
Query Parameters (22 parameters)
| Name | Description | Default | Type |
|---|---|---|---|
Required The operation to perform. Enum values:
| PQCOperations | ||
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 during starting and cause the route to fail being started. By deferring this startup to be lazy then the startup failure can be handled during routing messages via Camel’s routing error handlers. Beware that when the first message is processed then creating and starting the producer may take a little time and prolong the total processing time of the processing. | false | boolean | |
The classical key agreement algorithm to use in hybrid KEM operations. Enum values:
| String | ||
Autowired The classical KeyAgreement instance to be used in hybrid KEM operations. | KeyAgreement | ||
Autowired The classical KeyPair to be used in hybrid operations. | KeyPair | ||
The classical signature algorithm to use in hybrid operations. Enum values:
| String | ||
Autowired The classical Signature instance to be used in hybrid signature operations. | Signature | ||
The KDF algorithm to use for combining secrets in hybrid KEM operations. Enum values:
| HKDF-SHA256 | String | |
In case there is no keyGenerator, we specify an algorithm to build the KeyGenerator. Enum values:
| String | ||
Autowired The Key Generator to be used in encapsulation and extraction. | KeyGenerator | ||
Autowired The KeyLifecycleManager to use for key lifecycle operations such as generation, rotation, import/export, expiration, and revocation. | KeyLifecycleManager | ||
Autowired The KeyPair to be used. | KeyPair | ||
A KeyPair alias to use in combination with KeyStore parameter. | String | ||
Autowired A KeyStore where we could get Cryptographic material. | KeyStore | ||
The KeyStore password to use in combination with KeyStore Parameter. | String | ||
In case there is no signer, we specify an algorithm to build the KeyPair or the Signer. Enum values:
| String | ||
Autowired The Signer to be used. | Signature | ||
The warning threshold for stateful key exhaustion as a fraction of total signatures (0.0 to 1.0). When the remaining signatures for a stateful key (XMSS, XMSSMT, LMS/HSS) drop below this fraction of the total capacity, a WARN log is emitted. When remaining signatures reach zero, an exception is thrown to prevent key reuse. Set to 0 to disable warnings. | 0.1 | double | |
In the context of extractSecretKeyFromEncapsulation operation, this option define if we want to have the key set as header. | false | boolean | |
Whether to enforce key status checks before cryptographic operations. When enabled, REVOKED keys are rejected for all operations, EXPIRED keys are rejected for signing/encapsulation but allowed for verification/extraction, and DEPRECATED keys produce a warning but still function. Requires a KeyLifecycleManager and a CamelPQCKeyId header to be set. | true | boolean | |
In case we are using KEM operations, we need a Symmetric algorithm to be defined for the flow to work. Enum values:
| String | ||
The required length of the symmetric key used. | 128 | int |
Message Headers
The PQC Algorithms component supports 23 message header(s), which is/are listed below:
| Name | Description | Default | Type |
|---|---|---|---|
| Constant: | The operation we want to perform. | String | |
| Constant: | The signature of a body. | String | |
CamelPQCVerification (producer) Constant: | The result of verification of a Body signature. | Boolean | |
| Constant: | The extracted key in case of extractSecretKeyFromEncapsulation operation and storeExtractedSecretKeyAsHeader option enabled. | Boolean | |
CamelPQCRemainingSignatures (producer) Constant: | The remaining signatures for a stateful key. | Long | |
| Constant: | The key state for a stateful key. | StatefulKeyState | |
| Constant: | The key ID for stateful key operations. | String | |
| Constant: | The generated key pair. | KeyPair | |
| Constant: | The key format for import/export operations. | String | |
CamelPQCExportedKey (producer) Constant: | The exported key data. | byte[] | |
CamelPQCKeyMetadata (producer) Constant: | The key metadata. | KeyMetadata | |
| Constant: | List of key metadata. | List | |
| Constant: | The algorithm for key generation. | String | |
CamelPQCIncludePrivate (producer) Constant: | Include private key in export. | Boolean | |
CamelPQCRevocationReason (producer) Constant: | Revocation reason. | String | |
CamelPQCHybridSignature (producer) Constant: | The hybrid signature combining both classical and PQC signatures. | byte[] | |
CamelPQCClassicalSignature (producer) Constant: | The classical signature component of a hybrid signature. | byte[] | |
CamelPQCPqcSignature (producer) Constant: | The PQC signature component of a hybrid signature. | byte[] | |
CamelPQCClassicalEncapsulation (producer) Constant: | The classical encapsulation component of a hybrid KEM. | byte[] | |
CamelPQCPqcEncapsulation (producer) Constant: | The PQC encapsulation component of a hybrid KEM. | byte[] | |
CamelPQCHybridSecretKey (producer) Constant: | The combined secret key from hybrid KEM operation. | SecretKey | |
CamelPQCHybridEncapsulation (producer) Constant: | The hybrid encapsulation combining both classical and PQC encapsulations. | byte[] | |
CamelPQCHybridVerification (producer) Constant: | The verification result of hybrid signature (both must pass). | Boolean |
Supported Algorithms
The component supports the following algorithms for signature and verification.
Standardized and implemented
-
ML-DSA
-
SLH-DSA
-
LMS
-
HSS (Hierarchical Signature System)
-
XMSS
-
XMSSMT (XMSS Multi-Tree)
Experimental and non-standardized
-
Dilithium
-
Falcon
-
Picnic
-
SNOVA
-
MAYO
-
SPHINCS+
Supported Operations
The component supports the following operations:
Signature Operations:
-
sign - Sign data using a PQC signature algorithm
-
verify - Verify a signature
Key Encapsulation Operations:
-
generateSecretKeyEncapsulation - Generate a secret key and encapsulate it
-
extractSecretKeyEncapsulation - Extract the encapsulation
-
extractSecretKeyFromEncapsulation - Extract the secret key from encapsulation
Hybrid Operations (classical + post-quantum):
-
hybridSign - Create a hybrid signature combining a classical and a PQC signature
-
hybridVerify - Verify a hybrid signature (both components must be valid)
-
hybridGenerateSecretKeyEncapsulation - Generate a hybrid encapsulation and shared secret
-
hybridExtractSecretKeyEncapsulation - Extract the shared secret from a hybrid encapsulation
-
hybridExtractSecretKeyFromEncapsulation - Extract the secret key from a hybrid encapsulation
See PQC Hybrid Cryptography for configuration details and examples.
Key Lifecycle Operations:
-
generateKeyPair - Generate a new PQC key pair
-
exportKey - Export a key to PEM, DER, PKCS8, or X.509 format
-
importKey - Import a key from bytes
-
rotateKey - Rotate a key and deprecate the old one
-
getKeyMetadata - Get metadata for a key
-
listKeys - List all keys with metadata
-
expireKey - Mark a key as expired
-
revokeKey - Revoke a compromised key
See PQC Key Lifecycle Management for full details.
Sub-Pages
The PQC component documentation is split into focused sub-pages:
-
Key Lifecycle Management - Key generation, storage, rotation, expiration, revocation, and format conversion with FileBasedKeyLifecycleManager, InMemoryKeyLifecycleManager, HashiCorp Vault, and AWS Secrets Manager implementations
-
Hybrid Cryptography - Combining classical and post-quantum algorithms for defense-in-depth, including wire format v2
-
PQC DataFormat - DataFormat for quantum-resistant encryption/decryption using KEM
Signature and Verification
The component expects to find a KeyPair and a Signature Objects in to the Camel Registry.
In case the KeyPair and the Signature Objects are not in the registry, it will provide two instances of the Objects with default implementation.
This will be true for standardized algorithms and for experimental ones.
| To combine a classical signature (ECDSA, Ed25519, RSA) with a PQC signature for defense-in-depth during the post-quantum transition, use the hybrid signature operations described in Hybrid Cryptography. |
Examples
All signature algorithms follow the same route pattern. Below is a complete example using ML-DSA, followed by a reference table for the other algorithms.
ML-DSA (complete example)
-
Java
-
XML
-
YAML
from("direct:sign").to("pqc:sign?operation=sign").to("mock:sign").to("pqc:verify?operation=verify")
.to("mock:verify"); <route>
<from uri="direct:sign"/>
<to uri="pqc:sign?operation=sign"/>
<to uri="mock:sign"/>
<to uri="pqc:verify?operation=verify"/>
<to uri="mock:verify"/>
</route> - route:
from:
uri: direct:sign
steps:
- to:
uri: pqc:sign
parameters:
operation: sign
- to:
uri: mock:sign
- to:
uri: pqc:verify
parameters:
operation: verify
- to:
uri: mock:verify With the following beans registered in the Registry
@BindToRegistry("Keypair")
public KeyPair setKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ML-DSA", "BC");
kpGen.initialize(MLDSAParameterSpec.ml_dsa_65);
KeyPair kp = kpGen.generateKeyPair();
return kp;
}
@BindToRegistry("Signer")
public Signature getSigner() throws NoSuchAlgorithmException {
Signature mlDsa = Signature.getInstance("ML-DSA");
return mlDsa;
} This could be done even without the Registry beans, by specifying the signatureAlgorithm parameter in the following way
-
Java
-
XML
-
YAML
from("direct:sign").to("pqc:sign?operation=sign&signatureAlgorithm=MLDSA").to("mock:sign")
.to("pqc:verify?operation=verify&signatureAlgorithm=MLDSA")
.to("mock:verify"); <route>
<from uri="direct:sign"/>
<to uri="pqc:sign?operation=sign&signatureAlgorithm=MLDSA"/>
<to uri="mock:sign"/>
<to uri="pqc:verify?operation=verify&signatureAlgorithm=MLDSA"/>
<to uri="mock:verify"/>
</route> - route:
from:
uri: direct:sign
steps:
- to:
uri: pqc:sign
parameters:
operation: sign
signatureAlgorithm: MLDSA
- to:
uri: mock:sign
- to:
uri: pqc:verify
parameters:
operation: verify
signatureAlgorithm: MLDSA
- to:
uri: mock:verify With this approach the component will use the class org.apache.camel.component.pqc.crypto.PQCDefaultMLDSAMaterial, which will create the Signature and KeyPair objects to be used.
The Spec used for the KeyPair will be, in this case, ML-DSA-65.
Other Signature Algorithms
All other signature algorithms follow the exact same route pattern shown above for ML-DSA. The only differences are the algorithm name, the bean registration parameters, and the default material class. Use the following reference table:
| Algorithm | signatureAlgorithm param | JCA Algorithm Name | Provider | Default Parameter Spec | Material Class |
|---|---|---|---|---|---|
SLH-DSA |
| SLH-DSA | BC | SLH-DSA-SHA2-128s |
|
LMS |
| LMS | BC | LMS-SHA256-N32-H5 / SHA256-N32-W1 (OTS) |
|
XMSS |
| XMSS | BCPQC | Tree height 10, SHA-256 |
|
XMSSMT |
| XMSSMT | BCPQC | XMSSMT-SHA2-20d2-256 |
|
HSS |
| HSS | BC | LMS-SHA256-N32-H5 |
|
Dilithium |
| Dilithium | BCPQC | dilithium2 |
|
Falcon |
| Falcon | BCPQC | falcon_512 |
|
SPHINCS+ |
| SPHINCS+ | BCPQC | sha2_128s |
|
Picnic |
| Picnic | BCPQC | picnicl1fs |
|
To use any algorithm, set signatureAlgorithm in the URI (e.g., signatureAlgorithm=SLHDSA). Alternatively, register a KeyPair and Signature in the registry using the JCA Algorithm Name and Provider from the table above.
Key Encapsulation and Extraction
In Post Quantum Cryptography it has been introduced the concept of Key Encapsulation Algorithm.
In this context there are three entities to consider:
-
A key generation algorithm which generates a public key and a private key (a keypair).
-
An encapsulation algorithm which takes as input a public key, and outputs a shared secret value and an "encapsulation" (a ciphertext) of this secret value.
-
A decapsulation algorithm which takes as input the encapsulation and the private key, and outputs the shared secret value.
In the component we are supporting the three phases in generateSecretKeyEncapsulation, extractSecretKeyEncapsulation and extractSecretKeyFromEncapsulation
The KEM Algorithm supported are the following:
Standardized and implemented
-
ML-KEM
Experimental and non-standardized
-
BIKE
-
CMCE
-
HQC
-
FRODO
-
SABER
-
NTRU
-
NTRULPRime
-
SNTRUPrime
-
Kyber
The component expects to find a KeyGenerator and a KeyPair in to the Camel Registry.
In case the KeyPair and the KeyGenerator Objects are not in the registry, it will provide two instances of the Objects with default implementation.
This will be true for standardized algorithms and for experimental ones.
| To combine a classical key agreement (X25519, ECDH) with a PQC KEM (ML-KEM) for defense-in-depth, use the hybrid KEM operations described in Hybrid Cryptography. |
A possible flow of the operation could be the following:
ML-KEM Example
-
Java
-
XML
-
YAML
from("direct:encapsulate").to("pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES")
.to("mock:encapsulate")
.to("pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES").to("mock:extract"); <route>
<from uri="direct:encapsulate"/>
<to uri="pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES"/>
<to uri="mock:encapsulate"/>
<to uri="pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES"/>
<to uri="mock:extract"/>
</route> - route:
from:
uri: direct:encapsulate
steps:
- to:
uri: pqc:keyenc
parameters:
operation: generateSecretKeyEncapsulation
symmetricKeyAlgorithm: AES
- to:
uri: mock:encapsulate
- to:
uri: pqc:keyenc
parameters:
operation: extractSecretKeyEncapsulation
symmetricKeyAlgorithm: AES
- to:
uri: mock:extract With the following beans registered in the Registry
@BindToRegistry("Keypair")
public KeyPair setKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(),
PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider());
kpg.initialize(MLKEMParameterSpec.ml_kem_512, new SecureRandom());
KeyPair kp = kpg.generateKeyPair();
return kp;
}
@BindToRegistry("KeyGenerator")
public KeyGenerator setKeyGenerator()
throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
KeyGenerator kg = KeyGenerator.getInstance(PQCKeyEncapsulationAlgorithms.MLKEM.getAlgorithm(),
PQCKeyEncapsulationAlgorithms.MLKEM.getBcProvider());
return kg;
} This could be done even without the Registry beans, by specifying the symmetricKeyAlgorithm and keyEncapsulationAlgorithm parameters in the following way
-
Java
-
XML
-
YAML
from("direct:encapsulate").to(
"pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES&keyEncapsulationAlgorithm=MLKEM")
.to("mock:encapsulate")
.to("pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES&keyEncapsulationAlgorithm=MLKEM")
.to("mock:extract"); <route>
<from uri="direct:encapsulate"/>
<to uri="pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES&keyEncapsulationAlgorithm=MLKEM"/>
<to uri="mock:encapsulate"/>
<to uri="pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES&keyEncapsulationAlgorithm=MLKEM"/>
<to uri="mock:extract"/>
</route> - route:
from:
uri: direct:encapsulate
steps:
- to:
uri: pqc:keyenc
parameters:
operation: generateSecretKeyEncapsulation
symmetricKeyAlgorithm: AES
keyEncapsulationAlgorithm: MLKEM
- to:
uri: mock:encapsulate
- to:
uri: pqc:keyenc
parameters:
operation: extractSecretKeyEncapsulation
symmetricKeyAlgorithm: AES
keyEncapsulationAlgorithm: MLKEM
- to:
uri: mock:extract With this approach the component will use the class org.apache.camel.component.pqc.crypto.kem.PQCDefaultMLKEMMaterial, which will create the KeyGenerator and KeyPair objects to be used.
The Spec used for the KeyPair will be, in this case, ML-KEM-512.
Extract Secret Key from Encapsulation for downstream usage
Once you have the encapsulation you’re able to decapsulate the secret key by using private key.
All of this could be done to use the secret key coming from the encapsulation in the downstream route.
As example you could use the secret key to dynamically instruct the CryptoDataFormat to use it, like in the following route.
CryptoDataFormat cryptoFormat = new CryptoDataFormat("AES", null);
from("direct:encapsulate")
.to("pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES")
.to("mock:encapsulate")
.to("pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES")
.to("pqc:keyenc?operation=extractSecretKeyFromEncapsulation&symmetricKeyAlgorithm=AES")
.setHeader(CryptoDataFormat.KEY, body())
.setBody(constant("Hello"))
.marshal(cryptoFormat)
.log("Encrypted ${body}")
.to("mock:encrypted")
.unmarshal(cryptoFormat)
.log("Unencrypted ${body}")
.to("mock:unencrypted"); This could be used to generate a secret key, protect it through Encapsulation and KEM approach and re-use it once extracted.
| For a simplified approach to KEM-based encryption, consider using the PQC DataFormat which handles all KEM operations internally with a single marshal/unmarshal call. |