Skip to content

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:

  1. Generate an RSA-2048 key capable of encrypt/decrypt.

  2. Create an ML-KEM-768 successor in one API call (createRotation).

  3. 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

mvn -q compile exec:java\
  -Dexec.mainClass="co.ankatech.ankasecure.sdk.examples.ExampleScenario23"

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 reports ML-KEM-768+... confirming PQC redirect


Where next?

© 2025 Anka Technologies. All rights reserved.