Skip to content

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:

  1. List every key currently stored in the tenant.

  2. Generate a brand-new ML-KEM-768 key (kty="ML-KEM").

  3. Export the key data (JSON).

  4. Remove the key from secure storage.

  5. 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&nbsp;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&nbsp;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

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

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?

© 2025 Anka Technologies. All rights reserved.