Flow 14 --- ML-KEM-768 Key-Lifecycle Walk-through
This scenario walks through a full life-cycle for a post-quantum ML-KEM-768 key:
-
List every key currently stored in the tenant.
-
Generate a brand-new
ML-KEM-768
key (kty="ML-KEM"
). -
Export the key data (JSON).
-
Remove the key from secure storage.
-
Re-import the public-only JSON (stateless backup / restore).
Key points
End-to-end cycle: create → export → delete → import with a single class.
Uses NIST-selected ML-KEM-768 for quantum-safe key establishment.
Shows how to decrypt CLI-encrypted credentials on the fly.
All transient files are written to
temp_files/
, keeping your repo clean.
When to use it
-
Key hygiene tests --- prove you can back up / restore PQC keys without private material ever leaving disk unencrypted.
-
Disaster-recovery drills --- validate that JSON exports actually re-import after an accidental purge.
-
Compliance evidence --- demonstrate a repeatable life-cycle for auditors (FIPS / NIST PQ transition).
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/ExampleScenario14.java
/* *****************************************************************************
* FILE: ExampleScenario14.java
* Copyright © 2025 Anka Technologies.
* SPDX-License-Identifier: MIT
* -----------------------------------------------------------------------------
* Scenario 14 – ML-KEM-768 Key-Lifecycle Walk-through
* -----------------------------------------------------------------------------
* 1) List all existing keys.
* 2) Generate a brand-new ML-KEM-768 key.
* 3) Export that key’s metadata to JSON.
* 4) Remove the key from secure storage.
* 5) Re-import the public-only JSON (demonstrates stateless backup/restore).
*
* All artefacts are stored under <temp_files/>.
* ****************************************************************************/
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.GenerateKeySpec;
import co.ankatech.ankasecure.sdk.model.ImportKeySpec;
import com.google.gson.*;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Type;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.MessageFormat;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.authenticate;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.loadProperties;
/** Scenario 14 – ML-KEM-768 key life-cycle demo (list, export, delete, import). */
public final class ExampleScenario14 {
private static final Path TMP = Paths.get("temp_files");
/* ------------------------------------------------------------------ */
public static void main(String[] args) {
System.out.println("===== SCENARIO 14 START =====");
System.out.println("""
Purpose :
* Showcase full key-life-cycle operations on an ML-KEM-768 key.
Steps :
1) List existing keys
2) Generate ML-KEM-768
3) Export key metadata
4) Remove key
5) Re-import public-only JSON
--------------------------------------------------------------""");
try {
ensureTempDir(TMP);
Properties props = loadProperties();
AnkaSecureSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 14 failed", ex);
}
System.out.println("===== SCENARIO 14 END =====");
}
/* ------------------------------------------------------------------ */
private static void runScenario(final AnkaSecureSdk sdk) {
/* *****************************************************************************
* FILE: ExampleScenario14.java
* Copyright © 2025 Anka Technologies.
* SPDX-License-Identifier: MIT
* ---------------------------------------------------------------------------
* Scenario 14 – ML-KEM-768 Key-Lifecycle Walk-through
* ---------------------------------------------------------------------------
* 1) List all existing keys.
* 2) Generate a brand-new ML-KEM-768 key.
* 3) Export that key’s metadata to JSON.
* 4) Remove the key from secure storage.
* 5) Re-import the public-only JSON (stateless backup / restore demo).
*
* All artefacts are stored under <temp_files/>.
* ****************************************************************************/
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.GenerateKeySpec;
import co.ankatech.ankasecure.sdk.model.ImportKeySpec;
import com.google.gson.*;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
/**
* <h2>Scenario 14 – ML-KEM-768 Key-Lifecycle Demonstration</h2>
*
* <p>This scenario illustrates a complete key-lifecycle for an
* <strong>ML-KEM-768</strong> key via ANKASecure’s REST API:</p>
* <ol>
* <li>List all keys currently stored.</li>
* <li>Generate a new ML-KEM-768 key.</li>
* <li>Export its public metadata as JSON.</li>
* <li>Delete the key.</li>
* <li>Restore the key by re-importing the public-only JSON.</li>
* </ol>
*
* <p><b>Implementation notes (Java 21+):</b></p>
* <ul>
* <li>All filesystem access is performed via the {@link java.nio.file.Path} API.</li>
* <li>UTF-8 encoding is specified explicitly.</li>
* <li>JSON (de)serialisation uses <a href="https://github.com/google/gson">Gson</a>
* with a custom adapter for {@link ZonedDateTime}.</li>
* </ul>
*
* @author ANKATech – Security Engineering
*/
public final class ExampleScenario14 {
/** Working directory for scenario artefacts. */
private static final Path TEMP_DIR = Path.of("temp_files");
/* ====================================================================== */
/** Entry-point. */
public static void main(final String[] args) {
System.out.println("===== SCENARIO 14 START =====");
try {
ensureTempDir(TEMP_DIR);
Properties props = loadProperties();
AnkaSecureSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 14 failed", ex);
}
System.out.println("===== SCENARIO 14 END =====");
}
/* ====================================================================== */
/** Executes the demonstration steps. */
private static void runScenario(final AnkaSecureSdk sdk) throws Exception {
/* 1 ── list all keys -------------------------------------------- */
System.out.println("[1] Existing keys:");
System.out.println(sdk.listKeys());
/* 2 ── generate ML-KEM-768 key --------------------------------- */
String kid = "sc14_kem768_" + System.currentTimeMillis();
sdk.generateKey(new GenerateKeySpec()
.setKid(kid)
.setKty("ML-KEM")
.setAlg("ML-KEM-768"));
System.out.println("[2] Key generated -> kid = " + kid);
/* 3 ── export metadata ----------------------------------------- */
Path keyJson = TEMP_DIR.resolve("sc14_key.json");
sdk.exportKey(kid, keyJson);
System.out.println("[3] Key metadata exported -> " + keyJson.toAbsolutePath());
/* 4 ── delete key ---------------------------------------------- */
sdk.removeKey(kid);
System.out.println("[4] Key removed -> kid = " + kid);
/* 5 ── re-import public-only JSON ------------------------------ */
ImportKeySpec publicOnly = readKey(keyJson)
.setKid(kid) // restore under same identifier
.setPrivateKey(null); // ensure no private component
sdk.importKey(publicOnly);
System.out.println("[5] Public key re-imported -> kid = " + kid);
}
/* ====================================================================== */
/** Reads an exported key JSON file into an {@link ImportKeySpec}. */
private static ImportKeySpec readKey(final Path json) throws IOException {
try (var reader = Files.newBufferedReader(json, StandardCharsets.UTF_8)) {
Gson gson = new GsonBuilder()
.disableHtmlEscaping()
.registerTypeAdapter(
ZonedDateTime.class,
new JsonSerializer<ZonedDateTime>() {
@Override
public JsonElement serialize(
ZonedDateTime src, Type t, JsonSerializationContext ctx) {
return new JsonPrimitive(
src.format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
}
})
.registerTypeAdapter(
ZonedDateTime.class,
new JsonDeserializer<ZonedDateTime>() {
@Override
public ZonedDateTime deserialize(
JsonElement el, Type t, JsonDeserializationContext ctx)
throws JsonParseException {
return ZonedDateTime.parse(
el.getAsString(), DateTimeFormatter.ISO_OFFSET_DATE_TIME);
}
})
.create();
return gson.fromJson(reader, ImportKeySpec.class);
}
}
/* ====================================================================== */
/** Prints warnings, if any, in a consistent format. */
private static void printWarnings(final List<String> warnings) {
if (warnings != null && !warnings.isEmpty()) {
System.out.println(" * Warnings:");
warnings.forEach(w -> System.out.println(" * " + w));
}
}
/** Returns a printable representation, substituting <code>(none)</code> when blank. */
private static String nullSafe(final String s) {
return (s == null || s.isBlank()) ? "(none)" : s;
}
/**
* Private constructor prevents instantiation.
*/
private ExampleScenario14() {
/* utility class – no instantiation */
}
}
How to run
Console milestones
-
Existing-key inventory dump
-
ML-KEM-768 key creation
-
JSON export →
sc14_key.json
-
Key removal confirmation
-
Public-only JSON re-import (SUCCESS)
Where next?
-
Flow 13 --- RSA-2048 ➜ ML-KEM-768 Migration (PKCS#12 Import)
-
Flow 15 --- Utility-Stream - ML-DSA-87 Sign / Verify (Streaming)
© 2025 Anka Technologies. All rights reserved.