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, *.yaml files, 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 17 options, which are listed below.

Name Description Default Type

configuration (producer)

Component configuration.

PQCConfiguration

lazyStartProducer (producer)

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

operation (producer)

Required The operation to perform.

Enum values:

  • sign

  • verify

  • generateSecretKeyEncapsulation

  • extractSecretKeyEncapsulation

  • extractSecretKeyFromEncapsulation

  • getRemainingSignatures

  • getKeyState

  • deleteKeyState

  • generateKeyPair

  • exportKey

  • importKey

  • rotateKey

  • getKeyMetadata

  • listKeys

  • expireKey

  • revokeKey

PQCOperations

autowiredEnabled (advanced)

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

keyEncapsulationAlgorithm (advanced)

In case there is no keyGenerator, we specify an algorithm to build the KeyGenerator.

Enum values:

  • MLKEM

  • BIKE

  • HQC

  • CMCE

  • SABER

  • FRODO

  • NTRU

  • NTRULPRime

  • SNTRUPrime

  • KYBER

String

keyGenerator (advanced)

Autowired The Key Generator to be used in encapsulation and extraction.

KeyGenerator

keyPair (advanced)

Autowired The KeyPair to be used.

KeyPair

keyPairAlias (advanced)

A KeyPair alias to use in combination with KeyStore parameter.

String

keyStore (advanced)

Autowired A KeyStore where we could get Cryptographic material.

KeyStore

keyStorePassword (advanced)

The KeyStore password to use in combination with KeyStore Parameter.

String

signatureAlgorithm (advanced)

In case there is no signer, we specify an algorithm to build the KeyPair or the Signer.

Enum values:

  • MLDSA

  • SLHDSA

  • LMS

  • HSS

  • XMSS

  • XMSSMT

  • DILITHIUM

  • FALCON

  • PICNIC

  • SNOVA

  • MAYO

  • SPHINCSPLUS

String

signer (advanced)

Autowired The Signer to be used.

Signature

storeExtractedSecretKeyAsHeader (advanced)

In the context of extractSecretKeyFromEncapsulation operation, this option define if we want to have the key set as header.

false

boolean

symmetricKeyAlgorithm (advanced)

In case we are using KEM operations, we need a Symmetric algorithm to be defined for the flow to work.

Enum values:

  • AES

  • ARIA

  • RC2

  • RC5

  • CAMELLIA

  • CAST5

  • CAST6

  • CHACHA7539

  • DSTU7624

  • GOST28147

  • GOST3412_2015

  • GRAIN128

  • HC128

  • HC256

  • SALSA20

  • SEED

  • SM4

  • DESEDE

String

symmetricKeyLength (advanced)

The required length of the symmetric key used.

128

int

healthCheckConsumerEnabled (health)

Used for enabling or disabling all consumer based health checks from this component.

true

boolean

healthCheckProducerEnabled (health)

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:

Path Parameters (1 parameters)

Name Description Default Type

label (producer)

Required Logical name.

String

Query Parameters (13 parameters)

Name Description Default Type

operation (producer)

Required The operation to perform.

Enum values:

  • sign

  • verify

  • generateSecretKeyEncapsulation

  • extractSecretKeyEncapsulation

  • extractSecretKeyFromEncapsulation

  • getRemainingSignatures

  • getKeyState

  • deleteKeyState

  • generateKeyPair

  • exportKey

  • importKey

  • rotateKey

  • getKeyMetadata

  • listKeys

  • expireKey

  • revokeKey

PQCOperations

lazyStartProducer (producer (advanced))

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

keyEncapsulationAlgorithm (advanced)

In case there is no keyGenerator, we specify an algorithm to build the KeyGenerator.

Enum values:

  • MLKEM

  • BIKE

  • HQC

  • CMCE

  • SABER

  • FRODO

  • NTRU

  • NTRULPRime

  • SNTRUPrime

  • KYBER

String

keyGenerator (advanced)

Autowired The Key Generator to be used in encapsulation and extraction.

KeyGenerator

keyPair (advanced)

Autowired The KeyPair to be used.

KeyPair

keyPairAlias (advanced)

A KeyPair alias to use in combination with KeyStore parameter.

String

keyStore (advanced)

Autowired A KeyStore where we could get Cryptographic material.

KeyStore

keyStorePassword (advanced)

The KeyStore password to use in combination with KeyStore Parameter.

String

signatureAlgorithm (advanced)

In case there is no signer, we specify an algorithm to build the KeyPair or the Signer.

Enum values:

  • MLDSA

  • SLHDSA

  • LMS

  • HSS

  • XMSS

  • XMSSMT

  • DILITHIUM

  • FALCON

  • PICNIC

  • SNOVA

  • MAYO

  • SPHINCSPLUS

String

signer (advanced)

Autowired The Signer to be used.

Signature

storeExtractedSecretKeyAsHeader (advanced)

In the context of extractSecretKeyFromEncapsulation operation, this option define if we want to have the key set as header.

false

boolean

symmetricKeyAlgorithm (advanced)

In case we are using KEM operations, we need a Symmetric algorithm to be defined for the flow to work.

Enum values:

  • AES

  • ARIA

  • RC2

  • RC5

  • CAMELLIA

  • CAST5

  • CAST6

  • CHACHA7539

  • DSTU7624

  • GOST28147

  • GOST3412_2015

  • GRAIN128

  • HC128

  • HC256

  • SALSA20

  • SEED

  • SM4

  • DESEDE

String

symmetricKeyLength (advanced)

The required length of the symmetric key used.

128

int

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

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

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.

