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/pkcs12 (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.AnkaSecureSdk;
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.*;

/**
 * <h2>Scenario 26: PKCS#7 to JOSE Migration</h2>
 * <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>
 *
 * [Javadoc continues as in source file...]
 *
 * @since 3.0.0
 */
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();
            AnkaSecureSdk sdk = authenticate(props);
            runScenario(sdk);

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

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

    private static void runScenario(AnkaSecureSdk sdk) throws Exception {

        // PHASE 1: Generate Legacy PKCS#7 Test Data
        Pkcs7TestData testData = generatePkcs7TestData();

        // PHASE 2: Import RSA Key to AnkaSecure
        String rsaKid = importRsaKey(sdk, testData);

        // PHASE 3: Decrypt and Verify PKCS#7
        Path extractedFile = extractFromPkcs7(testData);

        // PHASE 4: Migrate to Modern JOSE with PQC
        String kemKid = generateModernKey(sdk);
        Path joseFile = migrateToJose(sdk, kemKid, extractedFile);

        // PHASE 5: Validate Migration
        validateMigration(testData.plaintext, extractedFile, joseFile, sdk);
    }

    // [Full implementation of all helper methods as shown in source code above]
    // [Including: generatePkcs7TestData(), importRsaKey(), extractFromPkcs7(),
    //  generateModernKey(), migrateToJose(), validateMigration(),
    //  createSelfSignedCertificate(), and Pkcs7TestData inner class]
}

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.78.jar:bcpkix-jdk18on-1.78.jar:." ExampleScenario26.java

# Run
java -cp "ankasecure-sdk-3.0.0.jar:bcprov-jdk18on-1.78.jar:bcpkix-jdk18on-1.78.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.