Skip to content

Flow 34 – Composite Key Rotation (COMPOSITE_KEM_COMBINE)

Rotate quantum-resistant composite keys while maintaining hybrid mode and component algorithms for continued HNDR protection.

Real-World Scenarios:

  • Scheduled rotation of production hybrid keys maintaining quantum resistance
  • Compliance-driven key refresh without algorithm changes
  • Zero-downtime rotation for critical encryption services
  • Rotation chain audit trails for regulatory compliance

Key Algorithms:

  • X25519: Classical ECDH key agreement providing efficient key exchange (NIST Level 3)
  • ML-KEM-768: Post-quantum KEM providing 192-bit security against quantum attacks (NIST FIPS 203)

API Endpoints:

  • POST /api/key-management/keys - Generate composite key (unified endpoint)
  • POST /api/key-management/keys/{kid}/rotations - Rotate composite key to successor
  • POST /api/crypto/encrypt - Encrypt with rotated key (transparent redirection)

Steps:

  1. Generate original composite key (X25519 + ML-KEM-768, COMPOSITE_KEM_COMBINE)
  2. Rotate to successor with same mode and algorithms using rotateKey()
  3. Verify bidirectional rotation chain (original.nextKid → successor, successor.previousKid → original)
  4. Verify original key status = ROTATED
  5. Demonstrate encryption transparently uses successor

When to use:

  • Scheduled key rotation maintaining quantum-resistant security
  • Compliance requirements for periodic key refresh
  • Zero-downtime rotation without re-encrypting historical data
  • Audit trails proving proper key lifecycle management

Dependency — this example imports co.ankatech.ankasecure.sdk.examples.ExampleUtil. If you have not copied that class yet, see example-util.md.


Complete Java Implementation

Source: src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario34.java

package co.ankatech.ankasecure.sdk.examples;

import co.ankatech.ankasecure.sdk.AuthenticatedSdk;
import co.ankatech.ankasecure.sdk.model.*;
import co.ankatech.secure.client.model.KeyRequest;

import java.nio.file.Path;

import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;

/**
 * Scenario 34 — Composite Key Rotation and Migration.
 *
 * <p>Demonstrates key rotation patterns for composite keys including:</p>
 * <ul>
 *   <li>Rotating from simple to composite keys (classical → hybrid)</li>
 *   <li>Upgrading security level (X25519+ML-KEM-768 → X448+ML-KEM-1024)</li>
 *   <li>Rotating composite to composite with different components</li>
 *   <li>Verifying rotation chains</li>
 * </ul>
 *
 * <h3>Rotation Patterns:</h3>
 * <ol>
 *   <li>Simple RSA → Composite hybrid X25519+ML-KEM-768 (migration to PQC)</li>
 *   <li>X25519+ML-KEM-768 → X448+ML-KEM-1024 (security level upgrade)</li>
 *   <li>Composite with KDF upgrade (HKDF-SHA256 → HKDF-SHA512)</li>
 * </ol>
 *
 * @author ANKATech Solutions Inc.
 * @since 3.0.0
 */
public final class ExampleScenario34 {

    private static final Path TEMP_DIR = Path.of("temp_files");

    private ExampleScenario34() { }

    public static void main(String[] args) {
        try {
            System.out.println("=================================================================");
            System.out.println("  SCENARIO 34: Composite Key Rotation");
            System.out.println("=================================================================\n");

            ensureTempDir(TEMP_DIR);
            java.util.Properties props = loadProperties();
            AuthenticatedSdk sdk = authenticate(props);

            demonstrateSimpleToCompositeRotation(sdk);
            demonstrateCompositeToCompositeRotation(sdk);
            demonstrateKdfUpgrade(sdk);

            System.out.println("\n=================================================================");
            System.out.println("  ALL ROTATION PATTERNS DEMONSTRATED");
            System.out.println("=================================================================");

        } catch (Exception e) {
            fatal("Scenario 34 failed", e);
        }
    }

