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
/*
* Copyright 2025 ANKATech Solutions Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* SPDX-License-Identifier: Apache-2.0
*/
/* *****************************************************************************
* FILE: ExampleScenario23.java
* ****************************************************************************/
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 =====");
System.out.println("""
Purpose :
* Provision an RSA-2048 key and rotate it to ML-KEM-768.
* Encrypt with original KID and observe successor selection.
Steps :
1) Generate RSA-2048 key
2) Rotate to ML-KEM-768 successor
3) Encrypt plaintext
--------------------------------------------------------------""");
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 ANKATech Solutions INC. All rights reserved.