Skip to content

Flow 12 --- RSA-2048 ➜ FALCON-1024 Detached-JWS Re-sign (Streaming)

This scenario performs a zero-plaintext-exposure migration from a classical RSA-2048 signature to a post-quantum FALCON-1024 signature, all with streaming helpers:

  • Generate an RSA-2048 key and stream-sign a document → detached JWS.

  • Generate a FALCON-1024 key.

  • Re-sign the existing JWS on the server (RSA → FALCON) --- no payload re-upload, no Base64 bloat.

  • Verify the new FALCON JWS in streaming mode.

  • Inspect rich metadata for every step (key actually used, algorithm, warnings).

Key points

  • Uses signFileStream → resignFileStream → verifySignatureStream for GB-scale artefacts.

  • Detached JWS keeps payload binary, avoiding Base64 overhead in transfers.

  • Proves you can upgrade to FALCON-1024 (NIST finalist) without ever exposing or re-hashing plaintext.

When to use it

  • Long-lived archives --- refresh classical RSA signatures to PQC without touching the data, ensuring future-proof authenticity.

  • Compliance pipelines --- stream re-sign terabyte data sets during nightly jobs with constant RAM.

  • Incremental hardening --- migrate gradually: keep RSA tokens for legacy consumers, add PQC FALCON tokens for forward security.

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/ExampleScenario12.java

/* *****************************************************************************
 * FILE: ExampleScenario12.java
 * Copyright © 2025 Anka Technologies.
 * SPDX-License-Identifier: MIT
 * ---------------------------------------------------------------------------
 * Scenario 12 – Streaming Re-sign RSA-2048 → FALCON-1024 (Detached JWS helpers)
 * ---------------------------------------------------------------------------
 *   1. Generate an RSA-2048 key and stream-sign a file
 *      → detached Compact JWS stored on disk.
 *   2. Generate a FALCON-1024 key.
 *   3. Stream-re-sign the payload on the server (RSA → FALCON) – no plaintext
 *      exposure to the client.
 *   4. Stream-verify the FALCON JWS and display rich server metadata.
 *
 * All transient artefacts are placed in <temp_files/>.
 * ****************************************************************************/
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.ResignResult;
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.*;

/**
 * <h2>Scenario&nbsp;12 – RSA-2048 → FALCON-1024 Streaming Re-sign
 * (Detached&nbsp;JWS)</h2>
 *
 * <p>This scenario migrates a detached JWS signature from a classical
 * RSA-2048 key to a post-quantum FALCON-1024 key, entirely on the server
 * side and therefore without requiring the client to upload the payload
 * again:</p>
 *
 * <ol>
 *   <li>Generate an RSA-2048 key and stream-sign a file.</li>
 *   <li>Generate a FALCON-1024 key.</li>
 *   <li>Re-sign the existing detached JWS on the server
 *       (RSA-2048 -> FALCON-1024).</li>
 *   <li>Stream-verify the fresh FALCON signature.</li>
 * </ol>
 *
 * <p><b>Implementation notes (Java&nbsp;21+):</b></p>
 * <ul>
 *   <li>The {@link java.nio.file.Path} API is used for all filesystem
 *       operations.</li>
 *   <li>UTF-8 encoding is specified explicitly for deterministic
 *       behaviour.</li>
 *   <li>The working directory is created via
 *       {@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 ExampleScenario12 {

    /* ====================================================================== */
    /**
     * Entry-point.
     *
     * @param args ignored
     */
    public static void main(final String[] args) {

        System.out.println("===== SCENARIO 12 START =====");
        System.out.println("""
                Purpose :
                  * Migrate a detached RSA-2048 signature to FALCON-1024
                  * Steps:
                    1) Generate RSA key & sign
                    2) Generate FALCON key
                    3) Re-sign on server
                    4) Verify new signature
                --------------------------------------------------------------""");

        try {
            ensureTempDir(TEMP_DIR);

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

            runScenario(sdk);

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

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

    /* ====================================================================== */
    /**
     * Executes all steps of Scenario&nbsp;12.
     *
     * @param sdk an authenticated {@link AnkaSecureSdk} instance
     *
     * @throws Exception if any operation fails
     */
    private static void runScenario(final AnkaSecureSdk sdk) throws Exception {

        /* Working paths --------------------------------------------------- */
        Path dataFile = TEMP_DIR.resolve("scenario12_data.txt");
        Path oldSig   = TEMP_DIR.resolve("scenario12_rsa.sig");
        Path newSig   = TEMP_DIR.resolve("scenario12_falcon.sig");

        /* 1 ── create payload & RSA-2048 key + sign ---------------------- */
        FileIO.writeUtf8(
                dataFile,
                "Scenario-12 – RSA-2048 → FALCON-1024 streaming re-sign demo.");
        System.out.println("[1] Data file ready       -> " + dataFile.toAbsolutePath());

        String oldKid = "sc12_rsa2048_" + System.currentTimeMillis();
        sdk.generateKey(new GenerateKeySpec()
                .setKid(oldKid)
                .setKty("RSA")
                .setAlg("RSA-2048"));
        System.out.println("[1] RSA-2048 key created  -> kid = " + oldKid);

        SignResult oldMeta = sdk.signFileStream(oldKid, dataFile, oldSig);
        System.out.println("[1] RSA signature stored  -> " + oldSig.toAbsolutePath());
        printSignMeta(oldMeta);

        /* 2 ── create FALCON-1024 key ----------------------------------- */
        String newKid = "sc12_falcon1024_" + System.currentTimeMillis();
        sdk.generateKey(new GenerateKeySpec()
                .setKid(newKid)
                .setKty("FALCON")
                .setAlg("FALCON-1024"));
        System.out.println("[2] FALCON-1024 key created -> kid = " + newKid);

        /* 3 ── re-sign on server ---------------------------------------- */
        ResignResult reMeta = sdk.resignFileStream(
                newKid,    // replacement key
                oldSig,    // existing detached JWS header
                dataFile,  // payload to sign
                newSig);   // output file
        System.out.println("[3] New signature written -> " + newSig.toAbsolutePath());
        printResignMeta(reMeta);

        /* 4 ── verify new signature ------------------------------------- */
        VerifySignatureResult verMeta = sdk.verifySignatureStream(dataFile, newSig);
        System.out.println(MessageFormat.format(
                "[4] Signature valid?       -> {0}", verMeta.isValid()));
        printVerifyMeta(verMeta);

        System.out.println(verMeta.isValid()
                ? "[5] SUCCESS – FALCON-1024 JWS verified."
                : "[5] FAILURE – verification failed.");
    }

    /**
     * Private constructor prevents instantiation.
     */
    private ExampleScenario12() {
        /* utility class – no instantiation */
    }
}

How to run

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

Console milestones

  • RSA-2048 key generation

  • Detached-JWS stream-sign → sc12_rsa.sig

  • FALCON-1024 key generation

  • Server-side stream re-sign → sc12_falcon.sig

  • Stream verification → SUCCESS confirmation


Where next?