Flow 10 --- ML-KEM-1024 Compact-JWE Encrypt / Decrypt (Non-Streaming)
This scenario walks through a post-quantum, non-streaming round-trip with an ML-KEM-1024 key:
-
Generate an
ML-KEM-1024
key-pair (kty="ML-KEM"
). -
Export its public metadata to a JSON file.
-
Encrypt a plaintext file → compact JWE (five Base64URL segments).
-
Decrypt the compact JWE back to plaintext.
-
Validate that the recovered data matches the original.
Key points
Uses
encryptFile( )
/decryptFile( )
helpers (entire token in memory, no streaming).Demonstrates the Compact JWE format, ideal for pasting into logs, manifests or tickets.
Shows server-supplied metadata: key actually used, algorithm, lifetime warnings.
When to use it
-
Medium-sized artefacts --- perfect for files up to ~10 MB where a single self-contained token is simpler than a multipart stream.
-
Post-quantum readiness --- ML-KEM-1024 offers NIST-selected KEM protection for data that must survive future RSA/ECC breaks.
-
Easy distribution & audit --- the compact-JWE string can be emailed, committed to Git, or embedded in JSON APIs without binary handling.
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/ExampleScenario10.java
/* *****************************************************************************
* FILE: ExampleScenario10.java
* Copyright © 2025 Anka Technologies.
* SPDX-License-Identifier: MIT
* ---------------------------------------------------------------------------
* Scenario 10 – ML-KEM-1024 Bulk Encrypt / Decrypt (Compact JWE helpers)
* ---------------------------------------------------------------------------
* 1. Generate an ML-KEM-1024 key.
* 2. Export the key’s public metadata to JSON.
* 3. Encrypt a local file → Compact JWE saved as UTF-8 text.
* 4. Decrypt that JWE back to plaintext.
* 5. Validate round-trip integrity and print rich server metadata.
*
* All transient artefacts are stored in <temp_files/>.
* ****************************************************************************/
package co.ankatech.ankasecure.sdk.examples;
import co.ankatech.ankasecure.sdk.AnkaSecureSdk;
import co.ankatech.ankasecure.sdk.model.DecryptResultMetadata;
import co.ankatech.ankasecure.sdk.model.EncryptResult;
import co.ankatech.ankasecure.sdk.model.ExportedKeySpec;
import co.ankatech.ankasecure.sdk.model.GenerateKeySpec;
import co.ankatech.ankasecure.sdk.util.FileIO;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
/**
* <h2>Scenario 10 – ML-KEM-1024 Bulk Helpers (Compact JWE)</h2>
*
* <p>This scenario demonstrates the <strong>non-streaming</strong> helper
* methods for RFC 7516 <em>Compact JWE</em> using an ML-KEM-1024
* key:</p>
* <ol>
* <li>Generate an ML-KEM-1024 key.</li>
* <li>Export its public metadata.</li>
* <li>Encrypt a plaintext file via {@link AnkaSecureSdk#encryptFile(String, Path, Path)}.</li>
* <li>Decrypt via {@link AnkaSecureSdk#decryptFile(Path, Path)}.</li>
* <li>Validate round-trip integrity.</li>
* </ol>
*
* <p><b>Implementation notes (Java 21+):</b></p>
* <ul>
* <li>All filesystem interactions use the {@link java.nio.file.Path} API.</li>
* <li>UTF-8 encoding is explicitly specified for deterministic behaviour.</li>
* <li>Temporary directories are ensured via {@link ExampleUtil#ensureTempDir(Path)}.</li>
* </ul>
*
* <p><b>Thread-safety:</b> this class is stateless and immutable.</p>
*
* @author ANKATech – Security Engineering
* @since 2.1.0
*/
public final class ExampleScenario10 {
/* ====================================================================== */
/**
* Entry-point.
*
* @param args ignored
*/
public static void main(final String[] args) {
System.out.println("===== SCENARIO 10 START =====");
System.out.println("""
Purpose :
* Demonstrate Compact JWE helpers with an ML-KEM-1024 key
* Steps: generate → export → encrypt → decrypt → validate
--------------------------------------------------------------""");
try {
ensureTempDir(TEMP_DIR);
Properties props = loadProperties();
AnkaSecureSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 10 failed", ex);
}
System.out.println("===== SCENARIO 10 END =====");
}
/* ====================================================================== */
/**
* Executes all steps of Scenario 10.
*
* @param sdk an authenticated {@link AnkaSecureSdk} instance
*
* @throws Exception if any step fails
*/
private static void runScenario(final AnkaSecureSdk sdk) throws Exception {
final String kid = "sc10_kem1024_" + System.currentTimeMillis();
Path plainFile = TEMP_DIR.resolve("scenario10_plain.txt");
Path cipherFile = TEMP_DIR.resolve("scenario10_cipher.jwe");
Path decFile = TEMP_DIR.resolve("scenario10_dec.txt");
Path exportJson = TEMP_DIR.resolve("scenario10_keydata.json");
/* 1 ── sample plaintext ---------------------------------------- */
FileIO.writeUtf8(
plainFile,
"Scenario-10 – ML-KEM-1024 non-streaming encrypt / decrypt.");
System.out.println("[1] Plaintext ready -> " + plainFile.toAbsolutePath());
/* 2 ── create ML-KEM-1024 key ---------------------------------- */
sdk.generateKey(new GenerateKeySpec()
.setKid(kid)
.setKty("ML-KEM")
.setAlg("ML-KEM-1024"));
System.out.println("[2] Key generated -> kid = " + kid);
/* 3 ── export metadata ---------------------------------------- */
ExportedKeySpec meta = sdk.exportKey(kid);
FileIO.writeUtf8(exportJson, toJson(meta));
System.out.println("[3] Metadata exported -> " + exportJson.toAbsolutePath());
/* 4 ── encrypt (Compact JWE) ---------------------------------- */
EncryptResult encMeta = sdk.encryptFile(kid, plainFile, cipherFile);
System.out.println(MessageFormat.format(
"[4] Ciphertext written -> {0}", cipherFile.toAbsolutePath()));
printEncryptMeta(encMeta);
/* 5 ── decrypt (Compact JWE) ---------------------------------- */
DecryptResultMetadata decMeta = sdk.decryptFile(cipherFile, decFile);
System.out.println(MessageFormat.format(
"[5] Decrypted file -> {0}", decFile.toAbsolutePath()));
printDecryptMeta(decMeta);
/* 6 ── validation --------------------------------------------- */
boolean match = FileIO.readUtf8(plainFile)
.equals(FileIO.readUtf8(decFile));
System.out.println(match
? "[6] SUCCESS – plaintext matches."
: "[6] FAILURE – plaintext mismatch!");
}
/**
* Private constructor prevents instantiation.
*/
private ExampleScenario10() {
/* utility class – no instantiation */
}
}
How to run
Console milestones
-
ML-KEM-1024 key generation
-
Metadata export →
scenario10_keydata.json
-
Compact-JWE encryption →
scenario10_cipher.jwe
-
Decryption →
scenario10_dec.txt
-
SUCCESS message confirming byte-perfect round-trip