Convert Operations
Purpose: Migration of legacy cryptographic data to modern formats and algorithms
Version: 3.0.0
Overview of Convert Phase
The Convert phase encompasses two distinct types of conversion:
1. Format Conversion (Legacy Containers → Modern JOSE)
Transforms legacy container formats to modern JOSE standards with the same classical keys — no post-quantum algorithm is introduced.
Key Operations:
- PKCS#7/CMS to JWE/JWS: Convert S/MIME and legacy system files to JOSE format
- Signatures produced again: each signer's content is re-signed with its matched key, under the JWS
algthat key signs with (PS256for RSA,ES*/ESB*for EC) - Content encrypted again: the content is always re-encrypted under
A256GCM(whatever cipher the PKCS#7 used — AES-CBC, 3DES, RC2 or CAST5), and a new content-encryption key is wrapped to every recipient under its key'salg(RSA-OAEP-512for RSA) - Every actor needs a key imported with its private key: current limitation — a certificate imported alone is a verify-only trust anchor and is refused as a signer or a recipient
- The caller needs re-operation grants on those keys:
REENCRYPTfrom the recipient that decrypts to every recipient (its own pair included) andRESIGNfrom each signer's key to itself. AREENCRYPTorRESIGNgrant is requested with exactly twoassetKids: N recipients need N-1 pair grants[decrypting recipient, recipient], one recipient needs the in-place grant, requested with its kid twice (assetKids: [kid, kid]) and stored as[kid], and each signer needsRESIGN[signer, signer]; there is no wildcardREENCRYPTorRESIGNgrant.DECRYPT,ENCRYPTandSIGNgrants, and themigration.convertPkcs7scope alone, authorize no conversion; a missing grant is403
Endpoints:
POST /api/v3/migration/convert-pkcs7-to-jose(compact; bounded bymigration.max-upload-bytes, default 5 MB)POST /api/v3/migration/stream/convert-pkcs7-to-jose(streaming; the upload is bounded at 100 MB and refused413 payload-too-largeabove it — a proxy in front of the deployment may cap uploads lower; see Behind a buffering proxy)
What unbounded size costs on the streaming endpoint, and how a failure reaches you
Cost. EnvelopedData converts in a single pass with bounded memory, whatever the number of recipients. The signed shapes read the uploaded file once per signer plus once more, because RFC 2315 places the signer metadata after the content and each signature is computed in its own pass: SignedData with N signers costs N + 1 passes, SignedAndEnvelopedData N + 3. Expect the wall-clock time to scale with the signer count. Every signer and recipient is resolved to a tenant key before the first byte is written, which is why a missing key is a 422 naming every unresolved actor, at every input size. The streaming route is also under the streaming concurrency bound (429 with Retry-After when it is full).
Failures. Every failure decidable before the first payload byte is a response status with an application/problem+json body. An EnvelopedData content-decryption failure — a PKCS #1 v1.5 encrypted key that does not unwrap included, since it is replaced by a random key (RFC 3218 §2.3.2) and fails at the content — is raised while the output is being emitted: it is the 422 decryption-failed problem document while the response is still uncommitted, and once the response is committed the response is aborted — its framing is never completed and no problem document is written into the body, so a response that stops short is a failure; discard the partial output. See PKCS#7 Conversion — the abort contract.
decryptionKid is optional, and a dual-use legacy key
For EnvelopedData and SignedAndEnvelopedData, decryptionKid is optional. When it is absent, the first recipient in encoded order whose tenant key admits decryption and encryption decrypts; when it is present it must name one of the recipients (a kid that names none of them is 400 invalid-input). If a recipient key was a dual-use legacy RSA keypair imported with purpose: DUAL, it was projected onto two single-purpose identities that share one certificate; the conversion selects the projection each role admits (the ENCRYPT_DECRYPT projection for a recipient, the SIGN_VERIFY projection for a signer). To name it explicitly, pass the <kid>-enc identity as decryptionKid, NOT the -sig identity. The DUAL projection is declared on the import request itself, POST /api/v3/admin/tenants/{tenantId}/keys/import-keystore.
targetFormat must match the parsed structure (else 422)
targetFormat selects the JOSE output: AUTO (default) auto-detects from the parsed PKCS#7 structure, while an explicit JWS / JWE / JWE_JWS_NESTED forces that output. An explicit targetFormat incompatible with the structure (JWS↔SignedData, JWE↔EnvelopedData, JWE_JWS_NESTED↔SignedAndEnvelopedData) is rejected with 422 unsupported-pkcs7-format (errorCode = INCOMPATIBLE_TARGET_FORMAT). The streaming endpoint honors targetFormat for this rejection too, returning the 422 as a response status with an application/problem+json body before any payload byte, at every input size. See PKCS#7 Conversion — Error Response Contract.
See: PKCS#7 Conversion for detailed workflow
2. Algorithm Conversion (Classical → Post-Quantum)
Transforms data from classical algorithms to quantum-resistant algorithms.
Key Operations:
- Data re-encryption: Decrypt with RSA/AES → Encrypt with ML-KEM/AES-GCM
- Signature conversion: Verify RSA/ECDSA → Re-sign with ML-DSA/FALCON
- Batch conversion: Bulk operations with checkpoints
- Streaming re-encryption: Large files with constant 2 MiB memory footprint (USPTO patent architecture)
Endpoints:
POST /api/v3/crypto/reencrypt,POST /api/v3/crypto/stream/reencryptPOST /api/v3/crypto/resign,POST /api/v3/crypto/stream/resign
Outcome: Data and signatures protected by quantum-resistant algorithms (ML-KEM, ML-DSA, FALCON, SLH-DSA)
Migration Path
For legacy PKCS#7 files:
- Format conversion first: PKCS7 → JOSE (using
/api/v3/migration/convert-pkcs7-to-jose) - Algorithm conversion second (optional): JOSE classical → JOSE PQC (using
/api/v3/crypto/reencryptor/api/v3/crypto/resign)
Step 2 accepts every conversion result, whether it names one key or several. On a General JSON JWS with several signatures or a General JSON JWE with several recipients — the output of a multi-signer or multi-recipient PKCS#7 — the crypto operations (decryptData, verifySignature, reencryptData, resignData, decryptThenVerify, and their streaming twins) follow four rules: decrypt uses the recipient the caller names in recipientKid and holds a grant on; verify requires every signature to be valid and reports each signer; re-sign verifies every signature first and replaces only the rotated one (sourceKid → newKid); re-encrypt always draws a fresh content-encryption key and replaces only the rotated recipient. Each key needs its own grant. See Operating on a converted result.
These are separate sequential steps, not a single operation.
Data Re-encryption Workflows
Compact Re-encryption (≤5MB files)
Purpose: Decrypt data encrypted with classical algorithms and re-encrypt with new keys
Process (in-memory):
graph LR
Ciphertext["Legacy Ciphertext<br/>RSA-encrypted data"] -->|1. Decrypt| LegacyKey["Imported RSA Key<br/>From PKCS#12"]
LegacyKey -->|2. Produces| Plaintext["Plaintext Data<br/>Decrypted payload<br/>Full byte array in RAM"]
Plaintext -->|3. Encrypt| PQCKey["New ML-KEM Key<br/>Generated in ANKASecure"]
PQCKey -->|4. Produces| PQCCiphertext["PQC Ciphertext<br/>ML-KEM-encrypted data"]
style Ciphertext fill:#ffcccc,stroke:#333,stroke-width:2px
style PQCCiphertext fill:#51cf66,stroke:#333,stroke-width:2px
style Plaintext fill:#ffd43b,stroke:#333,stroke-width:2px Endpoint: POST /api/v3/crypto/reencrypt
Key Considerations:
- Legacy key must have
decryptin keyOps: Expired certificates imported with IMPORT_ONLY mode allow decryption - Server-side operation: Re-encryption performed entirely server-side; plaintext exists as full byte array in server memory
- Memory zeroing: Plaintext is zeroized immediately after re-encryption (defense-in-depth)
- Size limit: ≤5MB (for larger files use streaming mode)
Streaming Re-encryption (any file size)
Purpose: Re-encrypt large files with constant memory footprint
Process (USPTO patent architecture):
graph LR
Ciphertext["Legacy Ciphertext<br/>Stream input"] -->|Decrypt Thread| Pipe["BoundedByteQueue<br/>2 MiB pipe<br/>32 chunks × 64 KiB"]
Pipe -->|Encrypt Thread| NewCipher["New Ciphertext<br/>Stream output"]
style Ciphertext fill:#ffcccc,stroke:#333,stroke-width:2px
style Pipe fill:#ffd43b,stroke:#333,stroke-width:2px
style NewCipher fill:#51cf66,stroke:#333,stroke-width:2px Endpoint: POST /api/v3/crypto/stream/reencrypt
Key Considerations:
- No full plaintext accumulation: Only small chunks (64 KiB) exist in memory at any time
- Constant memory footprint: 2 MiB regardless of file size (works with GB/TB files)
- Virtual threads: Decrypt and encrypt operate in parallel for performance
- Server-side operation: Plaintext chunks never leave server memory, never written to disk or sent to client
- A failure after the response is committed aborts it: the framing is never completed and no problem document is written into the body; treat a short read as a failure and discard the partial output. Before the response is committed the same failure is an
application/problem+jsonstatus - A producer failure is never an end-of-stream: the pipe between them carries one terminal state — complete only on a normal return, failed otherwise — so a decrypt failure makes the consumer's read throw instead of letting it finish over a short stream and report success
PQC Encryption (With New Keys)
Purpose: Encrypt data with quantum-resistant algorithms
Supported PQC Encryption Algorithms:
- ML-KEM-512: Equivalent to ~128-bit classical security
- ML-KEM-768: Equivalent to ~192-bit classical security (recommended)
- ML-KEM-1024: Equivalent to ~256-bit classical security (high security)
Process:
- Generate PQC key (if not already exists)
- Encrypt plaintext using ML-KEM + AES-256-GCM (hybrid encryption)
- Store ciphertext (replacing legacy encrypted version)
- Verify decryption (test round-trip to confirm success)
Streaming Re-encryption (Large Files)
Purpose: Convert large encrypted files without loading entire plaintext into memory
ANKASecure USPTO Patent (2025): Streaming re-encryption technology
Architecture:
graph TD
LegacyFile["Legacy Encrypted File<br/>e.g., 10 GB archive"] -->|Stream chunks| Decrypt["Decrypt Chunk<br/>with Legacy Key"]
Decrypt -->|Plaintext chunk| Encrypt["Encrypt Chunk<br/>with PQC Key"]
Encrypt -->|PQC ciphertext chunk| PQCFile["PQC Encrypted File<br/>Output stream"]
Decrypt -.->|No full plaintext| Memory["Memory Usage:<br/>Only 1 chunk at a time"]
Encrypt -.->|Streaming| Memory
style LegacyFile fill:#ffcccc,stroke:#333,stroke-width:2px
style PQCFile fill:#51cf66,stroke:#333,stroke-width:2px
style Memory fill:#4dabf7,stroke:#333,stroke-width:2px Advantages:
- ✅ Memory efficient: Only one chunk in memory at a time (typically 4 MB chunks)
- ✅ Plaintext never fully exposed: Only partial plaintext exists momentarily
- ✅ Progress tracking: Can report conversion progress per chunk
- ✅ Resumable: Can checkpoint and resume if interrupted
Endpoint: See Streaming Operations* for detailed API documentation
Verification After Conversion
Purpose: Ensure converted data can be decrypted successfully
Verification Process:
sequenceDiagram
participant Admin
participant Convert as Conversion Service
participant PQCKey as PQC Key
participant Test as Verification
Admin->>Convert: Convert file X from RSA to ML-KEM
Convert->>PQCKey: Encrypt with ML-KEM-768
Convert->>Test: Test decryption
Test->>PQCKey: Decrypt with ML-KEM-768
PQCKey-->>Test: Decrypted plaintext
Test->>Test: Compare with original
alt Match
Test-->>Admin: ✅ Conversion successful
else Mismatch
Test-->>Admin: ❌ Conversion failed<br/>Rollback recommended
end Validation Steps:
- Decrypt converted file with PQC key
- Compare hash of decrypted plaintext with original plaintext hash
- If match: Conversion successful
- If mismatch: Rollback, investigate issue, retry
Signature Conversion Workflows
Legacy Signature Verification
Purpose: Verify signatures created with classical algorithms
Process:
graph LR
Document["Signed Document"] -->|1. Extract| Signature["Legacy RSA Signature"]
Document -->|2. Hash| Hash["Document Hash"]
Signature -->|3. Verify| LegacyKey["Imported RSA Public Key"]
Hash -->|3. Verify| LegacyKey
LegacyKey -->|4. Result| Verdict{"Valid?"}
Verdict -->|Yes| Valid["✅ Signature Valid<br/>Proceed to re-sign"]
Verdict -->|No| Invalid["❌ Signature Invalid<br/>Do not convert"]
style Valid fill:#51cf66,stroke:#333,stroke-width:2px
style Invalid fill:#ff6b6b,stroke:#333,stroke-width:2px Key Consideration: Only convert if legacy signature is valid. Invalid signatures indicate data tampering or corruption.
PQC Re-signing
Purpose: Create new signatures using quantum-resistant algorithms
Supported PQC Signature Algorithms:
- ML-DSA-44: Small signature size (~2.4 KB), 128-bit security
- ML-DSA-65: Standard signature size (~3.3 KB), 192-bit security (recommended)
- ML-DSA-87: Large signature size (~4.6 KB), 256-bit security
- FALCON-512: Compact signature (~666 bytes), 128-bit security
- FALCON-1024: Compact signature (~1.3 KB), 256-bit security
Process:
- Verify legacy signature (ensure document authentic)
- Generate PQC signing key (ML-DSA or FALCON)
- Sign document with PQC key
- Store new signature (optionally keep legacy signature for transition period)
Hybrid Signatures (Dual Algorithms)
Purpose: Maintain both classical and PQC signatures during transition period
Use Case: Gradual migration where some systems still require classical signatures
This pattern signs with two separate SIMPLE keys, so each signature verifies on its own. It is not a COMPOSITE_SIGNATURE key, whose one composite signature is valid only when both of its components verify (see Composite Hybrid Keys*).
Architecture:
graph TD
Document["Document to Sign"] -->|Sign| LegacyKey["Legacy RSA Key"]
Document -->|Sign| PQCKey["PQC ML-DSA Key"]
LegacyKey -->|Produces| LegacySig["RSA Signature"]
PQCKey -->|Produces| PQCSig["ML-DSA Signature"]
LegacySig -->|Attach| Dual["Dual-Signed Document"]
PQCSig -->|Attach| Dual
Dual -->|Verify with| LegacyVerifier["Legacy Systems<br/>Use RSA signature"]
Dual -->|Verify with| PQCVerifier["PQC-Ready Systems<br/>Use ML-DSA signature"]
style Dual fill:#ffd43b,stroke:#333,stroke-width:2px
style LegacyVerifier fill:#ffcccc,stroke:#333,stroke-width:2px
style PQCVerifier fill:#51cf66,stroke:#333,stroke-width:2px Dual Signature Format (JWS with multiple signatures):
{
"payload": "eyJkYXRhIjogInNhbXBsZSJ9",
"signatures": [
{
"protected": "eyJhbGciOiJQUzI1NiJ9",
"signature": "RSA_SIGNATURE_HERE"
},
{
"protected": "eyJhbGciOiJNTC1EU0EtNjUifQ",
"signature": "ML_DSA_SIGNATURE_HERE"
}
]
}
Transition Strategy:
- Month 1-2: Add ML-DSA signature alongside RSA (dual signatures)
- Month 3-4: Verify both systems accept ML-DSA
- Month 5: Remove RSA signature, keep only ML-DSA
Key Format Conversion
Export Operations
Purpose: Retrieve keys for external system integration
Endpoint: GET /api/v3/admin/tenants/{tenantId}/keys/{kid}/export (Admin API; the Core API has no export route)
Scope Required: SCOPE_admin.keys.read
Use Cases:
- Sharing public keys with partner organizations
- Integrating ANKASecure keys with external verification systems
- Key distribution for multi-party encryption
- Comparing a tenant key with a certificate held elsewhere
Request:
GET /api/v3/admin/tenants/00000000-0000-0000-0000-000000000001/keys/prod-signing-key/export HTTP/1.1
Host: api.ankatech.co
Authorization: Bearer {jwt-token}
Response - Asymmetric Key (public portion only):
{
"kid": "prod-signing-key",
"kty": "ML-DSA",
"alg": "ML-DSA-87",
"type": "SIMPLE",
"publicKey": "MIIHsjALBglghkgBZQMEAxMDggehAE...",
"keyOps": ["sign", "verify"],
"exportable": true,
"origin": "GENERATED",
"restricted": false,
"status": "active",
"createdAt": "2025-01-15T10:20:00Z",
"expiresAt": "2030-01-15T10:20:00Z",
"usageCount": 1542
}
Response - Symmetric Key (secret omitted):
{
"kid": "aes-session-key",
"kty": "oct",
"alg": "AES-GCM-256",
"type": "SIMPLE",
"keyOps": ["encrypt", "decrypt"],
"exportable": true,
"origin": "GENERATED",
"status": "active",
"createdAt": "2025-12-01T08:00:00Z"
}
Private Material Never Exported
For asymmetric keys, only the public key is returned; a composite key returns its component public keys in components[]. For symmetric keys (kty=oct), the secret is deliberately omitted for security. A key marked non-exportable (exportable false) is refused 400 invalid-input with no key material.
Response - Not Found: a kid that does not exist for the tenant — or a kid of another tenant, or a path naming another tenant — answers 404 with type https://docs.ankatech.co/errors/not-found.
Format Transformation
Purpose: Convert between key formats (PEM, DER, JWK)
Supported Formats:
| Format | Description | Use Case |
|---|---|---|
| PEM | Base64-encoded DER with headers | Traditional Unix/Linux systems |
| DER | Binary X.509 encoding | Java keystores, Windows systems |
| JWK | JSON Web Key format | Modern web applications, REST APIs |
Note: ANKASecure stores keys internally in wrapped format. Export API returns keys in standard formats for interoperability.
Key Wrapping/Unwrapping
Purpose: Encrypt keys for secure transport
Key Wrapping Process:
graph LR
PlainKey["Plain PQC Key"] -->|Wrap with| KEK["Key Encryption Key<br/>AES-256-GCM"]
KEK -->|Produces| WrappedKey["Wrapped Key<br/>Encrypted blob"]
WrappedKey -->|Transmit| Transport["Secure Transport<br/>HTTPS, TLS"]
Transport -->|Receive| Destination["Destination System"]
Destination -->|Unwrap with| KEK2["Same KEK<br/>Pre-shared"]
KEK2 -->|Produces| PlainKey2["Plain PQC Key<br/>Restored"]
style WrappedKey fill:#51cf66,stroke:#333,stroke-width:2px
style Transport fill:#4dabf7,stroke:#333,stroke-width:2px Use Case: Migrating keys between ANKASecure instances or to external HSMs
Batch Conversion Operations
Bulk Re-encryption Strategies
Purpose: Convert large numbers of encrypted files efficiently
Strategy 1: Parallel Conversion
graph TD
FileList["1000 Encrypted Files"] -->|Split| Batch1["Batch 1<br/>Files 1-200"]
FileList -->|Split| Batch2["Batch 2<br/>Files 201-400"]
FileList -->|Split| Batch3["Batch 3<br/>Files 401-600"]
FileList -->|Split| Batch4["Batch 4<br/>Files 601-800"]
FileList -->|Split| Batch5["Batch 5<br/>Files 801-1000"]
Batch1 -->|Thread 1| Convert1["Convert to ML-KEM"]
Batch2 -->|Thread 2| Convert2["Convert to ML-KEM"]
Batch3 -->|Thread 3| Convert3["Convert to ML-KEM"]
Batch4 -->|Thread 4| Convert4["Convert to ML-KEM"]
Batch5 -->|Thread 5| Convert5["Convert to ML-KEM"]
Convert1 -->|Complete| Results["Aggregated Results"]
Convert2 -->|Complete| Results
Convert3 -->|Complete| Results
Convert4 -->|Complete| Results
Convert5 -->|Complete| Results
style Results fill:#51cf66,stroke:#333,stroke-width:2px Advantages:
- ⚡ Faster completion (parallel processing)
- 📊 Progress tracking per batch
- ♻️ Resource utilization (CPU/memory distributed)
Disadvantages:
- 🔧 More complex coordination
- 💾 Higher memory usage (multiple concurrent operations)
Strategy 2: Sequential Conversion with Checkpoints
graph LR
Start["File 1"] -->|Convert| C1["✓ File 1"]
C1 -->|Checkpoint| CP1["Checkpoint 1:<br/>1 file complete"]
CP1 -->|Continue| C2["✓ File 2"]
C2 -->|Checkpoint| CP2["Checkpoint 2:<br/>2 files complete"]
CP2 -->|Continue| Dots["..."]
Dots -->|Final| Complete["All Files Complete"]
style CP1 fill:#ffd43b,stroke:#333,stroke-width:2px
style CP2 fill:#ffd43b,stroke:#333,stroke-width:2px
style Complete fill:#51cf66,stroke:#333,stroke-width:2px Advantages:
- ✅ Simple implementation
- 💾 Low memory usage (one file at a time)
- ♻️ Easy resume (from last checkpoint)
Disadvantages:
- 🐢 Slower completion (sequential processing)
Performance Optimization
Batch Size Recommendations:
| Total Files | Recommended Batch Size | Parallel Threads | Estimated Time |
|---|---|---|---|
| < 100 | 20 files/batch | 2 threads | Minutes |
| 100-1,000 | 50 files/batch | 4 threads | Hours |
| 1,000-10,000 | 100 files/batch | 8 threads | Days |
| > 10,000 | 200 files/batch | 16 threads | Weeks |
Optimization Tips:
- Pre-validate keys: Ensure all legacy keys loaded before starting batch
- Warm up: Convert 10 sample files first to identify issues early
- Monitor resources: Track CPU, memory, disk I/O during conversion
- Rate limiting: If API-based, respect rate limits (e.g., 100 req/sec)
Checkpoint/Resume Patterns
Purpose: Handle interruptions gracefully without starting over
Checkpoint Format:
{
"batchKey": "batch-2025-12-24-001",
"totalFiles": 1000,
"completedFiles": 342,
"failedFiles": 3,
"checkpointTime": "2025-12-24T14:30:00Z",
"nextFileIndex": 343,
"failedFilesList": [
{"file": "file_150.enc", "error": "Decryption failed"},
{"file": "file_201.enc", "error": "Legacy key expired"},
{"file": "file_299.enc", "error": "Corrupted ciphertext"}
]
}
Resume Process:
- Load checkpoint: Read last checkpoint from persistent storage
- Verify completed files: Optionally re-check last N files to ensure integrity
- Resume from nextFileIndex: Continue conversion from where left off
- Update checkpoint periodically: Every N files or every M minutes
Failure Recovery
Failure Types:
| Failure Type | Recovery Strategy | Prevention |
|---|---|---|
| Decryption failure | Log error, skip file, continue | Pre-validate keys before batch |
| Network timeout | Retry with exponential backoff | Use connection pooling |
| Out of memory | Reduce batch size, restart | Monitor memory, use streaming |
| Disk full | Pause, free space, resume | Pre-check disk space |
| API rate limit | Wait, then resume | Implement rate limiting client-side |
Error Handling Pattern:
graph TD
Convert["Convert File"] -->|Error?| Check{"Error Type?"}
Check -->|Transient<br/>Network, timeout| Retry["Retry with Backoff<br/>Max 3 attempts"]
Check -->|Permanent<br/>Bad key, corrupt data| LogSkip["Log Error<br/>Skip file<br/>Continue batch"]
Check -->|Critical<br/>Out of memory, disk full| Abort["Abort Batch<br/>Save checkpoint<br/>Alert admin"]
Retry -->|Success| Next["Next File"]
Retry -->|Still failing| LogSkip
LogSkip -->|Continue| Next
style Next fill:#51cf66,stroke:#333,stroke-width:2px
style Abort fill:#ff6b6b,stroke:#333,stroke-width:2px Conversion Verification
Integrity Checks
Purpose: Ensure data integrity after conversion
Verification Methods:
-
Hash Comparison:
- Hash original plaintext:
SHA-256(original_plaintext) - Decrypt converted ciphertext:
plaintext' = decrypt_PQC(converted_ciphertext) - Hash decrypted plaintext:
SHA-256(plaintext') - Compare hashes:
original_hash == new_hash
- Hash original plaintext:
-
Content Comparison:
- Decrypt both legacy and PQC ciphertexts
- Compare byte-by-byte
- Verify exact match
-
Selective Sampling:
- For large batches, verify random sample (e.g., 5% of files)
- If sample passes, assume batch successful
- If sample fails, verify all files
Functionality Testing
Purpose: Ensure converted data works in production scenarios
Test Cases:
| Scenario | Test | Expected Result |
|---|---|---|
| Decrypt test | Decrypt PQC ciphertext with PQC key | Plaintext matches original |
| Sign/verify test | Create PQC signature, verify with PQC public key | Signature valid |
| Cross-system test | Export PQC key, decrypt on external system | Successful decryption |
| Performance test | Decrypt 100 PQC ciphertexts | Acceptable latency (<100ms/file) |
| Stress test | Decrypt 10,000 files concurrently | No errors, acceptable throughput |
Performance Validation
Purpose: Ensure PQC operations meet performance requirements
Baseline Metrics (RSA-2048 vs. ML-KEM-768):
| Operation | RSA-2048 | ML-KEM-768 | Relative Performance |
|---|---|---|---|
| Encryption | ~0.5 ms | ~0.05 ms | 10x faster |
| Decryption | ~5 ms | ~0.06 ms | 83x faster |
| Key Generation | ~50 ms | ~1 ms | 50x faster |
Validation:
- Measure actual performance after conversion
- Compare to baseline
- If degradation > 20%: Investigate (likely infrastructure issue)
- If improvement: Confirm and document
Related Documentation
- API Reference - Complete endpoint documentation
- Analyze Operations - Certificate validation and compatibility analysis
- Streaming Operations* - Streaming re-encryption architecture
- RSA to ML-KEM Migration* - Complete encryption migration workflow
- Monitoring & Validation - Success criteria and health checks
Version: 3.0.0
Last Updated: 2025-12-24 Status: Production Ready