Flow 1 – ML-KEM-512 Stream Encrypt / Decrypt (Detached JWET)
This scenario shows a complete post-quantum encryption round-trip with the streaming endpoints:
- Generate a PQC key-pair (
ML-KEM-512). - Export its public metadata.
- Stream-encrypt a plaintext file → detached JWET (General-JSON header + binary part).
- Stream-decrypt the ciphertext.
- Validate that the decrypted data matches the original.
Key points
- Leverages the streaming helpers encryptFileStream / decryptFileStream, letting you encrypt or decrypt multi-gigabyte files while holding only a few kB in memory.\
- Emits a detached JWET (General JSON): header + tag stay in a tiny JSON structure, the raw ciphertext streams as-is — zero Base64 expansion, ideal for direct‐to-disk or direct-to-object-store writes.\
- Illustrates a full post-quantum ML-KEM-512 life-cycle (generate key ➜ export metadata ➜ encrypt ➜ decrypt) and surfaces rich key-usage telemetry in HTTP headers so you can monitor rotations, expiry or soft-limit warnings in real time.
When to use it
- Massive datasets that must stay encrypted at rest — think nightly database dumps, genomic archives, video libraries or research data running into tens or hundreds of GB. Streaming keeps RAM flat while detached JWET avoids Base64 bloat.
- Write-once / read-seldom storage tiers — because the ciphertext is pure binary, you can pipe it straight to S3, GCS, Azure Blob or tape without post-processing; the slim JSON header is all you need to catalogue or audit the object later.
- Long-term confidentiality with quantum resilience — ML-KEM-512 protects backups and legal holds that must remain secret beyond the expected RSA/ECC break horizon, giving confidence for 10- to 20-year data-retention mandates.
Dependency — this example imports
co.ankatech.ankasecure.sdk.examples.ExampleUtil.
If you have not copied that class yet, see example-util.md.
Complete Java implementation
src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario1.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
*/
package co.ankatech.ankasecure.sdk.examples;
import co.ankatech.ankasecure.sdk.AuthenticatedSdk;
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.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
/**
* Scenario 1 — End-to-End ML-KEM-512 Life-cycle (Streaming).
*
* <p>This scenario walks through a complete post-quantum key life-cycle using
* the <strong>streaming</strong> endpoints of ANKASecure©. In streaming mode the
* service produces a <em>detached JWE</em> (General-JSON header + raw
* ciphertext stream) instead of a single compact JWE string.</p>
*
* <ol>
* <li>Generate an <code>ML-KEM-512</code> key-pair.</li>
* <li>Export its public metadata to JSON.</li>
* <li>Stream-encrypt a local file (detached JWE).</li>
* <li>Stream-decrypt the ciphertext.</li>
* <li>Validate round-trip integrity.</li>
* </ol>
*
* <p><strong>Prerequisite:</strong> a valid access-token must be present in the
* CLI configuration.</p>
*
* <p><b>Implementation notes (Java 21+):</b></p>
* <ul>
* <li>All file handling relies on the {@link java.nio.file.Path} API.</li>
* <li>UTF-8 is enforced explicitly to avoid platform-dependent defaults.</li>
* <li>Temporary artefacts are written under <kbd>temp_files/</kbd>.</li>
* </ul>
*
* <p><b>Thread-safety:</b> the class is stateless and immutable; a fresh
* {@link AuthenticatedSdk} instance is created inside {@link #main(String[])}.</p>
*
* @author ANKATech Solutions Inc.
* @since 3.0.0
* @see ExampleUtil
* @see AuthenticatedSdk
*/
public final class ExampleScenario1 {
/** No instantiation — this class only exposes {@link #main(String[])}. */
private ExampleScenario1() { }
/**
* Runs the 5-step ML-KEM-512 streaming life-cycle scenario.
*
* <p>Loads CLI properties, authenticates against ANKASecure©,
* and delegates to the scenario logic. On any unrecoverable error
* the JVM terminates via
* {@link ExampleUtil#fatal(String, Throwable)}.</p>
*
* @param args command-line arguments (ignored)
*/
public static void main(String[] args) {
System.out.println("===== SCENARIO 1 START =====");
System.out.println("""
Purpose :
* End-to-end ML-KEM-512 life-cycle in streaming mode
* Demonstrates detached-JWE pipeline (encrypt -> decrypt)
Steps :
1) Generate ML-KEM-512 key
2) Export public metadata
3) Encrypt payload (detached JWE)
4) Decrypt ciphertext
5) Validate integrity
--------------------------------------------------------------""");
try {
ensureTempDir(TEMP_DIR);
Properties props = loadProperties();
AuthenticatedSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 1 failed", ex);
}
System.out.println("===== SCENARIO 1 END =====");
}
/**
* Executes the 5-step ML-KEM-512 streaming encryption scenario.
*
* <ol>
* <li>Create plaintext file.</li>
* <li>Generate ML-KEM-512 key.</li>
* <li>Export key metadata.</li>
* <li>Stream-encrypt to detached JWE.</li>
* <li>Stream-decrypt and validate integrity.</li>
* </ol>
*
* @param sdk an authenticated {@link AuthenticatedSdk} instance;
* must not be {@code null}
* @throws Exception on any I/O or cryptographic failure
*/
private static void runScenario(final AuthenticatedSdk sdk) throws Exception {
final String kid = "sc1_kem_" + System.currentTimeMillis();
/* -- file system artefacts ----------------------------------------- */
Path plainFile = TEMP_DIR.resolve("scenario1_plain.txt");
Path encFile = TEMP_DIR.resolve("scenario1.enc");
Path decFile = TEMP_DIR.resolve("scenario1.dec");
Path exportJson = TEMP_DIR.resolve("scenario1_keydata.json");
/* 1 -- plaintext ---------------------------------------------------- */
FileIO.writeUtf8(plainFile,
"Hello Scenario-1 - streaming encryption demo!");
System.out.println("[1] Plaintext ready -> " + plainFile.toAbsolutePath());
/* 2 -- key generation ----------------------------------------------- */
sdk.generateKey(new GenerateKeySpec()
.setKid(kid)
.setKty("ML-KEM")
.setAlg("ML-KEM-512"));
System.out.println("[2] Key generated -> kid = " + kid);
/* 3 -- export metadata ---------------------------------------------- */
ExportedKeySpec exported = sdk.exportKey(kid);
FileIO.writeUtf8(exportJson, toJson(exported));
System.out.println("[3] Metadata exported -> " + exportJson.toAbsolutePath());
/* 4 -- streaming encrypt (detached JWE) ----------------------------- */
EncryptResult encMeta = sdk.encryptFileStream(kid, plainFile, encFile);
System.out.println("[4] Ciphertext written -> " + encFile.toAbsolutePath());
printEncryptMeta(encMeta);
/* 5 -- streaming decrypt -------------------------------------------- */
DecryptResultMetadata decMeta = sdk.decryptFileStream(encFile, decFile);
System.out.println("[5] Decrypted file -> " + decFile.toAbsolutePath());
printDecryptMeta(decMeta);
/* 6 -- validation --------------------------------------------------- */
String original = FileIO.readUtf8(plainFile);
String recovered = FileIO.readUtf8(decFile);
System.out.println(original.equals(recovered)
? "[6] Validation OK - plaintext matches."
: "[6] WARNING - plaintext mismatch!");
}
}
How to run
Console milestones:
-
ML-KEM-512 key creation
-
Metadata export →
scenario1_keydata.json -
Detached-JWET stream-encryption →
scenario1.enc -
Stream-decryption →
scenario1.dec -
Validation OK -- byte-perfect round-trip