Flow 2 – RSA-2048 Stream Sign / Verify (Detached JWS)
This flow walks through a streamed digital-signature round-trip with the AnkaSecure API:
- Generate a classical RSA-2048 key-pair.
- Stream-sign a document – server returns a detached JWS (General JSON).
- Stream-verify the signature against the same payload.
Key points
- Uses the streaming helpers signFileStream / verifySignatureStream, so you can sign or verify multi-gigabyte artefacts without ever loading them fully into RAM.\
- Produces a detached JWS (General JSON) — the payload stays as raw binary while the header and signature live in a tiny JSON part (no Base64 bloat, easy to cache or checksum independently).\
- Surfaces rich lifecycle telemetry in HTTP headers (key actually used, rotations, soft-limit warnings) ready for dashboards, logs or automated compliance hooks.
When to use it
- Release pipelines that still rely on classical RSA trust anchors — e.g. package repos, container registries or firmware images that must remain backwards-compatible with existing RSA-2048 verification tooling.
- Very large files — think multi-GB log bundles or VM snapshots where holding the whole payload in memory is infeasible but you still want a single authoritative signature.
- Bandwidth-sensitive or append-only storage — detached JWS keeps the payload untouched, so you can stream directly to S3/GCS/CDNs and append signatures later without rewriting the object.
Dependency — the example uses the common helper class
co.ankatech.ankasecure.sdk.examples.ExampleUtil
.
If you haven’t copied that file yet, grab it from example_util.md and place it next to the scenario sources.
Complete Java implementation
src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario2.java
/* *****************************************************************************
* FILE: ExampleScenario2.java
* ****************************************************************************/
package co.ankatech.ankasecure.sdk.examples;
import co.ankatech.ankasecure.sdk.AnkaSecureSdk;
import co.ankatech.ankasecure.sdk.model.GenerateKeySpec;
import co.ankatech.ankasecure.sdk.model.SignResult;
import co.ankatech.ankasecure.sdk.model.VerifySignatureResult;
import co.ankatech.ankasecure.sdk.util.FileIO;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileAttribute;
import java.text.MessageFormat;
import java.util.Properties;
import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;
/**
* <h2>Scenario 2 – RSA-2048 <em>Streaming</em> Sign / Verify</h2>
*
* <p>This walkthrough illustrates a detached-JWS workflow:</p>
* <ol>
* <li><strong>Key-pair generation</strong> – classical RSA-2048.</li>
* <li><strong>Streaming sign</strong> – the SDK uploads the file in chunks
* and receives a <em>detached JWS (General JSON)</em> whose
* {@code payload} is {@code null}.</li>
* <li><strong>Streaming verify</strong> – the same detached signature is
* verified against the binary payload with constant memory.</li>
* </ol>
*
* <p><b>Rule of thumb</b>:</p>
* <ul>
* <li><em>Non-streaming</em> → compact JWS / compact JWE</li>
* <li><em>Streaming</em> → detached JWS / detached JWE</li>
* </ul>
*
* <p>All artefacts are written under <kbd>temp_files/</kbd>.</p>
*
* <p><b>Implementation notes (Java 21+):</b></p>
* <ul>
* <li>File handling leverages the {@link java.nio.file.Path} API.</li>
* <li>UTF-8 is explicitly specified for deterministic encoding.</li>
* <li>Directory creation uses {@link Files#createDirectories(Path, FileAttribute[])}.</li>
* </ul>
*
* <p><b>Thread-safety:</b> the class is stateless and immutable; all variables
* are confined to the current thread.</p>
*
* @author ANKATech – Security Engineering
* @since 2.1.0
*/
public final class ExampleScenario2 {
/* ====================================================================== */
/**
* Entry-point.
*
* @param args ignored
*/
public static void main(final String[] args) {
System.out.println("===== SCENARIO 2 START =====");
System.out.println("""
Purpose : RSA-2048 key generation, detached-JWS streaming sign & verify
Artefacts : temp_files/scenario2_doc.txt (payload)
temp_files/scenario2.sig (detached JWS)
--------------------------------------------------------------""");
try {
Files.createDirectories(TEMP_DIR);
Properties props = loadProperties();
AnkaSecureSdk sdk = authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 2 failed", ex);
}
System.out.println("===== SCENARIO 2 END =====");
}
/* ====================================================================== */
/**
* Executes all steps of Scenario 2.
*
* @param sdk an authenticated {@link AnkaSecureSdk} instance
*
* @throws Exception if any operation fails
*/
private static void runScenario(final AnkaSecureSdk sdk) throws Exception {
/* 1 ── create sample document ------------------------------------- */
Path doc = TEMP_DIR.resolve("scenario2_doc.txt");
FileIO.writeUtf8(
doc,
"Scenario-2 – RSA-2048 detached-JWS streaming sign & verify.");
System.out.println("[1] Document ready -> " + doc.toAbsolutePath());
/* 2 ── generate RSA-2048 key -------------------------------------- */
String kid = "sc2_rsa_" + System.currentTimeMillis();
GenerateKeySpec rsa = new GenerateKeySpec()
.setKid(kid)
.setKty("RSA")
.setAlg("RSA-2048");
sdk.generateKey(rsa);
System.out.println("[2] RSA-2048 key created -> kid = " + kid);
/* 3 ── streaming sign (detached JWS) ------------------------------ */
Path sig = TEMP_DIR.resolve("scenario2.sig");
SignResult signMeta = sdk.signFileStream(kid, doc, sig);
System.out.println("[3] File signed -> " + sig.toAbsolutePath());
printSignMeta(signMeta);
/* 4 ── streaming verify ------------------------------------------ */
VerifySignatureResult verifyMeta = sdk.verifySignatureStream(doc, sig);
System.out.println(MessageFormat.format(
"[4] Signature valid : {0}", verifyMeta.isValid()));
printVerifyMeta(verifyMeta);
System.out.println(verifyMeta.isValid()
? "SUCCESS – signature verified."
: "FAILURE – signature verification failed.");
}
/**
* Private constructor prevents instantiation.
*/
private ExampleScenario2() {
/* utility class – no instantiation */
}
}
How to run
Console milestones:
-
RSA-2048 key creation (
kid = sc2_rsa_<timestamp>
) -
Detached-JWS stream-sign →
scenario2.sig
-
Streaming verify → SUCCESS confirmation