Examples

  • ML-DSA

    from("direct:sign").to("pqc:sign?operation=sign").to("mock:sign").to("pqc:verify?operation=verify")
      .to("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

  from("direct:sign").to("pqc:sign?operation=sign&signatureAlgorithm=MLDSA").to("mock:sign")
    .to("pqc:verify?operation=verify&signatureAlgorithm=MLDSA")
    .to("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.

  • SLH-DSA

    from("direct:sign").to("pqc:sign?operation=sign").to("mock:sign").to("pqc:verify?operation=verify")
      .to("mock:verify");

With the following beans registered in the Registry

    @BindToRegistry("Keypair")
    public KeyPair setKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("SLH-DSA", "BC");
        kpGen.initialize(SLHDSAParameterSpec.slh_dsa_sha2_128s);
        KeyPair kp = kpGen.generateKeyPair();
        return kp;
    }

    @BindToRegistry("Signer")
    public Signature getSigner() throws NoSuchAlgorithmException {
        Signature slhDsa = Signature.getInstance("SLH-DSA");
        return slhDsa;
    }

This could be done even without the Registry beans, by specifying the signatureAlgorithm parameter in the following way

  from("direct:sign").to("pqc:sign?operation=sign&signatureAlgorithm=SLHDSA").to("mock:sign")
    .to("pqc:verify?operation=verify&signatureAlgorithm=SLHDSA")
    .to("mock:verify");

With this approach the component will use the class org.apache.camel.component.pqc.crypto.PQCDefaultSLHDSAMaterial, which will create the Signature and KeyPair objects to be used.

The Spec used for the KeyPair will be, in this case, SLH-DSA-SHA2-128s.

  • LMS

    from("direct:sign").to("pqc:sign?operation=sign").to("mock:sign").to("pqc:verify?operation=verify")
      .to("mock:verify");

With the following beans registered in the Registry

    @BindToRegistry("Keypair")
    public KeyPair setKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("LMS", "BC");
        kpGen.initialize(new LMSKeyGenParameterSpec(LMSigParameters.lms_sha256_n32_h5, LMOtsParameters.sha256_n32_w1));
        KeyPair kp = kpGen.generateKeyPair();
        return kp;
    }

    @BindToRegistry("Signer")
    public Signature getSigner() throws NoSuchAlgorithmException {
        Signature lms = Signature.getInstance("LMS");
        return lms;
    }

This could be done even without the Registry beans, by specifying the signatureAlgorithm parameter in the following way

  from("direct:sign").to("pqc:sign?operation=sign&signatureAlgorithm=LMS").to("mock:sign")
    .to("pqc:verify?operation=verify&signatureAlgorithm=LMS")
    .to("mock:verify");

With this approach the component will use the class org.apache.camel.component.pqc.crypto.PQCDefaultLMSMaterial, which will create the Signature and KeyPair objects to be used.

The Parameters used will be LMS-SHA256-N32-H5 for the signature and SHA256-n32-w1 for the one-time signature.

  • XMSS

    from("direct:sign").to("pqc:sign?operation=sign").to("mock:sign").to("pqc:verify?operation=verify")
      .to("mock:verify");

With the following beans registered in the Registry

    @BindToRegistry("Keypair")
    public KeyPair setKeyPair() throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException {
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("XMSS", "BCPQC");
        kpGen.initialize(new XMSSParameterSpec(10, XMSSParameterSpec.SHA256), new SecureRandom());
        KeyPair kp = kpGen.generateKeyPair();
        return kp;
    }

    @BindToRegistry("Signer")
    public Signature getSigner() throws NoSuchAlgorithmException {
        Signature xmss = Signature.getInstance("XMSS");
        return xmss;
    }

This could be done even without the Registry beans, by specifying the signatureAlgorithm parameter in the following way

  from("direct:sign").to("pqc:sign?operation=sign&signatureAlgorithm=XMSS").to("mock:sign")
    .to("pqc:verify?operation=verify&signatureAlgorithm=XMSS")
    .to("mock:verify");

With this approach the component will use the class org.apache.camel.component.pqc.crypto.PQCDefaultXMSSMaterial, which will create the Signature and KeyPair objects to be used.

The Parameters used will be 10 as tree height and SHA-256 for the tree digest.

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.

A possible flow of the operation could be the following:

  • ML-KEM

from("direct:encapsulate").to("pqc:keyenc?operation=generateSecretKeyEncapsulation&symmetricKeyAlgorithm=AES")
  .to("mock:encapsulate")
  .to("pqc:keyenc?operation=extractSecretKeyEncapsulation&symmetricKeyAlgorithm=AES").to("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

   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");

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);
        return new RouteBuilder() {
            @Override
            public void configure() {
                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.

Key Lifecycle Management

The PQC component provides comprehensive key lifecycle management capabilities for Post-Quantum Cryptography keys. This includes key generation, storage, rotation, expiration, revocation, and format conversion.

Key lifecycle management is critical for maintaining security in production environments, especially with stateful hash-based signature algorithms (XMSS, XMSSMT, LMS, HSS) that have limited signature capacity.

Key Lifecycle Manager Interface

The KeyLifecycleManager interface provides the following operations:

  • Key Generation - Generate new key pairs with algorithm-specific parameters

  • Key Storage - Store and retrieve keys with metadata

  • Key Rotation - Rotate keys and deprecate old ones

  • Key Expiration - Mark keys as expired based on age or policy

  • Key Revocation - Revoke compromised keys with reason tracking

  • Key Export/Import - Convert keys between formats (PEM, DER, PKCS8, X.509)

  • Key Listing - List all keys with their metadata

  • Rotation Detection - Check if keys need rotation based on age or usage

Available Implementations

The component provides three implementations of KeyLifecycleManager:

FileBasedKeyLifecycleManager

A production-ready implementation that persists keys and metadata to disk.

Features:

  • Persistent storage - keys survive application restarts

  • File-based storage with .key and .metadata files

  • In-memory caching for performance

  • Automatic loading of existing keys on startup

  • Secure file permissions

Use Cases:

  • Production environments

  • Single-instance deployments

  • When persistence is required

  • Audit and compliance requirements

Example:

KeyLifecycleManager keyManager = new FileBasedKeyLifecycleManager("/secure/keys");

// Generate a new Dilithium key
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "app-signing-key",
    DilithiumParameterSpec.dilithium2);

// Use the key
KeyMetadata metadata = keyManager.getKeyMetadata("app-signing-key");
logger.info("Key created: {}", metadata);

InMemoryKeyLifecycleManager

A lightweight implementation that stores keys in memory only.

Features:

  • Non-persistent storage - keys lost on restart

  • ConcurrentHashMap-based storage

  • No I/O overhead

  • Thread-safe operations

  • Additional utility methods: clear() and size()

Use Cases:

  • Testing and development

  • Ephemeral workloads

  • Short-lived applications

  • Unit and integration tests

Example:

InMemoryKeyLifecycleManager keyManager = new InMemoryKeyLifecycleManager();

// Generate a test key
KeyPair keyPair = keyManager.generateKeyPair("FALCON", "test-key");

// Clean up after testing
keyManager.clear();

HashicorpVaultKeyLifecycleManager

An enterprise-grade implementation that integrates with HashiCorp Vault for centralized secret management.

Security Implementation:

This implementation uses industry-standard cryptographic key formats and separation of concerns:

  • Private keys: Stored in PKCS#8 format (RFC 5208) - the standard for private key encoding

  • Public keys: Stored in X.509/SubjectPublicKeyInfo format (RFC 5280) - the standard for public key encoding

  • Separate storage: Private keys, public keys, and metadata are stored in distinct Vault paths

  • Fine-grained ACLs: Enables different access policies for private keys (restricted) vs public keys (read-only)

Security Note: This implementation stores PQC keys in Vault’s KV secrets engine. While this approach uses industry-standard formats and enables fine-grained access control, organizations with stringent security requirements should consider:

  • Using Hardware Security Modules (HSMs) via PKCS#11 for keys that must never be exportable

  • Implementing additional encryption layers using Vault’s Transit engine to encrypt key material before storage

  • Applying strict Vault policies limiting private key access to specific services or key IDs only

  • Regular key rotation and audit log monitoring

  • For production use, review and customize the Vault ACL policies shown in the setup section

Features:

  • Centralized secret management via HashiCorp Vault

  • Industry-standard key formats (PKCS#8 for private keys, X.509 for public keys)

  • Separate storage for private and public keys (enables different ACLs)

  • Automatic audit logging of all key operations

  • Fine-grained access control with Vault policies

  • Encryption at rest

  • High availability support (Vault HA clusters)

  • In-memory caching for performance

  • Uses Spring Vault (spring-vault-core) consistent with camel-hashicorp-vault

  • HashiCorp Cloud Platform (HCP) Vault support

Use Cases:

  • Production environments with existing Vault infrastructure

  • Multi-node/distributed deployments

  • Enterprise security and compliance requirements

  • Centralized key management across multiple applications

  • Audit and compliance mandates

Dependencies:

To use HashicorpVaultKeyLifecycleManager, add the following optional dependency:

<dependency>
    <groupId>org.springframework.vault</groupId>
    <artifactId>spring-vault-core</artifactId>
    <version>${spring-vault-core-version}</version>
</dependency>

Example with VaultTemplate:

// Option 1: Using existing VaultTemplate (recommended when using camel-hashicorp-vault)
@BindToRegistry("vaultTemplate")
public VaultTemplate createVaultTemplate() {
    VaultEndpoint vaultEndpoint = new VaultEndpoint();
    vaultEndpoint.setHost("localhost");
    vaultEndpoint.setPort(8200);
    vaultEndpoint.setScheme("https");

    return new VaultTemplate(vaultEndpoint, new TokenAuthentication("s.token"));
}

@BindToRegistry("keyLifecycleManager")
public HashicorpVaultKeyLifecycleManager createKeyManager() {
    return new HashicorpVaultKeyLifecycleManager(
        vaultTemplate,      // Reuse existing VaultTemplate
        "secret",           // Secrets engine name
        "pqc/keys"         // Key prefix in Vault
    );
}

// Generate a Dilithium key stored in Vault
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "app-signing-key",
    DilithiumParameterSpec.dilithium2);

// Key is stored in Vault at: secret/data/pqc/keys/app-signing-key

Example with Direct Configuration:

// Option 2: Direct configuration with connection parameters
HashicorpVaultKeyLifecycleManager keyManager =
    new HashicorpVaultKeyLifecycleManager(
        "vault.example.com",  // host
        8200,                 // port
        "https",              // scheme
        "s.your-token",       // Vault token
        "secret",             // secrets engine (optional, defaults to "secret")
        "pqc/keys"           // key prefix (optional, defaults to "pqc/keys")
    );

// Generate and store key in Vault
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "vault-key",
    DilithiumParameterSpec.dilithium2);