    /**
     * Pattern 1: Rotate simple RSA key to composite hybrid.
     */
    private static void demonstrateSimpleToCompositeRotation(AuthenticatedSdk sdk) throws Exception {
        System.out.println("[1/3] ROTATE SIMPLE → COMPOSITE (Classical → Hybrid)\n");

        // Create simple RSA key
        String simpleKid = "simple_rsa_" + System.currentTimeMillis();
        KeyRequest simpleRequest = new KeyRequest()
            .kid(simpleKid)
            .kty("RSA")
            .alg("RSA-4096");

        KeyMetadata simpleKey = sdk.generateKey(simpleRequest);
        System.out.println("      Original key created: " + simpleKey.getKid());
        System.out.println("      Type: " + simpleKey.getKty());
        System.out.println("      Algorithm: " + simpleKey.getAlg());
        System.out.println();

        // Rotate to composite hybrid
        // Note: X25519 (128-bit) pairs with ML-KEM-768 (Level 3) for balanced security
        // For ML-KEM-1024 (Level 5), use X448 or P-384/P-521
        String compositeKid = "hybrid_successor_" + System.currentTimeMillis();
        KeyRequest compositeRequest = new KeyRequest()
            .kid(compositeKid)
            .kty("COMPOSITE_KEM_COMBINE")
            .alg("X25519+ML-KEM-768")
            .kdf("HKDF-SHA256");

        System.out.println("      Rotating to hybrid key (X25519+ML-KEM-768)...");
        System.out.println("      Note: RSA supports sign/verify, COMPOSITE_KEM_COMBINE does not");
        System.out.println("            Acknowledging capability reduction...");

        // Must acknowledge capability reduction: RSA has sign/verify, KEM does not
        KeyMetadata rotated = sdk.rotateKey(simpleKid, compositeRequest, true);

        System.out.println("\n      ✅ Rotation complete");
        System.out.println("      New KID: " + rotated.getKid());
        System.out.println("      New Type: " + rotated.getKty());
        System.out.println("      New Algorithm: " + rotated.getAlg());
        System.out.println("      KDF: " + rotated.getKdf());
        System.out.println("      Previous KID: " + rotated.getPreviousKid());
        System.out.println("      Capability reduction: Lost sign/verify operations");
        System.out.println("      Migration: Classical RSA → Quantum-resistant hybrid\n");
    }

    /**
     * Pattern 2: Upgrade PQC component in composite key.
     */
    private static void demonstrateCompositeToCompositeRotation(AuthenticatedSdk sdk) throws Exception {
        System.out.println("[2/3] ROTATE COMPOSITE → COMPOSITE (Security Level Upgrade)\n");

        // Create Level 3 composite key (X25519 = 128-bit, ML-KEM-768 = Level 3)
        String level3Kid = "hybrid_level3_" + System.currentTimeMillis();
        KeyRequest level3Request = new KeyRequest()
            .kid(level3Kid)
            .kty("COMPOSITE_KEM_COMBINE")
            .alg("X25519+ML-KEM-768");      // Level 3 PQC

        KeyMetadata level3Key = sdk.generateKey(level3Request);
        System.out.println("      Original key: " + level3Key.getKid());
        System.out.println("      Algorithm: " + level3Key.getAlg() + " (X25519 + ML-KEM Level 3)");
        System.out.println();

        // Upgrade to Level 5
        // X448+ML-KEM-1024 provides balanced Level 5 security (both components ~192-256 bit)
        String level5Kid = "hybrid_level5_" + System.currentTimeMillis();
        KeyRequest level5Request = new KeyRequest()
            .kid(level5Kid)
            .kty("COMPOSITE_KEM_COMBINE")
            .alg("X448+ML-KEM-1024");       // Upgraded both classical and PQC

        System.out.println("      Upgrading to Level 5...");
        KeyMetadata upgraded = sdk.rotateKey(level3Kid, level5Request, false);

        System.out.println("\n      ✅ Security upgrade complete");
        System.out.println("      New Algorithm: " + upgraded.getAlg() + " (Level 5)");
        System.out.println("      Previous KID: " + upgraded.getPreviousKid());
        System.out.println("      Upgrade: X25519+ML-KEM-768 → X448+ML-KEM-1024\n");
    }

    /**
     * Pattern 3: Upgrade KDF in composite key.
     */
    private static void demonstrateKdfUpgrade(AuthenticatedSdk sdk) throws Exception {
        System.out.println("[3/3] ROTATE WITH KDF UPGRADE (SHA256 → SHA512)\n");

        // Create key with HKDF-SHA256
        String sha256Kid = "hybrid_sha256_" + System.currentTimeMillis();
        KeyRequest sha256Request = new KeyRequest()
            .kid(sha256Kid)
            .kty("COMPOSITE_KEM_COMBINE")
            .alg("X25519+ML-KEM-768")
            .kdf("HKDF-SHA256");

        KeyMetadata sha256Key = sdk.generateKey(sha256Request);
        System.out.println("      Original key: " + sha256Key.getKid());
        System.out.println("      KDF: " + sha256Key.getKdf());
        System.out.println();

        // Rotate with stronger KDF
        String sha512Kid = "hybrid_sha512_" + System.currentTimeMillis();
        KeyRequest sha512Request = new KeyRequest()
            .kid(sha512Kid)
            .kty("COMPOSITE_KEM_COMBINE")
            .alg("X25519+ML-KEM-768")
            .kdf("HKDF-SHA512");            // Stronger KDF

        System.out.println("      Upgrading KDF...");
        KeyMetadata upgraded = sdk.rotateKey(sha256Kid, sha512Request, false);

        System.out.println("\n      ✅ KDF upgrade complete");
        System.out.println("      New KDF: " + upgraded.getKdf());
        System.out.println("      Previous KID: " + upgraded.getPreviousKid());
        System.out.println("      Upgrade: HKDF-SHA256 → HKDF-SHA512\n");
    }
}

