Flow 3 – AES-256 Stream Encrypt / Decrypt (Detached JWET)
This scenario demonstrates a symmetric encryption round-trip using the streaming endpoints:
- Generate an AES-256 key (
kty="oct"
,alg="AES-256"
). - Stream-encrypt a plaintext file – server returns a detached JWET (General JSON).
- Stream-decrypt the ciphertext.
- Validate the plaintext matches byte-for-byte.
Key points
- Purely symmetric, streaming workflow—encryptFileStream / decryptFileStream push raw bytes in one direction while you read them from the other, so RAM never spikes.
- Returns a detached JWET: header and encryption parameters stay in a tiny JSON blob while the ciphertext flows as native binary—no Base64 inflation, no line-length limits.
- Shows end-to-end lifecycle telemetry (actual key used, algorithm, soft-limit warnings) that arrives in HTTP headers, ready for dashboards or automated alerting.
When to use it
- Mass-volume files – perfect for multi-gigabyte database dumps, video archives, or nightly VM images where holding everything in memory is impossible.
- Low-overhead transfers – detached JWET keeps bandwidth lean and lets you pipe encrypted data straight into S3, GCS, or object storage without re-encoding.
- Regulated workloads – AES-256 is NIST-approved and FIPS-validated; combining it with streaming endpoints satisfies strict mandates for data-at-rest & in-motion encryption while avoiding temp-file sprawl.
Shared helper —
ExampleUtil
(configuration-loading, authentication, JSON, etc.).
If you haven’t copied it yet, fetch example_util.md and place the Java file beside the scenario sources.
Complete Java implementation
src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario3.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
*/
/* *****************************************************************************
* FILE: ExampleScenario3.java
* ****************************************************************************/
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.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.*;
/**
* <h2>Scenario 3 – AES-256 <em>Streaming</em> Encrypt / Decrypt</h2>
*
* <p>This scenario demonstrates a <strong>symmetric</strong> workflow via the
* streaming APIs. In streaming mode the service returns a
* <strong>detached JWE (General JSON)</strong>: the header
* portion is delivered separately from the raw ciphertext, keeping memory
* usage constant.</p>
*
* <ol>
* <li>Generate an <code>AES-256</code> key (<code>kty="oct"</code>).</li>
* <li>Stream-encrypt a plaintext file (detached JWE).</li>
* <li>Stream-decrypt the ciphertext.</li>
* <li>Validate that the plaintext round-trips.</li>
* </ol>
*
* <p>All artefacts are written under <kbd>temp_files/</kbd>.</p>
*
* <p><b>Implementation notes (Java 21+):</b></p>
* <ul>
* <li>All filesystem operations use the {@link java.nio.file.Path} API.</li>
* <li>UTF-8 is enforced explicitly to avoid platform defaults.</li>
* <li>Directory creation relies on {@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 ExampleScenario3 {
/* ====================================================================== */
/** Entry-point. */
public static void main(final String[] args) {
System.out.println("===== SCENARIO 3 START =====");
System.out.println("""
Purpose :
* AES-256 symmetric streaming life-cycle
* Demonstrates detached-JWE pipeline (encrypt → decrypt)
Steps :
1) Generate AES-256 key
2) Create sample payload
3) Encrypt payload (detached JWE)
4) Decrypt ciphertext
5) Validate integrity
--------------------------------------------------------------""");
try {
ensureTempDir(TEMP_DIR);
Properties props = loadProperties();
AnkaSecureSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 3 failed", ex);
}
System.out.println("===== SCENARIO 3 END =====");
}
/* ====================================================================== */
/**
* Executes Scenario 3.
*
* @param sdk an authenticated {@link AnkaSecureSdk} instance
* @throws Exception if any step fails
*/
private static void runScenario(final AnkaSecureSdk sdk) throws Exception {
/* 1 ── prepare plaintext ------------------------------------------- */
Path plainFile = TEMP_DIR.resolve("scenario3_plain.txt");
FileIO.writeUtf8(plainFile,
"Scenario-3 – AES-256 streaming encryption demo.");
System.out.println("[1] Plaintext ready -> " + plainFile.toAbsolutePath());
/* 2 ── generate AES-256 key ---------------------------------------- */
String kid = "sc3_aes256_" + System.currentTimeMillis();
sdk.generateKey(new GenerateKeySpec()
.setKid(kid)
.setKty("oct")
.setAlg("AES-256"));
System.out.println("[2] Key generated -> kid = " + kid);
/* 3 ── streaming encrypt ------------------------------------------ */
Path cipherFile = TEMP_DIR.resolve("scenario3.enc");
EncryptResult encMeta = sdk.encryptFileStream(kid, plainFile, cipherFile);
System.out.println("[3] Ciphertext written -> " + cipherFile.toAbsolutePath());
printEncryptMeta(encMeta);
/* 4 ── streaming decrypt ------------------------------------------ */
Path decFile = TEMP_DIR.resolve("scenario3_dec.txt");
DecryptResultMetadata decMeta = sdk.decryptFileStream(cipherFile, decFile);
System.out.println("[4] Decrypted file -> " + decFile.toAbsolutePath());
printDecryptMeta(decMeta);
/* 5 ── validation -------------------------------------------------- */
String original = FileIO.readUtf8(plainFile);
String recovered = FileIO.readUtf8(decFile);
System.out.println(original.equals(recovered)
? "[5] Validation OK – plaintext matches."
: "[5] WARNING – plaintext mismatch!");
}
/** Utility class – no instantiation. */
private ExampleScenario3() {
/* no-instantiation */
}
}
How to run
Console milestones
- AES-256 key creation (`kid = sc3_aes256_<timestamp>`)
- Detached-JWET stream-encryption → `scenario3.enc`
- Stream-decryption → `scenario3_dec.txt`
- **Validation OK** confirming bit-perfect round-trip