Example with HashiCorp Cloud Platform (HCP) Vault:

// Option 3: Configuration for HCP Vault with namespace
HashicorpVaultKeyLifecycleManager keyManager =
    new HashicorpVaultKeyLifecycleManager(
        "your-cluster.vault.hashicorp.cloud",  // HCP Vault host
        8200,                                    // port
        "https",                                 // scheme
        "s.your-hcp-token",                     // HCP Vault token
        "secret",                                // secrets engine
        "pqc/keys",                             // key prefix
        true,                                    // cloud=true for HCP Vault
        "admin"                                  // namespace (required for HCP)
    );

// Generate and store key in HCP Vault
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "hcp-key",
    DilithiumParameterSpec.dilithium2);

// Key is stored in HCP Vault at: admin/secret/data/pqc/keys/hcp-key

YAML Configuration:

camel:
  beans:
    # Create VaultTemplate
    vaultEndpoint:
      type: org.springframework.vault.client.VaultEndpoint
      properties:
        host: "vault.example.com"
        port: 8200
        scheme: "https"

    tokenAuthentication:
      type: org.springframework.vault.authentication.TokenAuthentication
      constructorArgs:
        - "${VAULT_TOKEN}"

    vaultTemplate:
      type: org.springframework.vault.core.VaultTemplate
      constructorArgs:
        - "#bean:vaultEndpoint"
        - "#bean:tokenAuthentication"

    # Create HashicorpVaultKeyLifecycleManager
    keyLifecycleManager:
      type: org.apache.camel.component.pqc.lifecycle.HashicorpVaultKeyLifecycleManager
      constructorArgs:
        - "#bean:vaultTemplate"
        - "secret"
        - "pqc/keys"
        - false              # cloud
        - null               # namespace

YAML Configuration for HCP Vault:

camel:
  beans:
    # Create VaultTemplate for HCP
    vaultEndpoint:
      type: org.springframework.vault.client.VaultEndpoint
      properties:
        host: "your-cluster.vault.hashicorp.cloud"
        port: 8200
        scheme: "https"

    tokenAuthentication:
      type: org.springframework.vault.authentication.TokenAuthentication
      constructorArgs:
        - "${HCP_VAULT_TOKEN}"

    vaultTemplate:
      type: org.springframework.vault.core.VaultTemplate
      constructorArgs:
        - "#bean:vaultEndpoint"
        - "#bean:tokenAuthentication"

    # Create HashicorpVaultKeyLifecycleManager for HCP Vault
    keyLifecycleManager:
      type: org.apache.camel.component.pqc.lifecycle.HashicorpVaultKeyLifecycleManager
      constructorArgs:
        - "#bean:vaultTemplate"
        - "secret"
        - "pqc/keys"
        - true               # cloud=true for HCP Vault
        - "admin"            # namespace (required for HCP)

Vault Storage Structure:

Keys are stored in Vault’s KV v2 secrets engine with separate paths for private keys, public keys, and metadata. This separation enables fine-grained access control where applications can access public keys without having access to private keys.

On-Premise Vault:

