Flow 14 --- In-Memory JWE / JWS Quick-start
This scenario runs a 100 % file-less round-trip using two post-quantum algorithms:
-
Resolve the pre-provisioned
HQC-128key for encryption/decryption. -
Resolve the pre-provisioned
SLH-DSA-SHA2-128Skey for signing/verification. -
Encrypt a UTF-8 message → Compact JWE (all in RAM).
-
Decrypt the token back to bytes.
-
Sign the same bytes → Compact JWS.
-
Verify the signature, print rich metadata, and confirm the plaintext still matches.
Key points
Zero I/O: Every artefact (keys, tokens, plaintext) lives only in memory.
Uses modern post-quantum algorithms (HQC-128 & SLH-DSA-SHA2-128S).
Shows the lightweight
encrypt()/decrypt()andsign()/verifySignature()helpers that return tokens directly.Ideal as a boiler-plate for micro-services, lambdas, or event pipelines.
Prerequisites
The flow examples are data-plane only. They never create, rotate, or delete keys — they resolve pre-provisioned playground keys and operate on them. Before running any flow example you must:
- Provision a fresh
demo-cliplayground. Use theankasecure-demo-provisioningtool to provision thedemo-cliplayground. This seeds the cryptographic keys the examples operate on and thecli-reference@demo-cliactor that holds capability grants on them. - Use the emitted
cli.properties. The provisioning tool writes acli.propertiesfile that carries theankasecure.demo.kidscatalogue line — the comma-separated list of provisioned key ids, in YAML file order. The examples load this file to discover which keys exist. - Authenticate as
cli-reference@demo-cli. Authenticate the SDK as thecli-reference@demo-cliactor — the all-operations actor of thedemo-cliplayground — so the resolved keys carry the capability grants each operation needs.
Key selection in the examples is by algorithm or by exact name:
kidForAlgorithm(alg)returns a pre-provisioned key id matching the requested algorithm — used by the single-key operation flows.requireKid(name)asserts that an exact, named cross-kid endpoint is present in theankasecure.demo.kidscatalogue — used by the cross-kid REENCRYPT / RESIGN flows that must operate on a specific granted source/target pair.
If cli.properties is missing the ankasecure.demo.kids line, the examples fail fast with a clear message instructing you to (re-)provision the demo-cli playground — they will not silently fall back.
PKCS#7 / CMS examples (Flow 19 & Flow 20)
The PKCS#7 interop examples operate on a packaged, non-sensitive CMS EnvelopedData fixture — you do not supply a PKCS#7 file:
- Fixture:
src/main/resources/pkcs7/enveloped-data-sample.p7m, loaded from the classpath byPkcs7ExampleFixture. It is a single-recipient, zero-signer EnvelopedData artifact from the QA test signer; it carries no private key and no secret. - Flow 19 (analysis) needs no key. Structural analysis (
analyzePkcs7/analyzePkcs7Stream) inspects the CMS envelope metadata only, so it runs with no decryption key and no extra configuration. - Flow 20 (conversion) needs a pre-provisioned recipient key. Converting EnvelopedData to JWE requires the platform to decrypt the envelope, so it needs the recipient's private key referenced by the
pkcs7.decryptionKidproperty incli.properties. That key is matched by issuer DN + serial number and is imported by a control-plane step (outside the data-plane SDK); until it is provisioned, Flow 20's conversion calls fail at the server while Flow 19 still runs. The calling actor also needs the in-placeREENCRYPTgrant on that kid, requested with the kid twice (assetKids: [kid, kid]) and stored as[kid]: a conversion is authorized byREENCRYPT/RESIGNgrants, never byDECRYPT, and no wildcardREENCRYPTgrant exists. - Data-plane only. Like every flow example, these never import keystores or perform any key-lifecycle operation.
When to use it
-
High-throughput services that must avoid disk latency or sandboxed file-system access.
-
Stateless functions (FaaS) or message brokers where tokens flow through headers or payloads.
-
Security demos / smoke tests proving that PQC algorithms work end-to-end without touching the HDD/SSD.
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
/*
* 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.
*/
package co.ankatech.ankasecure.sdk.examples;
import co.ankatech.ankasecure.sdk.AuthenticatedSdk;
import co.ankatech.ankasecure.sdk.exception.AnkaSecureSdkException;
import co.ankatech.ankasecure.sdk.model.*;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
/**
* Scenario 14 — In-Memory Post-Quantum Crypto (Compact JWE/JWS).
*
* <p>This scenario performs an <em>entirely file-less</em> encryption → decryption
* and signing → verification cycle with post-quantum algorithms:</p>
* <ol>
* <li>Resolve a pre-provisioned HQC-128 key for encryption and decryption
* (the SDK is data-plane-only — it does not create keys).</li>
* <li>Resolve a pre-provisioned SLH-DSA-SHA2-128S key for signing and verification.</li>
* <li>Encrypt a UTF-8 message into a Compact JWE token and decrypt it
* back to bytes.</li>
* <li>Sign the same bytes, producing a Compact JWS token, and verify
* that signature.</li>
* </ol>
*
* <p>All artefacts remain in memory; nothing touches the disk.</p>
*
* @see ExampleUtil
* @see ExamplePlaygroundKeys
* @see AuthenticatedSdk
*/
public final class ExampleScenario14 {
/** No instantiation — this class only exposes {@link #main(String[])}. */
private ExampleScenario14() { }
/**
* Runs the in-memory post-quantum crypto 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(final String[] args) {
System.out.println("===== SCENARIO 14 START =====");
System.out.println("""
Purpose :
* 100 % in-memory encrypt ➜ decrypt and sign ➜ verify.
* Operates on pre-provisioned playground keys.
Steps :
1) Resolve pre-provisioned HQC-128 key (encrypt/decrypt).
2) Resolve pre-provisioned SLH-DSA-SHA2-128S key (sign/verify).
3) Encrypt plaintext -> Compact JWE.
4) Decrypt Compact JWE.
5) Sign plaintext -> Compact JWS.
6) Verify Compact JWS signature.
--------------------------------------------------------------""");
try {
Properties props = loadProperties();
AuthenticatedSdk sdk = authenticate(props);
ExamplePlaygroundKeys playground = ExamplePlaygroundKeys.from(props, sdk);
runScenario(sdk, playground);
} catch (Exception ex) {
fatal("Scenario 14 failed", ex);
}
System.out.println("===== SCENARIO 14 END =====");
}
/* ====================================================================== */
/**
* Executes the complete in-memory flow on pre-provisioned keys.
*/
private static void runScenario(final AuthenticatedSdk sdk,
final ExamplePlaygroundKeys playground) throws AnkaSecureSdkException {
/* 0 ── plaintext -------------------------------------------------- */
byte[] plaintext = "Hello PQC world – Scenario 14".getBytes(StandardCharsets.UTF_8);
System.out.println("[0] Plaintext prepared (" + plaintext.length + " bytes)");
/* 1 ── resolve pre-provisioned HQC-128 key (encrypt/decrypt) ----- */
final String encKid = playground.kidForAlgorithm("HQC-128");
System.out.println("[1] Using pre-provisioned key -> kid = " + encKid);
/* 2 ── resolve pre-provisioned SLH-DSA-SHA2-128S key (sign/verify) */
final String signKid = playground.kidForAlgorithm("SLH-DSA-SHA2-128S");
System.out.println("[2] Using pre-provisioned key -> kid = " + signKid);
/* 3 ── Encrypt (Compact JWE) ------------------------------------ */
EncryptResult encRes = sdk.encrypt(encKid, plaintext);
String jwe = encRes.getJweToken();
System.out.println("[3] JWE created (length = " + jwe.length() + ")");
printEncryptMeta(encRes);
/* 4 ── Decrypt --------------------------------------------------- */
DecryptResult decRes = sdk.decrypt(jwe);
byte[] recovered = decRes.getDecryptedData();
System.out.println("[4] Decrypted text : " +
new String(recovered, StandardCharsets.UTF_8));
printDecryptMeta(decRes);
/* 5 ── Sign (Compact JWS) --------------------------------------- */
SignResult sigRes = sdk.sign(signKid, plaintext);
String jws = sigRes.getJwsToken();
System.out.println("[5] JWS created (length = " + jws.length() + ")");
printSignMeta(sigRes);
/* 6 ── Verify ---------------------------------------------------- */
VerifySignatureResult verRes = sdk.verifySignature(jws);
System.out.println("[6] Signature valid? -> " + verRes.isValid());
printVerifyMeta(verRes);
/* 7 ── Integrity check ----------------------------------------- */
boolean match = Objects.equals(
new String(plaintext, StandardCharsets.UTF_8),
new String(recovered, StandardCharsets.UTF_8));
System.out.println(match
? "SUCCESS - round-trip data matches."
: "FAILURE - data mismatch!");
}
}
How to run
Console milestones
-
HQC-128 & SLH-DSA-SHA2-128S keys resolved from the playground
-
Compact-JWE produced (string length printed)
-
Decryption returns original UTF-8 text
-
Compact-JWS produced and verified (valid = true)
-
SUCCESS -- decrypted plaintext matches original
Where next?
© 2025 ANKATech Solutions Inc. All rights reserved.