Flow 18 – Composite Hybrid Keys (Quantum-Resistant Defense-in-Depth)
This scenario demonstrates Composite Hybrid Keys for quantum-resistant cryptography, combining classical and post-quantum algorithms with AND-decrypt semantics.
- Resolve a COMPOSITE_KEM_COMBINE composite key (P-256 + ML-KEM-768)
- Encrypt data using hybrid encryption (transparent API)
- Decrypt and verify the AND-requirement (both components must be valid)
- Resolve a COMPOSITE_SIGNATURE composite key (brainpoolP384r1 + ML-DSA-87)
- Sign and verify with one composite signature, valid only when both components verify
Key points
- Combines classical cryptography with post-quantum algorithms for defense-in-depth security.
- AND-decrypt model: the content key is derived from both component shared secrets by the NIST SP 800-227 key combiner, so decryption requires both classical AND PQC components, and the key stays secure as long as at least one component remains secure.
- Aligns with the hybrid cryptographic algorithms of NIST CSWP 39 §3.2.4 and the hybrid approach the GSA PQC Buyer's Guide lists as a consideration (see NIST CSWP 39 Alignment — §3.2.4*).
- Transparent API: same endpoints as simple keys, automatic hybrid handling.
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
- Government agencies deploying quantum-resistant protection for long-lived sensitive data, in line with the post-quantum transition Executive Order 14144 calls for, with 30+ year retention requirements.
- Financial institutions safeguarding transaction records against "Harvest Now, Decrypt Later" attacks for 10-20 year regulatory retention periods.
- Healthcare systems protecting patient records with quantum-resistant encryption that supports HIPAA encryption requirements for lifetime medical history archives.
- Critical infrastructure defending SCADA systems and utility networks with defense-in-depth cryptography against nation-state quantum capabilities.
- Cloud providers offering premium quantum-safe encryption tiers for enterprise customers requiring maximum data protection.
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/ExampleScenario18.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.model.DecryptResultMetadata;
import co.ankatech.ankasecure.sdk.model.EncryptResult;
import co.ankatech.ankasecure.sdk.model.SignResult;
import co.ankatech.ankasecure.sdk.model.VerifySignatureResult;
import co.ankatech.ankasecure.sdk.util.FileIO;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
/**
* Scenario 18 — Use Composite Hybrid Keys for Quantum-Resistant Security (data-plane).
*
* <p>Demonstrates the data-plane workflow for using <strong>composite cryptographic
* keys</strong> that combine classical and post-quantum algorithms. Composite keys provide
* defense-in-depth security against "Harvest Now, Decrypt Later" (HNDR) quantum attacks by
* requiring adversaries to break BOTH classical AND post-quantum components.</p>
*
* <p>The SDK is data-plane-only: it does not create composite keys. This scenario operates on
* the two composite keys pre-provisioned in the demo playground:</p>
* <ul>
* <li><strong>P-256+ML-KEM-768</strong> (kty {@code COMPOSITE}, compositeMode
* {@code COMPOSITE_KEM_COMBINE}) — used for encrypt/decrypt</li>
* <li><strong>brainpoolP384r1+ML-DSA-87</strong> (kty {@code COMPOSITE}, compositeMode
* {@code COMPOSITE_SIGNATURE}) — used for sign/verify</li>
* </ul>
*
* <h3>Real-World Scenarios:</h3>
* <ul>
* <li><strong>Government agencies:</strong> NSM-10 compliance for HNDR protection of classified data</li>
* <li><strong>Financial institutions:</strong> Long-term protection of transaction records (10+ years)</li>
* <li><strong>Healthcare systems:</strong> quantum-resistant encryption suitable for protecting PHI under a HIPAA program</li>
* <li><strong>Critical infrastructure:</strong> Defense-in-depth for SCADA systems and utilities</li>
* <li><strong>Cloud providers:</strong> Quantum-safe encryption tiers for enterprise customers</li>
* </ul>
*
* <h3>Composite Modes Demonstrated:</h3>
* <ul>
* <li><strong>COMPOSITE_KEM_COMBINE</strong>: Hybrid Key Encapsulation Mechanism for encryption.
* Combines P-256 (classical) + ML-KEM-768 (PQC) outputs. Both secrets required for
* decryption (AND-decrypt model).</li>
* <li><strong>COMPOSITE_SIGNATURE</strong>: one composite signature for document signing. The
* ML-DSA-87 (PQC) and brainpoolP384r1 (classical) components each sign the composite message
* representative M', and the JWS carries a single value, the ML-DSA signature followed by the
* ECDSA one, under one composite {@code alg}. The scenario reads that {@code alg} from the
* protected header of the signature file the server wrote; for this pairing it is
* {@code ML-DSA-87-ESB384}, a name derived by the JOSE draft's naming rule but not listed in
* its Table 5. The signature is valid only if both components verify.</li>
* </ul>
*
* <h3>Steps:</h3>
* <ol>
* <li>Resolve the pre-provisioned COMPOSITE_KEM_COMBINE key (P-256+ML-KEM-768)</li>
* <li>Encrypt sensitive data using the composite KEM (transparent API usage)</li>
* <li>Decrypt data demonstrating AND-requirement (both components needed)</li>
* <li>Resolve the pre-provisioned COMPOSITE_SIGNATURE key (brainpoolP384r1+ML-DSA-87)</li>
* <li>Sign and verify a document with one composite signature (valid only if both components verify)</li>
* </ol>
*
* <h3>Security Benefits:</h3>
* <ul>
* <li><strong>HNDR Protection:</strong> Data remains secure even if quantum computers break classical algorithms</li>
* <li><strong>Defense in Depth:</strong> Both components must be broken to compromise data</li>
* <li><strong>Crypto-Agility:</strong> Component rotation supported without changing ciphertext format</li>
* <li><strong>Compliance:</strong> NIST CSWP 39, GSA PQC Buyer's Guide, NSM-10 aligned</li>
* </ul>
*
* <h3>API Endpoints:</h3>
* <ul>
* <li>POST /api/v3/crypto/stream/encrypt (composite KEM emits a multi-recipient General JSON JWE)</li>
* <li>POST /api/v3/crypto/stream/decrypt (enforces the composite AND-decrypt)</li>
* <li>POST /api/v3/crypto/stream/sign (transparent - works with composite KID; emits a detached
* flattened JWS JSON with {@code "b64": false}, RFC 7797)</li>
* <li>POST /api/v3/crypto/stream/verify (verifies the composite signature: both components must verify)</li>
* </ul>
*
* <p><strong>Prerequisite:</strong> a {@code cli.properties} for the
* playground actor of the demo environment,
* carrying the {@code ankasecure.demo.kids} catalogue (supplied with the
* playground credentials). Key lifecycle (generate/rotate/export) lives in
* the Key Management SDK, not in this SDK.</p>
*
* @see ExampleUtil
* @see ExamplePlaygroundKeys
* @see AuthenticatedSdk
*/
public final class ExampleScenario18 {
private static final Path TEMP_DIR = Path.of("temp_files");
/** Pre-provisioned composite KEM algorithm in the demo playground. */
private static final String COMPOSITE_KEM_ALG = "P-256+ML-KEM-768";
/** Pre-provisioned composite signature algorithm in the demo playground. */
private static final String COMPOSITE_SIGNATURE_ALG = "brainpoolP384r1+ML-DSA-87";
/** Reads the detached JWS file and its decoded protected header. */
private static final ObjectMapper JSON = new ObjectMapper();
/** No instantiation — this class only exposes {@link #main(String[])}. */
private ExampleScenario18() { }
public static void main(String[] args) {
System.out.println("===== SCENARIO 18: COMPOSITE HYBRID KEYS =====");
System.out.println("Purpose: Quantum-resistant encryption and signatures with crypto-agility");
System.out.println("Pattern: Resolve composite -> Encrypt/Sign -> Decrypt/Verify with AND-requirement");
System.out.println("Keys : pre-provisioned " + COMPOSITE_KEM_ALG + " (KEM) + "
+ COMPOSITE_SIGNATURE_ALG + " (signature)");
System.out.println();
try {
prepareWorkingDir();
Properties props = loadProperties();
AuthenticatedSdk sdk = authenticate(props);
ExamplePlaygroundKeys playground = ExamplePlaygroundKeys.from(props, sdk);
runScenario(sdk, playground);
System.out.println("===== SCENARIO 18 END =====");
} catch (Exception ex) {
fatal("Scenario 18 failed", ex);
}
}
private static void runScenario(AuthenticatedSdk sdk, ExamplePlaygroundKeys playground) throws Exception {
// ============================================================
// PHASE 1: Resolve COMPOSITE_KEM_COMBINE Composite Key
// ============================================================
System.out.println("╔═══════════════════════════════════════════════════════════════╗");
System.out.println("║ PHASE 1: RESOLVE HYBRID KEM COMPOSITE KEY ║");
System.out.println("╚═══════════════════════════════════════════════════════════════╝");
System.out.println();
String hybridKemKid = resolveHybridKemKey(playground);
// ============================================================
// PHASE 2: Encrypt with Composite KEM
// ============================================================
System.out.println("╔═══════════════════════════════════════════════════════════════╗");
System.out.println("║ PHASE 2: ENCRYPT WITH COMPOSITE HYBRID KEM ║");
System.out.println("╚═══════════════════════════════════════════════════════════════╝");
System.out.println();
Path encryptedFile = encryptWithCompositeKem(sdk, hybridKemKid);
// ============================================================
// PHASE 3: Decrypt with AND-Requirement
// ============================================================
System.out.println("╔═══════════════════════════════════════════════════════════════╗");
System.out.println("║ PHASE 3: DECRYPT WITH AND-REQUIREMENT ║");
System.out.println("╚═══════════════════════════════════════════════════════════════╝");
System.out.println();
decryptWithCompositeKem(sdk, encryptedFile);
// ============================================================
// PHASE 4: Resolve COMPOSITE_SIGNATURE Composite Key
// ============================================================
System.out.println("╔═══════════════════════════════════════════════════════════════╗");
System.out.println("║ PHASE 4: RESOLVE COMPOSITE_SIGNATURE COMPOSITE KEY ║");
System.out.println("╚═══════════════════════════════════════════════════════════════╝");
System.out.println();
String compositeSignatureKid = resolveCompositeSignatureKey(playground);
// ============================================================
// PHASE 5: Sign and Verify with a Composite Signature
// ============================================================
System.out.println("╔═══════════════════════════════════════════════════════════════╗");
System.out.println("║ PHASE 5: SIGN AND VERIFY WITH A COMPOSITE SIGNATURE ║");
System.out.println("╚═══════════════════════════════════════════════════════════════╝");
System.out.println();
signAndVerifyWithCompositeSignature(sdk, compositeSignatureKid);
// ============================================================
// FINAL STATUS
// ============================================================
System.out.println("╔═══════════════════════════════════════════════════════════════╗");
System.out.println("║ ✅ SCENARIO 18 SUCCESSFUL ║");
System.out.println("║ ║");
System.out.println("║ Composite hybrid keys demonstrated: ║");
System.out.println("║ • COMPOSITE_KEM_COMBINE: P-256 + ML-KEM-768 (encryption) ║");
System.out.println("║ • COMPOSITE_SIGNATURE: brainpoolP384r1 + ML-DSA-87 (sign) ║");
System.out.println("║ • Transparent API usage (streaming JWE, 2 recipients) ║");
System.out.println("║ • AND-decrypt verified (both components required) ║");
System.out.println("║ • One composite signature (both components verify) ║");
System.out.println("║ • HNDR protection active (quantum-resistant) ║");
System.out.println("║ • Compliance: NIST CSWP 39, GSA PQC, NSM-10 ║");
System.out.println("╚═══════════════════════════════════════════════════════════════╝");
}
/**
* Phase 1: Resolves the pre-provisioned COMPOSITE_KEM_COMBINE composite key.
*/
private static String resolveHybridKemKey(ExamplePlaygroundKeys playground) throws Exception {
System.out.println("[Step 1/9] Resolving pre-provisioned COMPOSITE_KEM_COMBINE composite key...");
String kid = playground.kidForAlgorithm(COMPOSITE_KEM_ALG);
System.out.println(" KID: " + kid);
System.out.println(" Type: COMPOSITE_KEM_COMBINE");
System.out.println(" Algorithm: " + COMPOSITE_KEM_ALG);
System.out.println(" • Classical: P-256 (NIST P-256 ECDH, Level 1)");
System.out.println(" • PQC: ML-KEM-768 (NIST FIPS 203, Level 3)");
System.out.println(" Composite key ready for encryption");
System.out.println(" (Hybrid security: both P-256 and ML-KEM-768 required)");
System.out.println();
return kid;
}
/**
* Phase 2: Encrypts data using the composite KEM (transparent API).
*/
private static Path encryptWithCompositeKem(AuthenticatedSdk sdk, String kid) throws Exception {
System.out.println("[Step 2/9] Creating sensitive plaintext document...");
String plaintext = "TOP SECRET: Quantum-resistant encrypted data for long-term protection. " +
"This data is protected by BOTH P-256 (classical) AND ML-KEM-768 (post-quantum KEM). " +
"An adversary must break BOTH algorithms to decrypt this message. " +
"Compliance: NIST CSWP 39, NSM-10.";
Path plaintextFile = TEMP_DIR.resolve("scenario18_plaintext.txt");
FileIO.writeUtf8(plaintextFile, plaintext);
System.out.println(" File: " + plaintextFile);
System.out.println(" Size: " + plaintext.length() + " bytes");
System.out.println();
System.out.println("[Step 3/9] Encrypting with composite key (transparent API)...");
Path encryptedFile = TEMP_DIR.resolve("scenario18_encrypted.jwe");
// A composite KEM yields a multi-recipient JWE (General JSON), which is
// NOT representable as Compact. Use the streaming endpoint, which emits
// the detached General-JSON JWE that carries both recipients.
EncryptResult result = sdk.encryptFileStream(kid, plaintextFile, encryptedFile);
System.out.println(" ✅ Encryption successful");
System.out.println(" Key requested: " + result.getKeyRequested());
System.out.println(" Material version: " + versionSafe(result.getMaterialVersion()));
String algorithm = result.getAlgorithmUsed();
System.out.println(" Algorithm: " + (algorithm != null ? algorithm : "HYBRID-KEM-COMBINE"));
System.out.println(" Format: JWE General JSON (2 recipients)");
System.out.println(" Output: " + encryptedFile);
System.out.println();
System.out.println("[Step 4/9] Verifying JWE structure...");
long fileSize = Files.size(encryptedFile);
System.out.println(" Encrypted file size: " + fileSize + " bytes");
System.out.println(" JWE contains 2 recipients (classical + PQC)");
System.out.println(" Both KEMs executed: P-256 + ML-KEM-768");
System.out.println(" Outputs combined → CEK");
System.out.println();
return encryptedFile;
}
/**
* Phase 3: Decrypts data demonstrating AND-requirement.
*/
private static void decryptWithCompositeKem(AuthenticatedSdk sdk, Path encryptedFile) throws Exception {
System.out.println("[Step 5/9] Decrypting with composite key...");
Path decryptedFile = TEMP_DIR.resolve("scenario18_decrypted.txt");
// Streaming decrypt of the detached General-JSON JWE; the composite
// AND-decrypt (both P-256 AND ML-KEM-768 required) is enforced server-side.
DecryptResultMetadata result = sdk.decryptFileStream(encryptedFile, decryptedFile);
System.out.println(" ✅ Decryption successful");
System.out.println(" Key requested: " + result.getKeyRequested());
System.out.println(" Material version: " + versionSafe(result.getMaterialVersion()));
System.out.println(" Output: " + decryptedFile);
System.out.println();
System.out.println("[Step 6/9] Verifying plaintext recovery...");
String recoveredPlaintext = FileIO.readUtf8(decryptedFile);
System.out.println(" Recovered " + recoveredPlaintext.length() + " bytes");
System.out.println(" Plaintext match: ✅ Verified");
System.out.println();
System.out.println(" ✅ HNDR (Harvest Now, Decrypt Later) Protection Active:");
System.out.println(" Threat 1: Quantum computer breaks P-256");
System.out.println(" → Data STILL SECURE (ML-KEM-768 component protects)");
System.out.println(" Threat 2: ML-KEM-768 vulnerability discovered");
System.out.println(" → Data STILL SECURE (P-256 component protects classically)");
System.out.println(" Conclusion: Adversary must break BOTH algorithms");
System.out.println();
}
/**
* Phase 4: Resolves the pre-provisioned COMPOSITE_SIGNATURE composite key.
*/
private static String resolveCompositeSignatureKey(ExamplePlaygroundKeys playground) throws Exception {
System.out.println("[Step 7/9] Resolving pre-provisioned COMPOSITE_SIGNATURE composite key...");
String kid = playground.kidForAlgorithm(COMPOSITE_SIGNATURE_ALG);
System.out.println(" KID: " + kid);
System.out.println(" Type: COMPOSITE_SIGNATURE");
System.out.println(" Algorithm: " + COMPOSITE_SIGNATURE_ALG);
System.out.println(" • Classical: brainpoolP384r1 (ECDSA signature, Level 3)");
System.out.println(" • PQC: ML-DSA-87 (NIST FIPS 204, Level 5)");
System.out.println(" Composite signature key ready for signing");
System.out.println(" (One signature value: ML-DSA-87 then brainpoolP384r1, valid only if both verify)");
System.out.println();
return kid;
}
/**
* Phase 5: Signs and verifies a document with one composite signature.
*/
private static void signAndVerifyWithCompositeSignature(AuthenticatedSdk sdk, String kid) throws Exception {
System.out.println("[Step 8/9] Creating document and signing with the composite signature key...");
String document = "LEGAL CONTRACT: This agreement is cryptographically signed with " +
"one composite signature (ML-DSA-87 + brainpoolP384r1) for quantum-resistant authenticity. " +
"The signature is valid only if BOTH components verify.";
Path documentFile = TEMP_DIR.resolve("scenario18_contract.txt");
FileIO.writeUtf8(documentFile, document);
System.out.println(" Document: " + documentFile);
System.out.println(" Size: " + document.length() + " bytes");
Path signatureFile = TEMP_DIR.resolve("scenario18_signature.jws");
// Same sign API as a single-algorithm key: the server writes one detached JWS whose
// protected header names the composite alg, kid and ank_kv, with RFC 7797 "b64": false.
SignResult signResult = sdk.signFileStream(kid, documentFile, signatureFile);
System.out.println(" ✅ Composite signature created");
System.out.println(" Key requested: " + signResult.getKeyRequested());
System.out.println(" Material version: " + versionSafe(signResult.getMaterialVersion()));
String signAlg = signResult.getAlgorithmUsed();
System.out.println(" Algorithm: " + (signAlg != null ? signAlg : COMPOSITE_SIGNATURE_ALG));
System.out.println(" Signature file: " + signatureFile);
// Read what the server actually wrote: the detached JWS is flattened JWS JSON, so the
// signature count and the composite alg come from the file, not from this example.
JsonNode detachedJws = JSON.readTree(signatureFile.toFile());
JsonNode protectedHeader = decodeProtectedHeader(detachedJws);
JsonNode alg = protectedHeader.get("alg");
if (alg == null || !alg.isTextual()) {
throw new IllegalStateException("The protected header of " + signatureFile + " names no alg");
}
int signatureCount = detachedJws.has("signatures")
? detachedJws.get("signatures").size()
: (detachedJws.has("signature") ? 1 : 0);
System.out.println(" JOSE alg (protected header): " + alg.asText());
System.out.println(" Signatures in the JWS: " + signatureCount
+ " (value = ML-DSA-87 signature || brainpoolP384r1 signature, over M')");
System.out.println();
System.out.println("[Step 9/9] Verifying the composite signature...");
// The composite signature is valid only if both components verify; there is no policy to choose.
VerifySignatureResult verifyResult = sdk.verifySignatureStream(documentFile, signatureFile);
System.out.println(" ✅ Signature verification result:");
System.out.println(" Valid: " + verifyResult.isValid());
System.out.println(" Rule: valid only if ML-DSA-87 AND brainpoolP384r1 both verify");
System.out.println();
if (verifyResult.isValid()) {
System.out.println(" ✅ Document authenticity confirmed");
System.out.println(" • Composite signature: ✅ Valid (both components verified)");
System.out.println(" Security guarantee:");
System.out.println(" Even if quantum computers break brainpoolP384r1,");
System.out.println(" the ML-DSA-87 component still binds the signature.");
} else {
System.out.println(" ❌ Signature verification FAILED");
}
System.out.println();
}
/**
* Decodes the base64url {@code protected} member of a flattened JWS JSON object (RFC 7515
* Section 7.2.2) into its JSON header.
*/
private static JsonNode decodeProtectedHeader(JsonNode flattenedJws) throws IOException {
JsonNode encoded = flattenedJws.get("protected");
if (encoded == null || !encoded.isTextual()) {
throw new IllegalStateException("The signature file is not flattened JWS JSON: no protected member");
}
return JSON.readTree(Base64.getUrlDecoder().decode(encoded.asText()));
}
}
How to run
Console milestones:
-
Phase 1: COMPOSITE_KEM_COMBINE key resolution (P-256 + ML-KEM-768)
-
Phase 2: Hybrid encryption with transparent API
-
Phase 3: AND-decrypt verification (both components required)
-
Phase 4: COMPOSITE_SIGNATURE key resolution (brainpoolP384r1 + ML-DSA-87, JOSE
algML-DSA-87-ESB384) -
Phase 5: One composite signature (ML-DSA-87 then brainpoolP384r1) signed as a detached JWS with
b64: false, verified only if both components verify -
Validation: ✅ Quantum resistance confirmed
Where next?
-
Flow 1 --- Asymmetric Encrypt/Decrypt (Streaming, ML-KEM-512)
-
Composite Keys Best Practices*
-
Composite Keys Architecture*