secret/                                    # Secrets engine
├── data/
│   └── pqc/
│       └── keys/
│           ├── app-signing-key/
│           │   ├── private                # Private key path (STRICT ACL)
│           │   │   ├── key                # Base64-encoded PKCS#8 private key
│           │   │   ├── format             # "PKCS8"
│           │   │   └── algorithm          # "DILITHIUM"
│           │   ├── public                 # Public key path (READ-ONLY ACL)
│           │   │   ├── key                # Base64-encoded X.509 public key
│           │   │   ├── format             # "X509"
│           │   │   └── algorithm          # "DILITHIUM"
│           │   └── metadata               # Metadata path
│           │       ├── metadata           # Serialized KeyMetadata
│           │       ├── keyId              # "app-signing-key"
│           │       └── algorithm          # "DILITHIUM"
│           └── app-signing-key-v2/
│               ├── private/
│               ├── public/
│               └── metadata/
└── metadata/
    └── pqc/
        └── keys/
            ├── app-signing-key/           # Vault metadata entry
            └── app-signing-key-v2/

HCP Vault (with namespace):

admin/                                     # Namespace
└── secret/                                # Secrets engine
    ├── data/
    │   └── pqc/
    │       └── keys/
    │           ├── app-signing-key/
    │           │   ├── private/           # PKCS#8 private key (STRICT ACL)
    │           │   ├── public/            # X.509 public key (READ-ONLY ACL)
    │           │   └── metadata/          # Key metadata
    │           └── app-signing-key-v2/
    │               ├── private/
    │               ├── public/
    │               └── metadata/
    └── metadata/
        └── pqc/
            └── keys/
                ├── app-signing-key/
                └── app-signing-key-v2/

Integration with camel-hashicorp-vault:

HashicorpVaultKeyLifecycleManager can share the same VaultTemplate with the camel-hashicorp-vault component:

// Reuse VaultTemplate from camel-hashicorp-vault
@BindToRegistry("keyLifecycleManager")
public HashicorpVaultKeyLifecycleManager createKeyManager() {
    VaultTemplate vaultTemplate = context.getRegistry()
        .lookupByNameAndType("vaultTemplate", VaultTemplate.class);

    return new HashicorpVaultKeyLifecycleManager(
        vaultTemplate,
        "secret",
        "pqc/keys"
    );
}

Vault Setup and Security Policies:

To use HashicorpVaultKeyLifecycleManager, configure Vault with appropriate policies. The implementation stores private keys, public keys, and metadata separately to enable fine-grained access control.

Basic Policy (Full Access - Development/Testing):

# Enable KV v2 secrets engine (usually enabled by default)
vault secrets enable -path=secret kv-v2

# Create basic policy with full access to all key paths
cat > pqc-policy-full.hcl <<EOF
# Full access to private keys
path "secret/data/pqc/keys/*/private" {
  capabilities = ["create", "read", "update", "delete"]
}

# Full access to public keys
path "secret/data/pqc/keys/*/public" {
  capabilities = ["create", "read", "update", "delete"]
}

# Full access to metadata
path "secret/data/pqc/keys/*/metadata" {
  capabilities = ["create", "read", "update", "delete"]
}

# List access to key paths
path "secret/metadata/pqc/keys/*" {
  capabilities = ["list", "read", "delete"]
}
EOF

# Apply policy
vault policy write pqc-keys-full pqc-policy-full.hcl

# Create token with policy
vault token create -policy=pqc-keys-full

Production Policies (Fine-Grained Access Control):

# POLICY 1: Admin Policy (Key Management Service)
# Full access to generate, rotate, and manage keys
cat > pqc-policy-admin.hcl <<EOF
path "secret/data/pqc/keys/*/private" {
  capabilities = ["create", "read", "update", "delete"]
}

path "secret/data/pqc/keys/*/public" {
  capabilities = ["create", "read", "update", "delete"]
}

path "secret/data/pqc/keys/*/metadata" {
  capabilities = ["create", "read", "update", "delete"]
}

path "secret/metadata/pqc/keys/*" {
  capabilities = ["list", "read", "delete"]
}
EOF

vault policy write pqc-admin pqc-policy-admin.hcl

# POLICY 2: Signing Service Policy (Read Private Keys for Signing)
# Read-only access to specific private keys for signing operations
cat > pqc-policy-signing.hcl <<EOF
# Read-only access to private keys (for signing operations)
path "secret/data/pqc/keys/*/private" {
  capabilities = ["read"]
}

# Read access to public keys
path "secret/data/pqc/keys/*/public" {
  capabilities = ["read"]
}

# Read access to metadata
path "secret/data/pqc/keys/*/metadata" {
  capabilities = ["read"]
}

# List keys
path "secret/metadata/pqc/keys/*" {
  capabilities = ["list", "read"]
}
EOF

vault policy write pqc-signing pqc-policy-signing.hcl

# POLICY 3: Application Policy (Public Keys Only)
# Read-only access to public keys for signature verification
cat > pqc-policy-app.hcl <<EOF
# NO access to private keys
# Read-only access to public keys
path "secret/data/pqc/keys/*/public" {
  capabilities = ["read"]
}

# Read access to metadata
path "secret/data/pqc/keys/*/metadata" {
  capabilities = ["read"]
}

# List keys
path "secret/metadata/pqc/keys/*" {
  capabilities = ["list", "read"]
}
EOF

vault policy write pqc-app pqc-policy-app.hcl

# POLICY 4: Specific Key Access (Production Best Practice)
# Limit access to specific key IDs only
cat > pqc-policy-specific.hcl <<EOF
# Access only to app-signing-key private key
path "secret/data/pqc/keys/app-signing-key/private" {
  capabilities = ["read"]
}

path "secret/data/pqc/keys/app-signing-key/public" {
  capabilities = ["read"]
}

path "secret/data/pqc/keys/app-signing-key/metadata" {
  capabilities = ["read"]
}
EOF

vault policy write pqc-app-signing-key pqc-policy-specific.hcl

# Create tokens with different policies
vault token create -policy=pqc-admin        # For key management service
vault token create -policy=pqc-signing      # For signing service
vault token create -policy=pqc-app          # For applications (verification only)
vault token create -policy=pqc-app-signing-key  # For specific key access

AwsSecretsManagerKeyLifecycleManager

An enterprise-grade implementation that integrates with AWS Secrets Manager for centralized secret management.

Security Implementation:

This implementation uses industry-standard cryptographic key formats and separation of concerns:

  • Private keys: Stored in PKCS#8 format (RFC 5208) - the standard for private key encoding

  • Public keys: Stored in X.509/SubjectPublicKeyInfo format (RFC 5280) - the standard for public key encoding

  • Separate storage: Private keys, public keys, and metadata are stored as distinct AWS secrets

  • Fine-grained IAM policies: Enables different access policies for private keys (restricted) vs public keys (read-only)

Security Note: This implementation stores PQC keys in AWS Secrets Manager. While this approach uses industry-standard formats and enables fine-grained access control, organizations with stringent security requirements should consider:

  • Using AWS CloudHSM for keys that must never be exportable

  • Implementing additional encryption layers using AWS KMS Customer Master Keys (CMKs)

  • Applying strict IAM policies limiting private key access to specific services or roles only

  • Regular key rotation and CloudTrail audit log monitoring

  • For production use, review and customize the IAM policies shown in the setup section

