Skip to content

Flow 2 – RSA-2048 Stream Sign / Verify (Detached JWS)

This flow walks through a streamed digital-signature round-trip with the AnkaSecure API:

  1. Generate a classical RSA-2048 key-pair.
  2. Stream-sign a document – server returns a detached JWS (General JSON).
  3. 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

/*
 * 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.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.Path;
import java.text.MessageFormat;
import java.util.Properties;

import static co.ankatech.ankasecure.sdk.examples.ExampleUtil.*;

/**
 * Scenario&nbsp;2 &mdash; RSA-2048 <em>Streaming</em> Sign / Verify.
 *
 * <p>This walkthrough illustrates a detached-JWS workflow:</p>
 * <ol>
 *   <li><strong>Key-pair generation</strong> &mdash; classical RSA-2048.</li>
 *   <li><strong>Streaming sign</strong> &mdash; the SDK uploads the file in chunks
 *       and receives a <em>detached JWS&nbsp;(General JSON)</em> whose
 *       {@code payload} is {@code null}.</li>
 *   <li><strong>Streaming verify</strong> &mdash; 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> &rarr; compact&nbsp;JWS / compact&nbsp;JWE</li>
 *   <li><em>Streaming</em>      &rarr; detached&nbsp;JWS / detached&nbsp;JWE</li>
 * </ul>
 *
 * <p>All artefacts are written under <kbd>temp_files/</kbd>.</p>
 *
 * <p><b>Implementation notes (Java&nbsp;21+):</b></p>
 * <ul>
 *   <li>File handling relies on the {@link java.nio.file.Path} API.</li>
 *   <li>UTF-8 is enforced explicitly for deterministic encoding.</li>
 *   <li>Directory creation delegates to {@link ExampleUtil#ensureTempDir(java.nio.file.Path)}.</li>
 * </ul>
 *
 * <p><b>Thread-safety:</b> the class is stateless and immutable; all variables
 * are confined to the current thread.</p>
 *
 * @author ANKATech Solutions Inc.
 * @since 3.0.0
 * @see ExampleUtil
 * @see AuthenticatedSdk
 */
public final class ExampleScenario2 {

    /** No instantiation &mdash; this class only exposes {@link #main(String[])}. */
    private ExampleScenario2() { }

    /**
     * Runs the RSA-2048 streaming sign/verify scenario.
     *
     * <p>Loads CLI properties, authenticates against ANKASecure&copy;,
     * 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 2 START =====");
        System.out.println("""
                Purpose :
                  * RSA-2048 streaming signature life-cycle
                  * Demonstrates detached-JWS pipeline (sign -> verify)
                Steps   :
                  1) Generate RSA-2048 key
                  2) Create sample payload
                  3) Sign payload (detached JWS)
                  4) Verify signature
                  5) Report result
                --------------------------------------------------------------""");

        try {
            ensureTempDir(TEMP_DIR);

            Properties   props = loadProperties();
            AuthenticatedSdk sdk  = authenticate(props);

            runScenario(sdk);

        } catch (Exception ex) {
            fatal("Scenario 2 failed", ex);
        }

        System.out.println("===== SCENARIO 2 END =====");
    }

    /**
     * Executes the 4-step RSA-2048 streaming sign/verify scenario.
     *
     * <ol>
     *   <li>Create sample document.</li>
     *   <li>Generate RSA-2048 signing key.</li>
     *   <li>Stream-sign to detached JWS.</li>
     *   <li>Stream-verify signature and report result.</li>
     * </ol>
     *
     * @param sdk an authenticated {@link AuthenticatedSdk} instance;
     *            must not be {@code null}
     * @throws Exception if any operation fails
     */
    private static void runScenario(final AuthenticatedSdk 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();
        sdk.generateKey(new GenerateKeySpec()
                .setKid(kid)
                .setKty("RSA")
                .setAlg("RSA-2048"));
        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.");
    }
}

How to run


mvn -q compile exec:java\
  -Dexec.mainClass="co.ankatech.ankasecure.sdk.examples.ExampleScenario2"

Console milestones:

  • RSA-2048 key creation (kid = sc2_rsa_<timestamp>)

  • Detached-JWS stream-sign → scenario2.sig

  • Streaming verify → SUCCESS confirmation


Where next?