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:
- Generate legacy RSA-2048 key pair (Bouncy Castle)
- Create self-signed X.509 certificate
- Create PKCS#7 SignedData (sign plaintext with RSA)
- Create PKCS#7 EnvelopedData (encrypt SignedData with RSA)
- Write binary PKCS#7 file (SignedAndEnvelopedData)
- Import RSA key to AnkaSecure via PKCS#12
- Decrypt PKCS#7 EnvelopedData (extract SignedData)
- Verify PKCS#7 SignedData (extract plaintext)
- Generate ML-KEM-768 key for modern encryption
- Encrypt plaintext with JOSE (JWE format)
- 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 keystoreanalyze-pkcs7- Analyze PKCS#7 structure before conversionconvert-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
Related Examples
- 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.