Features:

  • Centralized secret management via AWS Secrets Manager

  • Industry-standard key formats (PKCS#8 for private keys, X.509 for public keys)

  • Separate storage for private and public keys (enables different IAM policies)

  • Automatic audit logging through AWS CloudTrail

  • Fine-grained access control with IAM policies

  • Encryption at rest with AWS KMS

  • Multi-region replication support

  • In-memory caching for performance

  • Uses AWS SDK v2 (software.amazon.awssdk) consistent with other Camel AWS components

  • LocalStack endpoint override support for testing

Use Cases:

  • Production environments with existing AWS infrastructure

  • Multi-region deployments

  • Enterprise security and compliance requirements

  • Centralized key management across multiple applications

  • AWS Organizations and cross-account access scenarios

Dependencies:

To use AwsSecretsManagerKeyLifecycleManager, add the following optional dependency:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>secretsmanager</artifactId>
    <version>${aws-java-sdk2-version}</version>
</dependency>

Example with SecretsManagerClient:

// Option 1: Using existing SecretsManagerClient (recommended when using camel-aws-secrets-manager)
@BindToRegistry("secretsManagerClient")
public SecretsManagerClient createSecretsManagerClient() {
    return SecretsManagerClient.builder()
        .region(Region.US_EAST_1)
        .build(); // Uses default AWS credentials chain
}

@BindToRegistry("keyLifecycleManager")
public AwsSecretsManagerKeyLifecycleManager createKeyManager() {
    return new AwsSecretsManagerKeyLifecycleManager(
        secretsManagerClient,   // Reuse existing client
        "pqc/keys"             // Key prefix
    );
}

// Generate a Dilithium key stored in AWS Secrets Manager
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "app-signing-key",
    DilithiumParameterSpec.dilithium2);

// Keys are stored as: pqc/keys/app-signing-key/private, /public, /metadata

Example with Direct Configuration:

// Option 2: Direct configuration with AWS credentials
AwsSecretsManagerKeyLifecycleManager keyManager =
    new AwsSecretsManagerKeyLifecycleManager(
        "us-east-1",          // AWS region
        "AKIAIOSFODNN7EXAMPLE", // access key (optional, uses default credentials if null)
        "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", // secret key (optional)
        "pqc/keys"            // key prefix (optional, defaults to "pqc/keys")
    );

// Generate and store key in AWS Secrets Manager
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "aws-key",
    DilithiumParameterSpec.dilithium2);

Example with LocalStack (Testing):

// Option 3: Configuration for LocalStack testing
AwsSecretsManagerKeyLifecycleManager keyManager =
    new AwsSecretsManagerKeyLifecycleManager(
        "us-east-1",                    // region
        "test",                         // access key for LocalStack
        "test",                         // secret key for LocalStack
        "pqc/test-keys",                // key prefix
        "http://localhost:4566"         // LocalStack endpoint
    );

// Generate and store key in LocalStack
KeyPair keyPair = keyManager.generateKeyPair("DILITHIUM", "test-key",
    DilithiumParameterSpec.dilithium2);

YAML Configuration:

camel:
  beans:
    # Create SecretsManagerClient using default credentials
    secretsManagerClient:
      type: software.amazon.awssdk.services.secretsmanager.SecretsManagerClient
      factoryMethod: builder
      factoryBean:
        type: software.amazon.awssdk.services.secretsmanager.SecretsManagerClientBuilder
        properties:
          region: "!software.amazon.awssdk.regions.Region#US_EAST_1"
        factoryMethod: build

    # Create AwsSecretsManagerKeyLifecycleManager
    keyLifecycleManager:
      type: org.apache.camel.component.pqc.lifecycle.AwsSecretsManagerKeyLifecycleManager
      constructorArgs:
        - "#bean:secretsManagerClient"
        - "pqc/keys"

YAML Configuration with Explicit Credentials:

camel:
  beans:
    # Create AwsSecretsManagerKeyLifecycleManager with explicit configuration
    keyLifecycleManager:
      type: org.apache.camel.component.pqc.lifecycle.AwsSecretsManagerKeyLifecycleManager
      constructorArgs:
        - "us-east-1"           # region
        - "${AWS_ACCESS_KEY}"   # access key from environment
        - "${AWS_SECRET_KEY}"   # secret key from environment
        - "pqc/keys"            # key prefix
        - null                  # endpoint override (null for production)

AWS Secrets Storage Structure:

Keys are stored in AWS Secrets Manager with separate secrets for private keys, public keys, and metadata. This separation enables fine-grained access control where applications can access public keys without having access to private keys.

Each key creates three secrets:

pqc/keys/app-signing-key/private     # PKCS#8 private key (STRICT IAM POLICY)
  {
    "key": "MIIEvQIBADANBg...",        # Base64-encoded PKCS#8 private key
    "format": "PKCS8",
    "algorithm": "DILITHIUM"
  }
  Tags: ManagedBy=camel-pqc

pqc/keys/app-signing-key/public      # X.509 public key (READ-ONLY IAM POLICY)
  {
    "key": "MIIBIjANBgkqhk...",        # Base64-encoded X.509 public key
    "format": "X509",
    "algorithm": "DILITHIUM"
  }
  Tags: ManagedBy=camel-pqc

pqc/keys/app-signing-key/metadata    # Key metadata
  {
    "metadata": "rO0ABXNyAC9vcm...",  # Serialized KeyMetadata object
    "keyId": "app-signing-key",
    "algorithm": "DILITHIUM"
  }
  Tags: ManagedBy=camel-pqc

AWS Setup and IAM Policies:

To use AwsSecretsManagerKeyLifecycleManager, configure IAM policies for appropriate access control. The implementation stores private keys, public keys, and metadata separately to enable fine-grained access control.

Basic Policy (Full Access - Development/Testing):

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PQCKeysFullAccess",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:CreateSecret",
        "secretsmanager:GetSecretValue",
        "secretsmanager:PutSecretValue",
        "secretsmanager:DeleteSecret",
        "secretsmanager:ListSecrets",
        "secretsmanager:DescribeSecret",
        "secretsmanager:TagResource"
      ],
      "Resource": "arn:aws:secretsmanager:*:*:secret:pqc/keys/*"
    },
    {
      "Sid": "KMSAccess",
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "*",
      "Condition": {
        "StringEquals": {
          "kms:ViaService": "secretsmanager.*.amazonaws.com"
        }
      }
    }
  ]
}

Production Policies (Fine-Grained Access Control):

