Flow 23 --- RSA-2048 → ML-KEM-768 Immediate Rotation
This scenario shows an instant successor upgrade from a classical RSA-2048 key to a post-quantum ML-KEM-768 key and then proves that the old KID can still be used transparently:
-
Generate an RSA-2048 key capable of
encrypt/decrypt
. -
Create an ML-KEM-768 successor in one API call (
createRotation
). -
Encrypt a plaintext with the original RSA KID and watch the platform silently redirect the request to the ML-KEM successor.
Key points
Zero downtime: the old KID stays valid while cryptography is instantly upgraded.
The SDK's response reveals both the key you asked for and the successor actually used.
Works for any successor pair (P-384 → ML-KEM-768, RSA-3072 → FALCON-1024, ...).
Perfect fit for brown-field services that must migrate to PQC without touching client code.
When to use it
-
Regulatory cut-overs---move to quantum-safe algorithms overnight yet keep legacy identifiers alive.
-
Gradual roll-outs---encrypt new data with the successor while historical tokens continue to decrypt with the old key.
-
Secrets-rotation policies---rotate keys on schedule (or on compromise) without ever re-encrypting data client-side.
Shared helper – this code imports the utility class from
example_util.md (configuration, authentication, JSON).
Complete Java implementation
src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario23.java
/* *****************************************************************************
* FILE: ExampleScenario23.java
* Copyright © 2025 Anka Technologies.
* SPDX-License-Identifier: MIT
* ---------------------------------------------------------------------------
* Scenario 23 – RSA-2048 ⇒ ML-KEM-768 Immediate Rotation
* ---------------------------------------------------------------------------
* Demonstrates how to:
* * Provision a brand-new **RSA-2048** key (encrypt/decrypt).
* * Rotate it immediately to an **ML-KEM-768** successor.
* * Encrypt data with the *original* KID and observe transparent successor
* selection by the platform.
*
* Console highlights:
* * `Key requested :` the original RSA KID.
* * `Key used :` the ML-KEM successor KID (server redirection).
* * `Algorithm used:` `ML-KEM-768+…`.
* ****************************************************************************/
package co.ankatech.ankasecure.sdk.examples;
import co.ankatech.ankasecure.sdk.AnkaSecureSdk;
import co.ankatech.ankasecure.sdk.exception.AnkaSecureSdkException;
import co.ankatech.ankasecure.sdk.model.EncryptResult;
import co.ankatech.ankasecure.sdk.model.ExportedKeySpec;
import co.ankatech.ankasecure.sdk.model.GenerateKeySpec;
import java.nio.file.Files;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
import static java.nio.charset.StandardCharsets.UTF_8;
/**
* Immediate key rotation from RSA-2048 to ML-KEM-768 and transparent
* successor usage during encryption.
*
* @author ANKATech – Security Engineering
* @since 2.1.0
*/
public final class ExampleScenario23 {
/* ------------------------------------------------------------------ */
private static final String RSA_KID =
"scenario23_rsa_" + System.currentTimeMillis();
/* ====================================================================== */
public static void main(String[] args) {
System.out.println("===== SCENARIO 23 START =====");
try {
Files.createDirectories(TEMP_DIR);
Properties props = loadProperties();
AnkaSecureSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 23 failed", ex);
}
System.out.println("===== SCENARIO 23 END =====");
}
/* ====================================================================== */
private static void runScenario(AnkaSecureSdk sdk)
throws AnkaSecureSdkException {
/* 1 – RSA-2048 key ------------------------------------------------ */
sdk.generateKey(new GenerateKeySpec()
.setKid(RSA_KID)
.setKty("RSA")
.setAlg("RSA-2048")
.setKeyOps(List.of("encrypt", "decrypt")));
System.out.println("[1] RSA-2048 key generated -> kid = " + RSA_KID);
/* 2 – rotate to ML-KEM-768 ------------------------------------- */
String kemKid = "scenario23_mlkem_" + System.currentTimeMillis();
ExportedKeySpec successor = sdk.createRotation(
RSA_KID,
new GenerateKeySpec()
.setKid(kemKid)
.setKty("ML-KEM")
.setAlg("ML-KEM-768")
.setKeyOps(List.of("encrypt", "decrypt")));
Objects.requireNonNull(successor, "Rotation must return successor metadata");
System.out.println("[2] Successor created -> kid = " + successor.getKid());
/* 3 – encrypt with original KID -------------------------------- */
byte[] plaintext = "Post-rotation encryption demo".getBytes(UTF_8);
EncryptResult enc = sdk.encrypt(RSA_KID, plaintext);
System.out.println("[3] Encryption metadata");
System.out.println(" Key requested : " + nullSafe(enc.getKeyRequested()));
System.out.println(" Key used : " + nullSafe(enc.getActualKeyUsed()));
System.out.println(" Algorithm used : " + nullSafe(enc.getAlgorithmUsed()));
}
private ExampleScenario23() {/* no-instantiation */}
}
How to run
Console milestones
-
RSA-2048 key generated
-
ML-KEM-768 successor created (
createRotation
) -
Encryption call shows Key requested = RSA KID but Key used = ML-KEM successor
-
Algorithm used
reportsML-KEM-768+...
confirming PQC redirect
Where next?
© 2025 Anka Technologies. All rights reserved.