Running This Example

Prerequisites

  1. AnkaSecure SDK 3.0.0 or higher
  2. Java 17+
  3. Valid cli.properties with credentials
  4. Running AnkaSecure Core API instance

Compilation and Execution

# Compile example
javac -cp "ankasecure-sdk-3.0.0.jar:lib/*" ExampleScenario34.java ExampleUtil.java

# Run example
java -cp ".:ankasecure-sdk-3.0.0.jar:lib/*" \
  -Dcli.config=cli.properties \
  co.ankatech.ankasecure.sdk.examples.ExampleScenario34

# Or via Maven
cd ankasecure-sdk
mvn exec:java -Dexec.mainClass="co.ankatech.ankasecure.sdk.examples.ExampleScenario34"

Expected Output

===== SCENARIO 34: COMPOSITE KEY ROTATION =====
Purpose: Rotate hybrid quantum-resistant keys
Pattern: Generate Composite → Rotate → Verify Chain

╔═══════════════════════════════════════════╗
║  PHASE 1: GENERATE ORIGINAL COMPOSITE    ║
╚═══════════════════════════════════════════╝

[1/3] Building composite key specification...
      KID: sc34_hybrid_v1_1735396800000
      Mode: COMPOSITE_KEM_COMBINE
      Components:
        • Classical: X25519 (Curve25519 ECDH, Level 3)
        • PQC: ML-KEM-768 (NIST FIPS 203, Level 3)
      KDF: HKDF-SHA256

[2/3] Generating composite key on server...
      ✅ Composite key generated
      Algorithm: X25519+ML-KEM-768
      Status: ACTIVE
      Usage count: 0

╔═══════════════════════════════════════════╗
║  PHASE 2: ROTATE TO SUCCESSOR            ║
╚═══════════════════════════════════════════╝

[3/5] Building successor specification...
      Original KID: sc34_hybrid_v1_1735396800000
      Successor KID: sc34_hybrid_v2_1735396800001
      ⚠️ IMPORTANT:
         • Mode MUST match (COMPOSITE_KEM_COMBINE)
         • Algorithms MUST match (X25519 + ML-KEM-768)
         • Cannot change to COMPOSITE_SIGNATURE
         • Cannot downgrade to SIMPLE

[4/5] Executing composite key rotation...
      Calling: sdk.rotateKey()
      ✅ Rotation successful
      Successor KID: sc34_hybrid_v2_1735396800001
      Successor Status: ACTIVE

╔═══════════════════════════════════════════╗
║  PHASE 3: VERIFY ROTATION CHAIN          ║
╚═══════════════════════════════════════════╝

[5/7] Retrieving original key metadata...
      Original key:
         • KID: sc34_hybrid_v1_1735396800000
         • Status: ROTATED
         • Next KID: sc34_hybrid_v2_1735396800001

[6/7] Retrieving successor key metadata...
      Successor key:
         • KID: sc34_hybrid_v2_1735396800001
         • Status: ACTIVE
         • Previous KID: sc34_hybrid_v1_1735396800000

[7/7] Verifying bidirectional rotation chain...
      ✅ Rotation chain verified:
         • Original → ROTATED status
         • Original.nextKid → Successor
         • Successor.previousKid → Original
         • Bidirectional linkage: VALID

╔═══════════════════════════════════════════╗
║  PHASE 4: TRANSPARENT ENCRYPTION         ║
╚═══════════════════════════════════════════╝

[8/10] Creating test plaintext...
       File: temp_files/sc34_plaintext.txt
       Size: 45 bytes

[9/10] Encrypting with ORIGINAL KID (should use successor)...
       Requested KID: sc34_hybrid_v1_1735396800000 (ROTATED)
       ✅ Encryption successful
       Key requested: sc34_hybrid_v1_1735396800000
       Key actually used: sc34_hybrid_v2_1735396800001
       Algorithm: COMPOSITE-KEM-COMBINE