POLICY 1: Admin Policy (Key Management Service)

Full access to generate, rotate, and manage keys:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "PQCKeyManagement",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:CreateSecret",
        "secretsmanager:GetSecretValue",
        "secretsmanager:PutSecretValue",
        "secretsmanager:DeleteSecret",
        "secretsmanager:UpdateSecret",
        "secretsmanager:ListSecrets",
        "secretsmanager:DescribeSecret",
        "secretsmanager:TagResource"
      ],
      "Resource": "arn:aws:secretsmanager:*:*:secret:pqc/keys/*"
    },
    {
      "Sid": "KMSFullAccess",
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:Encrypt",
        "kms:GenerateDataKey",
        "kms:DescribeKey"
      ],
      "Resource": "*"
    }
  ]
}

POLICY 2: Signing Service Policy (Read Private Keys for Signing)

Read-only access to specific private keys for signing operations:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadPrivateKeysForSigning",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:*:*:secret:pqc/keys/*/private-*",
        "arn:aws:secretsmanager:*:*:secret:pqc/keys/*/public-*",
        "arn:aws:secretsmanager:*:*:secret:pqc/keys/*/metadata-*"
      ]
    },
    {
      "Sid": "ListKeys",
      "Effect": "Allow",
      "Action": "secretsmanager:ListSecrets",
      "Resource": "*",
      "Condition": {
        "StringLike": {
          "secretsmanager:Name": "pqc/keys/*"
        }
      }
    },
    {
      "Sid": "KMSDecrypt",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "*"
    }
  ]
}

POLICY 3: Application Policy (Public Keys Only)

Read-only access to public keys for signature verification:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadPublicKeysOnly",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:*:*:secret:pqc/keys/*/public-*",
        "arn:aws:secretsmanager:*:*:secret:pqc/keys/*/metadata-*"
      ]
    },
    {
      "Sid": "DenyPrivateKeyAccess",
      "Effect": "Deny",
      "Action": "secretsmanager:GetSecretValue",
      "Resource": "arn:aws:secretsmanager:*:*:secret:pqc/keys/*/private-*"
    },
    {
      "Sid": "ListKeys",
      "Effect": "Allow",
      "Action": "secretsmanager:ListSecrets",
      "Resource": "*"
    },
    {
      "Sid": "KMSDecrypt",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "*"
    }
  ]
}

POLICY 4: Specific Key Access (Production Best Practice)

Limit access to specific key IDs only:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "AccessSpecificKeyOnly",
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue",
        "secretsmanager:DescribeSecret"
      ],
      "Resource": [
        "arn:aws:secretsmanager:us-east-1:123456789012:secret:pqc/keys/app-signing-key/private-*",
        "arn:aws:secretsmanager:us-east-1:123456789012:secret:pqc/keys/app-signing-key/public-*",
        "arn:aws:secretsmanager:us-east-1:123456789012:secret:pqc/keys/app-signing-key/metadata-*"
      ]
    },
    {
      "Sid": "KMSDecrypt",
      "Effect": "Allow",
      "Action": "kms:Decrypt",
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/your-kms-key-id"
    }
  ]
}

Integration with camel-aws-secrets-manager:

AwsSecretsManagerKeyLifecycleManager can share the same SecretsManagerClient with the camel-aws-secrets-manager component:

// Reuse SecretsManagerClient from camel-aws-secrets-manager
@BindToRegistry("keyLifecycleManager")
public AwsSecretsManagerKeyLifecycleManager createKeyManager() {
    SecretsManagerClient secretsManagerClient = context.getRegistry()
        .lookupByNameAndType("secretsManagerClient", SecretsManagerClient.class);

    return new AwsSecretsManagerKeyLifecycleManager(
        secretsManagerClient,
        "pqc/keys"
    );
}

Comparison of Implementations:

Feature FileBasedKeyLifecycleManager InMemoryKeyLifecycleManager HashicorpVaultKeyLifecycleManager AwsSecretsManagerKeyLifecycleManager

Persistence

✅ File system

❌ Memory only

✅ Vault backend

✅ AWS Secrets Manager

Distributed

❌ Single node

❌ Single node

✅ Multi-node

✅ Multi-region

Audit Logging

❌ Manual

❌ None

✅ Automatic (Vault)

✅ Automatic (CloudTrail)

Access Control

❌ File permissions

❌ None

✅ Vault policies

✅ IAM policies

Encryption at Rest

❌ OS-dependent

❌ N/A

✅ Always (Vault)

✅ Always (AWS KMS)

High Availability

❌ No

❌ No

✅ Yes (Vault HA)

✅ Yes (AWS Multi-AZ)

External Dependencies

❌ None

❌ None

✅ Vault + spring-vault

✅ AWS SDK v2

Caching

✅ Yes

✅ Yes

✅ Yes

✅ Yes

Spring Integration

❌ No

❌ No

✅ Yes

❌ No

Cloud Integration

❌ No

❌ No

✅ HCP Vault

✅ AWS Native

Multi-Region Support

❌ No

❌ No

❌ No

✅ Yes

Use Case

Single server

Testing/Dev

Production/Enterprise (Vault)

Production/Enterprise (AWS)

Key Generation

The key lifecycle manager supports all PQC algorithms with sensible default parameter specifications.

Signature Algorithms

// ML-DSA (uses default ML-DSA-65)
KeyPair mldsaKey = keyManager.generateKeyPair("MLDSA", "mldsa-key");

// Dilithium with specific parameter
KeyPair dilithiumKey = keyManager.generateKeyPair("DILITHIUM", "dilithium-key",
    DilithiumParameterSpec.dilithium3);

// Falcon (uses default Falcon-512)
KeyPair falconKey = keyManager.generateKeyPair("FALCON", "falcon-key");

// XMSS (uses default 10-tree height with SHA-256)
KeyPair xmssKey = keyManager.generateKeyPair("XMSS", "xmss-key");

// XMSSMT (uses default XMSSMT-SHA2-20d2-256)
KeyPair xmssmtKey = keyManager.generateKeyPair("XMSSMT", "xmssmt-key");

// LMS/HSS (uses default LMS-SHA256-N32-H10)
KeyPair lmsKey = keyManager.generateKeyPair("LMS", "lms-key");

Key Encapsulation Algorithms

// ML-KEM (uses default)
KeyPair mlkemKey = keyManager.generateKeyPair("MLKEM", "mlkem-key");

// NTRU (uses default ntruhps2048509)
KeyPair ntruKey = keyManager.generateKeyPair("NTRU", "ntru-key");

// SNTRUPrime (uses default sntrup761)
KeyPair sntrupKey = keyManager.generateKeyPair("SNTRUPrime", "sntrup-key");

