Skip to content

Flow 26 – PKCS#7 to JOSE Migration

Demonstrates complete legacy cryptographic system migration: programmatically generate PKCS#7 SignedAndEnvelopedData (using Bouncy Castle), decrypt and verify it, then migrate the content to modern JOSE format (JWE) with post-quantum cryptography.

Real-World Context:

Many enterprise systems (healthcare, finance, government) use PKCS#7/CMS for secure messaging. Migrating to JOSE provides:

  • JSON compatibility: JOSE uses JSON, easier to parse than ASN.1/DER
  • Web standards: Native support in JWT libraries
  • Post-quantum ready: JOSE supports ML-KEM, ML-DSA (PKCS#7 does not)
  • Simpler tooling: Better developer experience than legacy PKCS#7

Steps:

  1. Generate legacy RSA-2048 key pair (Bouncy Castle)
  2. Create self-signed X.509 certificate
  3. Create PKCS#7 SignedData (sign plaintext with RSA)
  4. Create PKCS#7 EnvelopedData (encrypt SignedData with RSA)
  5. Write binary PKCS#7 file (SignedAndEnvelopedData)
  6. Import RSA key to AnkaSecure via PKCS#12
  7. Decrypt PKCS#7 EnvelopedData (extract SignedData)
  8. Verify PKCS#7 SignedData (extract plaintext)
  9. Generate ML-KEM-768 key for modern encryption
  10. Encrypt plaintext with JOSE (JWE format)
  11. Decrypt JOSE and validate migration success

Key Technologies:

  • PKCS#7 (Legacy): CMS SignedData + EnvelopedData with RSA-2048
  • JOSE (Modern): JWE with ML-KEM-768 post-quantum encryption
  • Migration tool: Bouncy Castle for PKCS#7 parsing and generation

API Endpoints:

  • POST /api/migration/keystores (import legacy RSA key)
  • POST /api/key-management/keys (generate ML-KEM key)
  • POST /api/crypto/stream/encrypt (JOSE encryption)
  • POST /api/crypto/stream/decrypt (JOSE decryption)

When to use:

  • Migrating healthcare systems using PKCS#7 for HL7/DICOM messaging
  • Finance industry moving from S/MIME (PKCS#7) to modern secure email
  • Government systems transitioning from legacy CMS to web-native JOSE
  • Any organization with PKCS#7 archives that need post-quantum protection

Maps to CLI commands (NEW in v3.0.0):

  • import-pkcs12 - Import PKCS#12 bundles into keystore
  • analyze-pkcs7 - Analyze PKCS#7 structure before conversion
  • convert-pkcs7 - Convert PKCS#7 SignedData/EnvelopedData to JWS/JWE

Dependency — this example requires Bouncy Castle libraries for PKCS#7 generation. It also imports co.ankatech.ankasecure.sdk.examples.ExampleUtil. See example-util.md for helper class documentation.


Complete Java Implementation

Source: src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario26.java

Note: This example is 471 lines and includes complete Bouncy Castle PKCS#7 generation code.

package co.ankatech.ankasecure.sdk.examples;

import co.ankatech.ankasecure.sdk.AuthenticatedSdk;
import co.ankatech.ankasecure.sdk.model.*;
import co.ankatech.ankasecure.sdk.util.FileIO;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.cms.*;
import org.bouncycastle.cms.jcajce.*;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaDigestCalculatorProviderBuilder;

import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.*;

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

/**
 * Scenario 26 — PKCS#7 to JOSE Migration.
 *
 * <p>Demonstrates complete legacy cryptographic system migration: programmatically generate PKCS#7
 * SignedAndEnvelopedData (using Bouncy Castle), decrypt and verify it, then migrate the content
 * to modern JOSE format (JWE) with post-quantum cryptography.</p>
 *
 * <h3>Real-World Context:</h3>
 * <p>
 * Many enterprise systems (healthcare, finance, government) use PKCS#7/CMS for secure messaging.
 * Migrating to JOSE provides:
 * </p>
 * <ul>
 *   <li><strong>JSON compatibility:</strong> JOSE uses JSON, easier to parse than ASN.1/DER</li>
 *   <li><strong>Web standards:</strong> Native support in JWT libraries</li>
 *   <li><strong>Post-quantum ready:</strong> JOSE supports ML-KEM, ML-DSA (PKCS#7 does not)</li>
 *   <li><strong>Simpler tooling:</strong> Better developer experience than legacy PKCS#7</li>
 * </ul>
 *
 * <h3>Steps:</h3>
 * <ol>
 *   <li>Generate legacy RSA-2048 key pair (Bouncy Castle)</li>
 *   <li>Create self-signed X.509 certificate</li>
 *   <li>Create PKCS#7 SignedData (sign plaintext with RSA)</li>
 *   <li>Create PKCS#7 EnvelopedData (encrypt SignedData with RSA)</li>
 *   <li>Write binary PKCS#7 file (SignedAndEnvelopedData)</li>
 *   <li>Import RSA key to AnkaSecure via PKCS#12</li>
 *   <li>Decrypt PKCS#7 EnvelopedData (extract SignedData)</li>
 *   <li>Verify PKCS#7 SignedData (extract plaintext)</li>
 *   <li>Generate ML-KEM-768 key for modern encryption</li>
 *   <li>Encrypt plaintext with JOSE (JWE format)</li>
 *   <li>Decrypt JOSE and validate migration success</li>
 * </ol>
 *
 * <h3>Key Technologies:</h3>
 * <ul>
 *   <li><strong>PKCS#7 (Legacy):</strong> CMS SignedData + EnvelopedData with RSA-2048</li>
 *   <li><strong>JOSE (Modern):</strong> JWE with ML-KEM-768 post-quantum encryption</li>
 *   <li><strong>Migration tool:</strong> Bouncy Castle for PKCS#7 parsing and generation</li>
 * </ul>
 *
 * <h3>API Endpoints:</h3>
 * <ul>
 *   <li>POST /api/migration/pkcs12 (import legacy RSA key)</li>
 *   <li>POST /api/key-management/keys (generate ML-KEM key)</li>
 *   <li>POST /api/crypto/stream/encrypt (JOSE encryption)</li>
 *   <li>POST /api/crypto/stream/decrypt (JOSE decryption)</li>
 * </ul>
 *
 * 
 */
public final class ExampleScenario26 {

    private static final Path TEMP_DIR = Path.of("temp_files");

    static {
        // Register Bouncy Castle as security provider
        Security.addProvider(new BouncyCastleProvider());
    }

    private ExampleScenario26() {
        /* static only */
    }

    public static void main(String[] args) {
        System.out.println("===== SCENARIO 26: PKCS#7 TO JOSE MIGRATION =====");
        System.out.println("Purpose: Migrate legacy PKCS#7 SignedAndEnvelopedData to modern JOSE with PQC");
        System.out.println("Pattern: Legacy RSA-2048 → Modern ML-KEM-768");
        System.out.println();

        try {
            ensureTempDir(TEMP_DIR);
            Properties props = loadProperties();
            AuthenticatedSdk sdk = authenticate(props);
            runScenario(sdk);

            System.out.println("===== SCENARIO 26 END =====");

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

    private static void runScenario(AuthenticatedSdk sdk) throws Exception {

        // ============================================================
        // PHASE 1: Generate Legacy PKCS#7 Test Data
        // ============================================================

        System.out.println("╔═══════════════════════════════════════════════════════════════╗");
        System.out.println("║  PHASE 1: GENERATE LEGACY PKCS#7 TEST DATA                   ║");
        System.out.println("╚═══════════════════════════════════════════════════════════════╝");
        System.out.println();

        Pkcs7TestData testData = generatePkcs7TestData();

        System.out.println("Legacy PKCS#7 file generated: " + testData.pkcs7File);
        System.out.println("Format: SignedAndEnvelopedData (nested structure)");
        System.out.println();

        // ============================================================
        // PHASE 2: Import RSA Key to AnkaSecure
        // ============================================================

        System.out.println("╔═══════════════════════════════════════════════════════════════╗");
        System.out.println("║  PHASE 2: IMPORT LEGACY RSA KEY                               ║");
        System.out.println("╚═══════════════════════════════════════════════════════════════╝");
        System.out.println();

        String rsaKid = importRsaKey(sdk, testData);

        System.out.println("RSA key imported to AnkaSecure: " + rsaKid);
        System.out.println();

        // ============================================================
        // PHASE 3: Decrypt and Verify PKCS#7
        // ============================================================

        System.out.println("╔═══════════════════════════════════════════════════════════════╗");
        System.out.println("║  PHASE 3: DECRYPT AND VERIFY PKCS#7                           ║");
        System.out.println("╚═══════════════════════════════════════════════════════════════╝");
        System.out.println();

        Path extractedFile = extractFromPkcs7(testData);

        String extractedPlaintext = FileIO.readUtf8(extractedFile);
        System.out.println("Extracted plaintext: \"" + extractedPlaintext + "\"");
        System.out.println("Signature verified: ✅ VALID");
        System.out.println();

        // ============================================================
        // PHASE 4: Migrate to Modern JOSE with PQC
        // ============================================================

        System.out.println("╔═══════════════════════════════════════════════════════════════╗");
        System.out.println("║  PHASE 4: MIGRATE TO MODERN JOSE WITH PQC                     ║");
        System.out.println("╚═══════════════════════════════════════════════════════════════╝");
        System.out.println();

        String kemKid = generateModernKey(sdk);

        Path joseFile = migrateToJose(sdk, kemKid, extractedFile);

        System.out.println("Migration complete!");
        System.out.println("Legacy PKCS#7 → Modern JOSE (ML-KEM-768)");
        System.out.println();

        // ============================================================
        // PHASE 5: Validate Migration
        // ============================================================

        System.out.println("╔═══════════════════════════════════════════════════════════════╗");
        System.out.println("║  PHASE 5: VALIDATE MIGRATION                                  ║");
        System.out.println("╚═══════════════════════════════════════════════════════════════╝");
        System.out.println();

        validateMigration(testData.plaintext, extractedFile, joseFile, sdk);
    }

    /**
     * Generates PKCS#7 test data with SignedAndEnvelopedData structure.
     */
    private static Pkcs7TestData generatePkcs7TestData() throws Exception {
        System.out.println("[Step 1/4] Generating RSA-2048 key pair (Bouncy Castle)...");

        KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC");
        kpg.initialize(2048, new SecureRandom());
        KeyPair rsaKp = kpg.generateKeyPair();

        System.out.println("           RSA key pair generated");
        System.out.println();

        System.out.println("[Step 2/4] Creating self-signed X.509 certificate...");

        X509Certificate cert = createSelfSignedCertificate(rsaKp, "CN=Legacy PKCS7 Demo,O=AnkaSecure,C=US");

        System.out.println("           Certificate DN: " + cert.getSubjectX500Principal().getName());
        System.out.println();

        System.out.println("[Step 3/4] Creating PKCS#7 SignedData (inner layer)...");

        byte[] plaintext = "Scenario-26: Legacy PKCS#7 migration to JOSE with ML-KEM-768.".getBytes(StandardCharsets.UTF_8);

        // Create SignedData
        CMSSignedDataGenerator signGen = new CMSSignedDataGenerator();
        signGen.addSignerInfoGenerator(
                new JcaSignerInfoGeneratorBuilder(
                        new JcaDigestCalculatorProviderBuilder().setProvider("BC").build())
                        .build(new JcaContentSignerBuilder("SHA256withRSA").setProvider("BC").build(rsaKp.getPrivate()), cert)
        );

        CMSTypedData plainMsg = new CMSProcessableByteArray(plaintext);
        CMSSignedData signedData = signGen.generate(plainMsg, true);

        System.out.println("           SignedData created (algorithm: SHA256withRSA)");
        System.out.println();

        System.out.println("[Step 4/4] Creating PKCS#7 EnvelopedData (outer layer)...");

        // Create EnvelopedData (encrypts the SignedData)
        CMSEnvelopedDataGenerator envGen = new CMSEnvelopedDataGenerator();
        envGen.addRecipientInfoGenerator(
                new JceKeyTransRecipientInfoGenerator(cert).setProvider("BC")
        );

        OutputEncryptor encryptor = new JceCMSContentEncryptorBuilder(CMSAlgorithm.AES256_CBC)
                .setProvider("BC").build();

        CMSEnvelopedData envelopedData = envGen.generate(
                new CMSProcessableByteArray(signedData.getEncoded()),
                encryptor
        );

        // Write PKCS#7 file
        Path pkcs7File = TEMP_DIR.resolve("scenario26_legacy.p7m");
        FileIO.writeBytes(pkcs7File, envelopedData.getEncoded());

        System.out.println("           EnvelopedData created (algorithm: RSA-OAEP + AES-256-CBC)");
        System.out.println("           PKCS#7 file written: " + pkcs7File);
        System.out.println();

        Pkcs7TestData result = new Pkcs7TestData();
        result.rsaKeyPair = rsaKp;
        result.certificate = cert;
        result.plaintext = plaintext;
        result.pkcs7File = pkcs7File;

        return result;
    }

    /**
     * Imports RSA key to AnkaSecure via PKCS#12.
     */
    private static String importRsaKey(AuthenticatedSdk sdk, Pkcs7TestData testData) throws Exception {
        System.out.println("[Step 5/11] Converting RSA key to PKCS#12 format...");

        String p12Password = "legacy-p12-pwd-" + System.currentTimeMillis();

        // Create PKCS#12 keystore
        KeyStore ks = KeyStore.getInstance("PKCS12");
        ks.load(null, p12Password.toCharArray());
        ks.setKeyEntry("legacy-rsa", testData.rsaKeyPair.getPrivate(), p12Password.toCharArray(),
                new Certificate[]{testData.certificate});

        // Write to byte array and Base64 encode
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ks.store(baos, p12Password.toCharArray());
        String p12Base64 = Base64.getEncoder().encodeToString(baos.toByteArray());

        System.out.println("           PKCS#12 created and Base64 encoded");
        System.out.println();

        System.out.println("[Step 6/11] Importing RSA key to AnkaSecure...");

        String rsaKid = "sc26_rsa_legacy_" + System.currentTimeMillis();

        sdk.importKeystore(new KeystoreImportSpec()
                .setKid(rsaKid)
                .setPassword(p12Password)
                .setKeystoreContent(p12Base64));

        System.out.println("           Key ID: " + rsaKid);
        System.out.println();

        return rsaKid;
    }

    /**
     * Decrypts and verifies PKCS#7 using Bouncy Castle.
     */
    private static Path extractFromPkcs7(Pkcs7TestData testData) throws Exception {
        System.out.println("[Step 7/11] Decrypting PKCS#7 EnvelopedData (outer layer)...");

        // Read PKCS#7 file
        byte[] pkcs7Bytes = FileIO.readBytes(testData.pkcs7File);

        // Parse EnvelopedData
        CMSEnvelopedData envData = new CMSEnvelopedData(pkcs7Bytes);
        Collection<RecipientInformation> recipients = envData.getRecipientInfos().getRecipients();
        RecipientInformation recipient = recipients.iterator().next();

        // Decrypt to get SignedData bytes
        byte[] signedBytes = recipient.getContent(
                new JceKeyTransEnvelopedRecipient(testData.rsaKeyPair.getPrivate()).setProvider("BC")
        );

        System.out.println("           EnvelopedData decrypted");
        System.out.println();

        System.out.println("[Step 8/11] Verifying PKCS#7 SignedData (inner layer)...");

        // Parse SignedData
        CMSSignedData sigData = new CMSSignedData(signedBytes);

        // Verify signature
        Collection<SignerInformation> signers = sigData.getSignerInfos().getSigners();
        SignerInformation signer = signers.iterator().next();

        boolean signatureValid = signer.verify(
                new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(testData.certificate)
        );

        if (!signatureValid) {
            throw new SecurityException("PKCS#7 signature verification failed");
        }

        // Extract plaintext
        CMSTypedData signedContent = sigData.getSignedContent();
        byte[] extractedPlaintext = (byte[]) signedContent.getContent();

        Path extractedFile = TEMP_DIR.resolve("scenario26_pkcs7_extracted.txt");
        FileIO.writeBytes(extractedFile, extractedPlaintext);

        System.out.println("           Signature verified: ✅ VALID");
        System.out.println("           Plaintext extracted to: " + extractedFile);
        System.out.println();

        return extractedFile;
    }

    /**
     * Generates modern ML-KEM-768 key.
     */
    private static String generateModernKey(AuthenticatedSdk sdk) throws Exception {
        System.out.println("[Step 9/11] Generating ML-KEM-768 key for modern encryption...");

        String kemKid = "sc26_kem_modern_" + System.currentTimeMillis();

        sdk.generateKey(new GenerateKeySpec()
                .setKid(kemKid)
                .setKty("ML-KEM")
                .setAlg("ML-KEM-768")
                .setKeyOps(List.of("encrypt", "decrypt")));

        System.out.println("           Key ID: " + kemKid);
        System.out.println("           Algorithm: ML-KEM-768 (NIST FIPS 203 post-quantum)");
        System.out.println();

        return kemKid;
    }

    /**
     * Migrates extracted plaintext to JOSE format.
     */
    private static Path migrateToJose(AuthenticatedSdk sdk, String kemKid, Path plaintextFile) throws Exception {
        System.out.println("[Step 10/11] Encrypting with JOSE (JWE format)...");

        Path joseFile = TEMP_DIR.resolve("scenario26_jose.enc");

        EncryptResult encMeta = sdk.encryptFileStream(kemKid, plaintextFile, joseFile);

        System.out.println("           JOSE file: " + joseFile);
        printEncryptMeta(encMeta);
        System.out.println();

        return joseFile;
    }

    /**
     * Validates migration by decrypting JOSE and comparing with original.
     */
    private static void validateMigration(byte[] originalPlaintext, Path extractedFile, Path joseFile, AuthenticatedSdk sdk) throws Exception {
        System.out.println("[Step 11/11] Validating migration...");

        // Decrypt JOSE
        Path decryptedFile = TEMP_DIR.resolve("scenario26_jose_decrypted.txt");
        DecryptResultMetadata decMeta = sdk.decryptFileStream(joseFile, decryptedFile);

        System.out.println("           JOSE decrypted");
        printDecryptMeta(decMeta);
        System.out.println();

        // Compare
        String original = new String(originalPlaintext, StandardCharsets.UTF_8);
        String pkcs7Extracted = FileIO.readUtf8(extractedFile);
        String joseDecrypted = FileIO.readUtf8(decryptedFile);

        boolean pkcs7Match = original.equals(pkcs7Extracted);
        boolean joseMatch = original.equals(joseDecrypted);

        System.out.println("Validation Results:");
        System.out.println("  • PKCS#7 extraction: " + (pkcs7Match ? "✅ VALID" : "❌ FAILED"));
        System.out.println("  • JOSE round-trip:   " + (joseMatch ? "✅ VALID" : "❌ FAILED"));
        System.out.println();

        if (pkcs7Match && joseMatch) {
            System.out.println("╔═══════════════════════════════════════════════════════════════╗");
            System.out.println("║               ✅ SCENARIO 26 SUCCESSFUL                        ║");
            System.out.println("║                                                               ║");
            System.out.println("║  Legacy PKCS#7 successfully migrated to modern JOSE:          ║");
            System.out.println("║  • PKCS#7 SignedAndEnvelopedData decrypted and verified       ║");
            System.out.println("║  • Content migrated to JOSE (JWE) with ML-KEM-768             ║");
            System.out.println("║  • Plaintext integrity maintained throughout migration        ║");
            System.out.println("║                                                               ║");
            System.out.println("║  Migration path: RSA-2048 (Legacy) → ML-KEM-768 (PQC)         ║");
            System.out.println("╚═══════════════════════════════════════════════════════════════╝");
        } else {
            System.out.println("❌ SCENARIO 26 FAILED - Validation errors detected");
        }
    }

    /**
     * Creates a self-signed X.509 certificate.
     */
    private static X509Certificate createSelfSignedCertificate(KeyPair keyPair, String dn) throws Exception {
        long now = System.currentTimeMillis();
        Date notBefore = new Date(now);
        Date notAfter = new Date(now + 365L * 24L * 60L * 60L * 1000L); // 1 year

        X500Name issuer = new X500Name(dn);
        BigInteger serial = BigInteger.valueOf(now);

        JcaX509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(
                issuer,
                serial,
                notBefore,
                notAfter,
                issuer,
                keyPair.getPublic()
        );

        ContentSigner signer = new JcaContentSignerBuilder("SHA256withRSA")
                .setProvider("BC")
                .build(keyPair.getPrivate());

        X509CertificateHolder certHolder = certBuilder.build(signer);

        return new JcaX509CertificateConverter()
                .setProvider("BC")
                .getCertificate(certHolder);
    }

    /**
     * Helper class to hold PKCS#7 test data.
     */
    private static class Pkcs7TestData {
        KeyPair rsaKeyPair;
        X509Certificate certificate;
        byte[] plaintext;
        Path pkcs7File;
    }
}

For complete 471-line implementation, see the source file at: ankasecure-sdk/src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario26.java


Running This Example

Additional Dependencies Required:

<!-- Bouncy Castle for PKCS#7 generation -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk18on</artifactId>
    <version>1.78</version>
</dependency>
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcpkix-jdk18on</artifactId>
    <version>1.78</version>
</dependency>

Compile and Run:

# Compile (with Bouncy Castle in classpath)
javac -cp "ankasecure-sdk-3.0.0.jar:bcprov-jdk18on-1.83.jar:bcpkix-jdk18on-1.83.jar:." ExampleScenario26.java

# Run
java -cp "ankasecure-sdk-3.0.0.jar:bcprov-jdk18on-1.83.jar:bcpkix-jdk18on-1.83.jar:." \
  co.ankatech.ankasecure.sdk.examples.ExampleScenario26

Expected Output:

===== SCENARIO 26: PKCS#7 TO JOSE MIGRATION =====
Purpose: Migrate legacy PKCS#7 SignedAndEnvelopedData to modern JOSE with PQC
Pattern: Legacy RSA-2048 → Modern ML-KEM-768

╔═══════════════════════════════════════════════════════════════╗
║  PHASE 1: GENERATE LEGACY PKCS#7 TEST DATA                   ║
╚═══════════════════════════════════════════════════════════════╝

[Step 1/4] Generating RSA-2048 key pair (Bouncy Castle)...
           RSA key pair generated

[Step 2/4] Creating self-signed X.509 certificate...
           Certificate DN: CN=Legacy PKCS7 Demo,O=AnkaSecure,C=US

[Step 3/4] Creating PKCS#7 SignedData (inner layer)...
           SignedData created (algorithm: SHA256withRSA)

[Step 4/4] Creating PKCS#7 EnvelopedData (outer layer)...
           EnvelopedData created (algorithm: RSA-OAEP + AES-256-CBC)
           PKCS#7 file written: temp_files/scenario26_legacy.p7m

Legacy PKCS#7 file generated: temp_files/scenario26_legacy.p7m
Format: SignedAndEnvelopedData (nested structure)

╔═══════════════════════════════════════════════════════════════╗
║  PHASE 2: IMPORT LEGACY RSA KEY                               ║
╚═══════════════════════════════════════════════════════════════╝

[Step 5/11] Converting RSA key to PKCS#12 format...
           PKCS#12 created and Base64 encoded

[Step 6/11] Importing RSA key to AnkaSecure...
           Key ID: sc26_rsa_legacy_1735152000000

╔═══════════════════════════════════════════════════════════════╗
║  PHASE 3: DECRYPT AND VERIFY PKCS#7                           ║
╚═══════════════════════════════════════════════════════════════╝

[Step 7/11] Decrypting PKCS#7 EnvelopedData (outer layer)...
           EnvelopedData decrypted

[Step 8/11] Verifying PKCS#7 SignedData (inner layer)...
           Signature verified: ✅ VALID
           Plaintext extracted to: temp_files/scenario26_pkcs7_extracted.txt

╔═══════════════════════════════════════════════════════════════╗
║  PHASE 4: MIGRATE TO MODERN JOSE WITH PQC                     ║
╚═══════════════════════════════════════════════════════════════╝

[Step 9/11] Generating ML-KEM-768 key for modern encryption...
           Key ID: sc26_kem_modern_1735152000100
           Algorithm: ML-KEM-768 (NIST FIPS 203 post-quantum)

[Step 10/11] Encrypting with JOSE (JWE format)...
           JOSE file: temp_files/scenario26_jose.enc

╔═══════════════════════════════════════════════════════════════╗
║  PHASE 5: VALIDATE MIGRATION                                  ║
╚═══════════════════════════════════════════════════════════════╝

[Step 11/11] Validating migration...
           JOSE decrypted

Validation Results:
  • PKCS#7 extraction: ✅ VALID
  • JOSE round-trip:   ✅ VALID

╔═══════════════════════════════════════════════════════════════╗
║               ✅ SCENARIO 26 SUCCESSFUL                        ║
║                                                               ║
║  Legacy PKCS#7 successfully migrated to modern JOSE:          ║
║  • PKCS#7 SignedAndEnvelopedData decrypted and verified       ║
║  • Content migrated to JOSE (JWE) with ML-KEM-768             ║
║  • Plaintext integrity maintained throughout migration        ║
║                                                               ║
║  Migration path: RSA-2048 (Legacy) → ML-KEM-768 (PQC)         ║
╚═══════════════════════════════════════════════════════════════╝
===== SCENARIO 26 END =====

Key Concepts

PKCS#7/CMS Overview

PKCS#7 (Cryptographic Message Syntax) is a standard for digitally signed and/or encrypted data:

SignedData: Contains signature over plaintext

EnvelopedData: Contains encrypted content for recipients

SignedAndEnvelopedData: Nested structure - signature inside encryption

Migration Benefits

Aspect PKCS#7 (Legacy) JOSE (Modern)
Format ASN.1/DER binary JSON text
Algorithms RSA, AES (classical only) RSA, ML-KEM, ML-DSA (PQC ready)
Tooling Bouncy Castle, OpenSSL Native JWT libraries, easier integration
Web compatibility Requires encoding Native JSON
Future-proof Quantum-vulnerable Post-quantum capable

Bouncy Castle Dependency

This example requires Bouncy Castle for PKCS#7 generation (legacy side only):

  • Modern JOSE operations use AnkaSecure SDK (no Bouncy Castle needed)
  • PKCS#7 parsing in production would use POST /api/migration/analyze-pkcs7
  • PKCS#7 conversion in production uses POST /api/migration/convert-pkcs7-to-jose

  • Flow 13 - PKCS#12 Import & Hybrid Crypto (key import only)
  • Flow 25 - External Key Interoperability (B2B encryption)
  • Flow 4 - RSA→ML-KEM Re-encrypt Streaming (algorithm migration)

Note: For the complete 471-line implementation with full Bouncy Castle PKCS#7 generation code, helper methods, and X.509 certificate creation, refer to the source file in the SDK.