[10/10] Analyzing transparent redirection...
       ✅ Transparent redirection verified:
          • Client requested: sc34_hybrid_v1_1735396800000
          • Server used: sc34_hybrid_v2_1735396800001
          • Rotation transparent to client
          • No code changes required

       Security guarantee:
       • Encryption uses NEW rotated key
       • Historical data decrypts with OLD key
       • Zero-downtime rotation achieved

✅ SCENARIO 34 SUCCESSFUL
   - Original key: sc34_hybrid_v1_1735396800000 (ROTATED)
   - Successor key: sc34_hybrid_v2_1735396800001 (ACTIVE)
   - Rotation chain: verified
   - Quantum resistance: maintained

===== SCENARIO 34 END =====

Key Concepts

1. Composite Key Rotation Rules

Immutable Requirements:

  • Mode Preservation: COMPOSITE_KEM_COMBINE must remain COMPOSITE_KEM_COMBINE
  • Algorithm Preservation: Component algorithms must match exactly
  • Classical at index 0: X25519 → X25519
  • PQC at index 1: ML-KEM-768 → ML-KEM-768

  • Component Count: Must maintain same number of components (2)

Mutable Settings:

  • Can change: kid (successor identifier)
  • Can change: maxUsageLimit, softUsageLimit
  • Can change: expiresAt, softLimitExpiration
  • Can change: exportable flag
  • Can change: keyOps (if subset of original)

Blocked Scenarios:

// Cannot change mode
Original: COMPOSITE_KEM_COMBINE
Successor: COMPOSITE_SIGNATURE
Result: InvalidInputException("Composite mode mismatch")

// Cannot change algorithms
Original: [X25519, ML-KEM-768]
Successor: [RSA-3072, ML-KEM-768]
Result: InvalidInputException("Component algorithm mismatch at index 0")

// Cannot downgrade to SIMPLE
Original: COMPOSITE (X25519 + ML-KEM-768)
Successor: SIMPLE (ML-KEM-1024)
Result: InvalidInputException("Cannot rotate COMPOSITE key to SIMPLE key")

2. Rotation Chain Tracking

Bidirectional Linkage:

Original Key (ROTATED):
  ├─ kid: "hybrid-v1"
  ├─ status: ROTATED
  ├─ nextKid: "hybrid-v2"  ← Points forward
  └─ previousKid: null

Successor Key (ACTIVE):
  ├─ kid: "hybrid-v2"
  ├─ status: ACTIVE
  ├─ nextKid: null
  └─ previousKid: "hybrid-v1"  ← Points backward

Audit Trail:

  • Compliance: Proves key rotation occurred
  • Forensics: Traces historical encryption keys
  • Migration: Identifies rotation lineage

3. Transparent Redirection

Zero-Downtime Rotation:

When a client encrypts with a ROTATED key identifier:

Client Request:
  POST /api/crypto/encrypt
  { "kid": "hybrid-v1", "data": "..." }

Server Behavior:
  1. Lookup "hybrid-v1" → status = ROTATED
  2. Follow nextKid → "hybrid-v2"
  3. Encrypt using "hybrid-v2" (successor)
  4. Return: keyRequested="hybrid-v1", actualKeyUsed="hybrid-v2"

Client Result:
  ✅ Encryption successful
  ⚠️ Warning: "Key hybrid-v1 is ROTATED, used successor hybrid-v2"

Benefits:

  • No client code changes required
  • Historical data still decrypts with old key
  • New data encrypts with new key
  • Gradual migration without forced re-encryption

4. Quantum Resistance Continuity

Security Guarantee During Rotation:

Before Rotation:
  Key: hybrid-v1 (X25519 + ML-KEM-768)
  Security: Quantum-resistant (HNDR protected)

During Rotation:
  Old Key: hybrid-v1 (ROTATED, decrypt-only)
  New Key: hybrid-v2 (ACTIVE, encrypt+decrypt)
  Security: BOTH quantum-resistant

After Rotation:
  New Key: hybrid-v2 (X25519 + ML-KEM-768)
  Security: Quantum-resistant maintained
  Historical Data: Protected by hybrid-v1

No Security Gap: Quantum resistance maintained throughout rotation lifecycle.


  • Flow 23 - Simple key rotation (RSA → ML-KEM)
  • Flow 29 - Composite key generation and usage
  • Flow 30 - Regulatory compliance templates
  • Flow 17 - Key lifecycle and revocation

Flow: 34

Complexity: Intermediate

Estimated Time: 8 minutes