// BIKE (uses default bike128)
KeyPair bikeKey = keyManager.generateKeyPair("BIKE", "bike-key");

Key Metadata

Each key is associated with metadata that tracks its lifecycle:

KeyMetadata metadata = keyManager.getKeyMetadata("my-key");

System.out.println("Key ID: " + metadata.getKeyId());
System.out.println("Algorithm: " + metadata.getAlgorithm());
System.out.println("Status: " + metadata.getStatus());
System.out.println("Created: " + metadata.getCreatedAt());
System.out.println("Age (days): " + metadata.getAgeInDays());
System.out.println("Usage count: " + metadata.getUsageCount());
System.out.println("Expires at: " + metadata.getExpiresAt());
System.out.println("Next rotation: " + metadata.getNextRotationAt());

Key Status Values:

  • ACTIVE - Key is active and can be used

  • EXPIRED - Key has expired and should not be used

  • REVOKED - Key has been revoked due to compromise

  • PENDING_ROTATION - Key should be rotated soon

  • DEPRECATED - Key has been rotated and replaced

Key Rotation

Key rotation is essential for maintaining security. The lifecycle manager supports automated rotation:

// Check if key needs rotation
boolean needsRotation = keyManager.needsRotation("old-key",
    Duration.ofDays(90),  // Max age: 90 days
    10000);                // Max usage: 10,000 operations

if (needsRotation) {
    // Rotate the key
    KeyPair newKey = keyManager.rotateKey("old-key", "new-key", "DILITHIUM");

    // Old key is now DEPRECATED
    // New key is ACTIVE
    logger.info("Key rotated successfully");
}

Key Export and Import

Keys can be exported and imported in multiple formats:

Supported Formats:

  • PEM - Privacy-Enhanced Mail format (Base64 encoded)

  • DER - Distinguished Encoding Rules (binary)

  • PKCS8 - PKCS#8 format for private keys

  • X509 - X.509 format for public keys

Export Example:

KeyPair keyPair = keyManager.getKey("my-key");

// Export public key as PEM
byte[] publicPem = keyManager.exportPublicKey(keyPair, KeyFormat.PEM);
String pemString = new String(publicPem);
System.out.println(pemString);
// Output:
// -----BEGIN PUBLIC KEY-----
// MIIBIjAN...
// -----END PUBLIC KEY-----

// Export entire key pair (public only for safety)
byte[] keyPairPem = keyManager.exportKey(keyPair, KeyFormat.PEM, false);

// Export with private key (USE WITH CAUTION)
byte[] fullExport = keyManager.exportKey(keyPair, KeyFormat.DER, true);

Import Example:

// Import from PEM format
byte[] pemData = Files.readAllBytes(Paths.get("public-key.pem"));
KeyPair imported = keyManager.importKey(pemData, KeyFormat.PEM, "DILITHIUM");

// Store the imported key
KeyMetadata metadata = new KeyMetadata("imported-key", "DILITHIUM");
keyManager.storeKey("imported-key", imported, metadata);

Key Expiration and Revocation

Expire a Key:

// Set expiration time
KeyMetadata metadata = keyManager.getKeyMetadata("my-key");
metadata.setExpiresAt(Instant.now().plus(Duration.ofDays(365)));
keyManager.updateKeyMetadata("my-key", metadata);

// Manually expire immediately
keyManager.expireKey("my-key");

// Check if expired
if (metadata.isExpired()) {
    logger.warn("Key {} has expired", metadata.getKeyId());
}

Revoke a Key:

// Revoke a compromised key
keyManager.revokeKey("compromised-key", "Private key exposed in log file");

KeyMetadata metadata = keyManager.getKeyMetadata("compromised-key");
assert metadata.getStatus() == KeyMetadata.KeyStatus.REVOKED;
assert metadata.getDescription().contains("Revoked: Private key exposed");

Listing and Managing Keys

// List all keys
List<KeyMetadata> allKeys = keyManager.listKeys();

// Filter active keys
List<KeyMetadata> activeKeys = allKeys.stream()
    .filter(m -> m.getStatus() == KeyMetadata.KeyStatus.ACTIVE)
    .collect(Collectors.toList());

// Find keys needing rotation
for (KeyMetadata metadata : allKeys) {
    if (keyManager.needsRotation(metadata.getKeyId(), Duration.ofDays(90), 5000)) {
        logger.warn("Key {} needs rotation", metadata.getKeyId());
    }
}

// Delete old keys
for (KeyMetadata metadata : allKeys) {
    if (metadata.getStatus() == KeyMetadata.KeyStatus.DEPRECATED
        && metadata.getAgeInDays() > 365) {
        keyManager.deleteKey(metadata.getKeyId());
        logger.info("Deleted old deprecated key: {}", metadata.getKeyId());
    }
}

Integration with Camel Routes

The key lifecycle manager can be registered in the Camel registry and used in routes:

  • Java

  • YAML

@BindToRegistry("keyLifecycleManager")
public KeyLifecycleManager createKeyManager() throws IOException {
    return new FileBasedKeyLifecycleManager("/secure/keys");
}

@BindToRegistry("signingKey")
public KeyPair createSigningKey() throws Exception {
    KeyLifecycleManager manager = createKeyManager();
    return manager.generateKeyPair("DILITHIUM", "route-signing-key",
        DilithiumParameterSpec.dilithium2);
}
# Configure key lifecycle manager in application.yaml
camel:
  beans:
    keyLifecycleManager:
      type: org.apache.camel.component.pqc.lifecycle.FileBasedKeyLifecycleManager
      properties:
        keyDirectoryPath: "/secure/keys"

    signingKey:
      type: org.apache.camel.component.pqc.lifecycle.FileBasedKeyLifecycleManager
      scriptLanguage: groovy
      script: |
        def manager = new org.apache.camel.component.pqc.lifecycle.FileBasedKeyLifecycleManager('/secure/keys')
        def spec = org.bouncycastle.pqc.jcajce.spec.DilithiumParameterSpec.dilithium2
        manager.generateKeyPair('DILITHIUM', 'route-signing-key', spec)

Using in Routes:

  • Java

  • YAML

from("timer:check-rotation?period=86400000") // Check daily
    .bean("keyLifecycleManager", "needsRotation('route-signing-key', 90, 10000)")
    .choice()
        .when(body().isEqualTo(true))
            .log("Rotating signing key")
            .bean("keyLifecycleManager", "rotateKey('route-signing-key', 'route-signing-key-new', 'DILITHIUM')")
            .to("log:rotation-complete")
        .otherwise()
            .log("Key rotation not needed")
    .end();
