Flow 13 --- Runtime Algorithm-Discovery Smoke-Test
This scenario proves that your integration can adapt at runtime by discovering which algorithms are currently RECOMMENDED by the platform and then completing a full sign/verify and encrypt/decrypt round-trip without a single hard-coded algorithm name:
-
Discover the live catalog with
getSupportedAlgorithms(). -
Pick the first RECOMMENDED sign/verify algorithm and the first RECOMMENDED encrypt/decrypt algorithm that meet strict PQC filters (security level & dual-standard).
-
Resolve the pre-provisioned keys for both algorithms.
-
Compact-JWS sign → verify a sample document.
-
Compact-JWE encrypt → decrypt the same document.
-
Print rich server metadata for every step.
-
Confirm that the decrypted plaintext matches the original.
Key points
Absolutely no brittle constants -- works even if tomorrow's recommended set changes.
Demonstrates
getSupportedAlgorithms()plus "patch-free" algorithm selection.Covers both PQC signing (level 5) and PQC encryption (level 3).
Drops human-readable artefacts in
temp_files/for audits and demos.
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. - Data-plane only. Like every flow example, these never import keystores or perform any key-lifecycle operation.
When to use it
-
Smoke tests & CI gates -- guarantee your code survives future algorithm rotations.
-
Long-lived integrations -- auto-negotiate the most secure option instead of shipping updates.
-
Crypto posture reviews -- show auditors that you honour platform guidance in real time.
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/ExampleScenario13.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.*;
import co.ankatech.ankasecure.sdk.util.FileIO;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
import static co.ankatech.ankasecure.sdk.model.AlgorithmInfo.Category.POST_QUANTUM;
import static co.ankatech.ankasecure.sdk.model.AlgorithmInfo.Status.RECOMMENDED;
/**
* Scenario 13 — Runtime Discovery of PQC Algorithms.
*
* <p>This scenario discovers two platform-recommended <em>post-quantum</em>
* algorithms at runtime, filtered by <strong>exact</strong> security levels
* and the dual-standards requirement <q>NIST and ENISA</q>:</p>
* <ol>
* <li>Select the first PQC signing algorithm with
* <code>securityLevel 5</code>.</li>
* <li>Select the first PQC encryption algorithm with
* <code>securityLevel 3</code>.</li>
* <li>Resolve pre-provisioned keys for the discovered algorithms and exercise
* Compact JWS / Compact JWE helpers (the SDK is data-plane-only — it does
* not create keys).</li>
* <li>Validate round-trip integrity and print verbose metadata.</li>
* </ol>
*
* @author ANKATech Solutions Inc.
* @since 3.0.0
* @see ExampleUtil
* @see ExamplePlaygroundKeys
* @see AuthenticatedSdk
*/
public final class ExampleScenario13 {
/** No instantiation — this class only exposes {@link #main(String[])}. */
private ExampleScenario13() { }
/**
* Runs the runtime PQC algorithm discovery 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 13 START =====");
System.out.println("""
Purpose :
* Discover PQC signing & encryption algorithms with strict filters.
* Resolve pre-provisioned keys for the discovered algorithms.
* Perform compact JWS sign/verify and compact JWE encrypt/decrypt.
--------------------------------------------------------------""");
try {
prepareWorkingDir();
Properties props = loadProperties();
AuthenticatedSdk sdk = authenticate(props);
ExamplePlaygroundKeys playground = ExamplePlaygroundKeys.from(props, sdk);
runScenario(sdk, playground);
} catch (Exception ex) {
fatal("Scenario 13 failed", ex);
}
System.out.println("===== SCENARIO 13 END =====");
}
/* ====================================================================== */
/** Executes discovery, key resolution, and validation. */
private static void runScenario(final AuthenticatedSdk sdk,
final ExamplePlaygroundKeys playground) throws Exception {
/* 1 – discover algorithms -------------------------------------- */
List<AlgorithmInfo> algorithms = sdk.getSupportedAlgorithms();
AlgorithmInfo signAlg = algorithms.stream()
.filter(a -> a.getStatus() == RECOMMENDED)
.filter(a -> a.getCategory() == POST_QUANTUM)
.filter(a -> Integer.valueOf(5).equals(a.getSecurityLevel()))
.filter(a -> supports(a, "sign", "verify"))
.filter(a -> a.getStandards().containsAll(Set.of("NIST", "ENISA")))
.findFirst()
.orElseThrow(() ->
new IllegalStateException("No PQC signing algorithm level 5 (NIST & ENISA) found."));
AlgorithmInfo encAlg = algorithms.stream()
.filter(a -> a.getStatus() == RECOMMENDED)
.filter(a -> a.getCategory() == POST_QUANTUM)
.filter(a -> Integer.valueOf(3).equals(a.getSecurityLevel()))
.filter(a -> supports(a, "encrypt", "decrypt"))
.filter(a -> a.getStandards().containsAll(Set.of("NIST", "ENISA")))
.findFirst()
.orElseThrow(() ->
new IllegalStateException("No PQC encryption algorithm level 3 (NIST & ENISA) found."));
System.out.println("[1] PQC signing algorithm : " + signAlg.getAlg());
System.out.println("[2] PQC encryption algorithm : " + encAlg.getAlg());
/* prepare sample data ------------------------------------------ */
Path plain = TEMP_DIR.resolve("scenario13_plain.txt");
FileIO.writeUtf8(
plain,
"Scenario 13 – PQC discovery smoke-test.");
System.out.println("[3] Plaintext prepared -> " + plain.toAbsolutePath());
/* 2 – Compact JWS sign / verify ------------------------------- */
String signKid = playground.kidForAlgorithm(signAlg.getAlg());
System.out.printf(" * Using pre-provisioned key -> kid=%s, alg=%s%n", signKid, signAlg.getAlg());
Path jwsFile = TEMP_DIR.resolve("scenario13.jws");
SignResult signMeta = sdk.signFileCompact(signKid, plain, jwsFile);
System.out.println("[4] JWS created -> " + jwsFile);
printSignMeta(signMeta);
VerifySignatureResult verifyMeta = sdk.verifySignature(jwsFile);
System.out.println("[5] JWS valid? -> " + verifyMeta.isValid());
printVerifyMeta(verifyMeta);
/* 3 – Compact JWE encrypt / decrypt --------------------------- */
String encKid = playground.kidForAlgorithm(encAlg.getAlg());
System.out.printf(" * Using pre-provisioned key -> kid=%s, alg=%s%n", encKid, encAlg.getAlg());
Path jweFile = TEMP_DIR.resolve("scenario13.enc");
EncryptResult encMeta = sdk.encryptFile(encKid, plain, jweFile);
System.out.println("[6] JWE created -> " + jweFile);
printEncryptMeta(encMeta);
Path decFile = TEMP_DIR.resolve("scenario13_dec.txt");
DecryptResultMetadata decMeta = sdk.decryptFile(jweFile, decFile);
System.out.println("[7] Decrypted file -> " + decFile);
printDecryptMeta(decMeta);
/* 4 – round-trip validation ---------------------------------- */
boolean match = Objects.equals(
FileIO.readUtf8(plain),
FileIO.readUtf8(decFile));
System.out.println(match
? "[✔] SUCCESS – round-trip data matches."
: "[✘] FAILURE – data mismatch!");
}
/* ====================================================================== */
private static boolean supports(final AlgorithmInfo alg, final String... ops) {
Set<String> caps = alg.getKeyOps().stream()
.map(String::toLowerCase)
.collect(Collectors.toSet());
return Stream.of(ops)
.map(String::toLowerCase)
.allMatch(caps::contains);
}
}
How to run
Console milestones
-
Platform-query returns live algorithm list
-
PQC signing algorithm (level 5) selected
-
PQC encryption algorithm (level 3) selected
-
Compact-JWS sign → verify succeeds
-
Compact-JWE encrypt → decrypt succeeds
-
SUCCESS -- decrypted plaintext matches original
Where next?
© 2025 ANKATech Solutions INC. All rights reserved.