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:
- Generate original composite key (X25519 + ML-KEM-768, COMPOSITE_KEM_COMBINE)
- Rotate to successor with same mode and algorithms using
rotateKey() - Verify bidirectional rotation chain (original.nextKid → successor, successor.previousKid → original)
- Verify original key status = ROTATED
- 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
- AnkaSecure SDK 3.0.0 or higher
- Java 17+
- Valid
cli.propertieswith credentials - 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.
Related Examples
- 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