# Automated key rotation route
- route:
    id: check-key-rotation
    from:
      uri: timer:check-rotation
      parameters:
        period: 86400000  # Check daily
    steps:
      - bean:
          ref: keyLifecycleManager
          method: needsRotation('route-signing-key', 90, 10000)
      - choice:
          when:
            - simple: "${body} == true"
              steps:
                - log: "Rotating signing key"
                - bean:
                    ref: keyLifecycleManager
                    method: rotateKey('route-signing-key', 'route-signing-key-new', 'DILITHIUM')
                - to: log:rotation-complete
          otherwise:
            steps:
              - log: "Key rotation not needed"

Default Parameter Specifications

The lifecycle manager provides sensible defaults for all algorithms:

Algorithm Default Parameter Spec

DILITHIUM

dilithium2

FALCON

falcon_512

SPHINCSPLUS

sha2_128s

XMSS

10-tree height with SHA-256

XMSSMT

XMSSMT-SHA2-20d2-256

LMS/HSS

LMS-SHA256-N32-H10 with SHA256-N32-W4

NTRU

ntruhps2048509

NTRULPRime

ntrulpr653

SNTRUPrime

sntrup761

SABER

lightsaberkem128r3

FRODO

frodokem640aes

BIKE

bike128

HQC

hqc128

CMCE

mceliece348864

Best Practices

1. Regular Key Rotation

Implement automated key rotation policies:

// Rotate keys every 90 days or after 10,000 uses
Duration maxAge = Duration.ofDays(90);
long maxUsage = 10000;

if (keyManager.needsRotation(keyId, maxAge, maxUsage)) {
    keyManager.rotateKey(keyId, keyId + "-new", algorithm);
}

2. Secure Storage

For FileBasedKeyLifecycleManager:

  • Store keys in a secure directory with restricted permissions

  • Use encrypted file systems where possible

  • Implement backup strategies for key files

  • Monitor access to key directories

3. Key Metadata Tracking

Always update metadata when using keys:

KeyMetadata metadata = keyManager.getKeyMetadata(keyId);
metadata.updateLastUsed(); // Increments usage count
keyManager.updateKeyMetadata(keyId, metadata);

4. Handle Stateful Signatures Carefully

For XMSS, XMSSMT, LMS, and HSS algorithms:

  • Track signature usage to prevent exhaustion

  • Never reuse a stateful signature state (critical security requirement)

  • Monitor usage percentage and rotate before exhaustion

  • Set appropriate maxSignatures based on tree height

5. Secure Key Export

When exporting keys:

  • Export public keys only when possible

  • Encrypt private key exports

  • Use secure channels for key transfer

  • Audit all key export operations

6. Testing Strategy

Use InMemoryKeyLifecycleManager for tests:

@BeforeEach
public void setup() {
    keyManager = new InMemoryKeyLifecycleManager();
}

@AfterEach
public void cleanup() {
    keyManager.clear();
}

Thread Safety

Both implementations are thread-safe:

  • FileBasedKeyLifecycleManager: Uses ConcurrentHashMap for caching and atomic file operations

  • InMemoryKeyLifecycleManager: Uses ConcurrentHashMap for all storage

Concurrent key operations are safe:

ExecutorService executor = Executors.newFixedThreadPool(10);

for (int i = 0; i < 100; i++) {
    final int index = i;
    executor.submit(() -> {
        try {
            keyManager.generateKeyPair("DILITHIUM", "key-" + index,
                DilithiumParameterSpec.dilithium2);
        } catch (Exception e) {
            logger.error("Key generation failed", e);
        }
    });
}

executor.shutdown();
executor.awaitTermination(1, TimeUnit.MINUTES);

Migration Between Implementations

To migrate from InMemoryKeyLifecycleManager to FileBasedKeyLifecycleManager:

InMemoryKeyLifecycleManager memoryManager = new InMemoryKeyLifecycleManager();
FileBasedKeyLifecycleManager fileManager = new FileBasedKeyLifecycleManager("/secure/keys");

// Export all keys
List<KeyMetadata> keys = memoryManager.listKeys();
for (KeyMetadata metadata : keys) {
    KeyPair keyPair = memoryManager.getKey(metadata.getKeyId());
    fileManager.storeKey(metadata.getKeyId(), keyPair, metadata);
}

logger.info("Migrated {} keys to file-based storage", keys.size());

Spring Boot Auto-Configuration

When using pqc with Spring Boot make sure to use the following Maven dependency to have support for auto configuration:

<dependency>
  <groupId>org.apache.camel.springboot</groupId>
  <artifactId>camel-pqc-starter</artifactId>
  <version>x.x.x</version>
  <!-- use the same version as your Camel core version -->
</dependency>

The component supports 18 options, which are listed below.

Name Description Default Type

camel.component.pqc.autowired-enabled

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

camel.component.pqc.configuration

Component configuration. The option is a org.apache.camel.component.pqc.PQCConfiguration type.

PQCConfiguration

camel.component.pqc.enabled

Whether to enable auto configuration of the pqc component. This is enabled by default.

Boolean

camel.component.pqc.health-check-consumer-enabled

Used for enabling or disabling all consumer based health checks from this component.

true

Boolean

camel.component.pqc.health-check-producer-enabled

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

camel.component.pqc.key-encapsulation-algorithm

In case there is no keyGenerator, we specify an algorithm to build the KeyGenerator.

String

camel.component.pqc.key-generator

The Key Generator to be used in encapsulation and extraction. The option is a javax.crypto.KeyGenerator type.

KeyGenerator

camel.component.pqc.key-pair

The KeyPair to be used. The option is a java.security.KeyPair type.

KeyPair

camel.component.pqc.key-pair-alias

A KeyPair alias to use in combination with KeyStore parameter.

String

camel.component.pqc.key-store

A KeyStore where we could get Cryptographic material. The option is a java.security.KeyStore type.

KeyStore

camel.component.pqc.key-store-password

The KeyStore password to use in combination with KeyStore Parameter.

String

camel.component.pqc.lazy-start-producer

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

camel.component.pqc.operation

The operation to perform.

PQCOperations

camel.component.pqc.signature-algorithm

In case there is no signer, we specify an algorithm to build the KeyPair or the Signer.

String

camel.component.pqc.signer

The Signer to be used. The option is a java.security.Signature type.

Signature

camel.component.pqc.store-extracted-secret-key-as-header

In the context of extractSecretKeyFromEncapsulation operation, this option define if we want to have the key set as header.

false

Boolean

camel.component.pqc.symmetric-key-algorithm

In case we are using KEM operations, we need a Symmetric algorithm to be defined for the flow to work.

String

camel.component.pqc.symmetric-key-length

The required length of the symmetric key used.

128

Integer