Policy-Driven Crypto-Agility Fundamentals
Target Audience: Solution Architects, Security Architects, Operations Engineers
Reading Time: 12 minutes
Prerequisites: Understanding of cryptographic algorithms, key management basics
Executive Summary
Crypto-agility is the ability to rapidly change cryptographic algorithms without modifying application code. ANKASecure achieves this through KID abstraction, policy-driven algorithm selection, and zero-code migration via re-encryption and re-signing APIs.
Why it matters: Cryptographic algorithms have limited lifespans. Organizations must be able to migrate from compromised or deprecated algorithms (e.g., RSA-1024 → RSA-2048, or RSA-2048 → ML-KEM-768) without rewriting applications.
Table of Contents
- The Problem: Crypto-Rigidity
- What is Crypto-Agility?
- KID Abstraction Layer
- Policy-Driven Algorithm Selection
- Zero-Code Migration
- Key Rotation Strategies
- Implementation Examples
- Best Practices
The Problem: Crypto-Rigidity
Traditional Approach (Hardcoded Algorithms)
Typical application code:
// BAD: Algorithm hardcoded in application
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] ciphertext = cipher.encrypt(plaintext);
Problems:
- Algorithm is hardcoded - Changing from RSA to ML-KEM requires code changes
- Key type is fixed - Cannot switch key types without refactoring
- No abstraction - Application tightly coupled to cryptographic implementation
- Migration is expensive - Must modify, test, and redeploy all applications
Real-World Scenarios
Scenario 1: Algorithm deprecation
- NIST deprecates SHA-1 (2017)
- All applications using SHA-1 must be updated
- Cost: Millions in development, testing, deployment
Scenario 2: Quantum threat
- Quantum computers threaten RSA/ECC (2030 deadline)
- All RSA/ECC applications must migrate to PQC
- Cost: Astronomical if algorithms are hardcoded
Scenario 3: Security vulnerability
- New attack discovered against AES-CBC (hypothetical)
- Must migrate to AES-GCM immediately
- Cost: Emergency code changes, rushed deployments, high risk
The Cost of Crypto-Rigidity
| Migration Type | Crypto-Rigid Cost | Crypto-Agile Cost | Savings |
|---|---|---|---|
| SHA-1 → SHA-256 | 6-12 months, $2M-5M | 1 week, $50K | 95%+ |
| RSA-2048 → ML-KEM-768 | 12-24 months, $10M-20M | 2-4 weeks, $200K | 98%+ |
| AES-CBC → AES-GCM | 3-6 months, $1M-2M | 1 week, $50K | 97%+ |
ANKASecure goal: Reduce migration cost by 95%+ through crypto-agility.
What is Crypto-Agility?
Definition
Crypto-agility is the ability to change cryptographic algorithms, key sizes, or security parameters without modifying application source code.
Key principles:
- Algorithm abstraction - Applications reference keys by identifier, not algorithm
- Policy-driven selection - Algorithm chosen based on policies, not code
- Transparent migration - Re-encrypt/re-sign without exposing plaintext
- Backward compatibility - Old ciphertexts remain decryptable during transition
Crypto-Agile Architecture
Application Code
↓
[KID Reference] ← Abstract identifier, no algorithm
↓
Policy Layer
↓
[Algorithm Selection] ← Policy determines algorithm
↓
Cryptographic Engine
↓
[Actual Encryption/Signing]
Application perspective:
No algorithm mentioned in code. Platform determines algorithm based on key metadata and policies.
Benefits
| Benefit | Description |
|---|---|
| Future-proof | Easily adopt new algorithms (PQC, post-PQC) |
| Rapid response | Quickly migrate from compromised algorithms |
| Cost reduction | Avoid expensive code changes and redeployments |
| Compliance | Meet evolving regulatory requirements (CNSA 2.0, FIPS) |
| Risk mitigation | Hedge against cryptanalysis breakthroughs |
KID Abstraction Layer
What is a KID?
KID (Key Identifier): An abstract, user-friendly identifier for a cryptographic key.
Examples:
my-encryption-keypayment-signing-keyuser-data-encryption-2025
Key insight: KID does not reveal the underlying algorithm.
KID vs Algorithm
Traditional approach:
Key: rsa-2048-key-001
Algorithm: RSA-2048 (embedded in name)
Problem: Changing to ML-KEM requires renaming key everywhere
Crypto-agile approach (ANKASecure):
KID: my-encryption-key
Algorithm: [metadata, not in identifier]
Benefit: Change algorithm without changing KID
How KID Abstraction Works
Key generation:
POST /api/v3/key-management/keys
Request:
{
"kid": "my-encryption-key",
"kty": "RSA",
"alg": "RSA-3072",
"keyOps": ["encrypt", "decrypt"]
}
Usage (application code):
Internal mapping (platform):
KID: "my-encryption-key"
→ UUID: "550e8400-e29b-41d4-a716-446655440000"
→ Tenant: "tenant-a"
→ Algorithm: "RSA-3072" (JWE key management: RSA-OAEP-512)
→ Keystore path: "/srv/anka-secure/.../my-encryption-key.p12"
Migration (zero code changes):
# 1. Generate new key with PQC algorithm
POST /api/v3/admin/tenants/{tenantId}/keys
{
"kid": "my-encryption-key-v2",
"kty": "ML-KEM",
"algorithm": "ML-KEM-768"
}
# 2. Re-encrypt data (the source key is read from the JWE header)
POST /api/v3/crypto/reencrypt
{
"jweToken": { "protected": "...", "recipients": [ ... ], "iv": "...", "ciphertext": "...", "tag": "..." },
"newKid": "my-encryption-key-v2"
}
# 3. Update references (configuration, not code)
# Old: encryption_key=my-encryption-key
# New: encryption_key=my-encryption-key-v2
# 4. Application code unchanged
String jwe = client.encrypt(config.encryptionKey, plaintext);
See: KID System Explained
Policy-Driven Algorithm Selection
Types of Policies
ANKASecure uses three policy layers to control cryptographic behavior:
| Policy Type | Purpose | Example |
|---|---|---|
| Algorithm Availability | Which algorithms are allowed | "Only FIPS-approved algorithms" |
| Algorithm Rotation | When to migrate to new algorithms | "Migrate RSA to ML-KEM by 2030" |
| Key Lifecycle | When keys expire and rotate | "Rotate keys every 90 days" |
Algorithm Availability Policy
Purpose: Control which algorithms can be used for new keys.
Example policy:
{
"policyName": "PQC-Transition-2025",
"allowedAlgorithms": {
"encryption": ["ML-KEM-768", "ML-KEM-1024", "AES-256-GCM"],
"signature": ["ML-DSA-65", "ML-DSA-87"],
"composite": ["P-256+ML-KEM-768", "P-384+ML-KEM-768"]
},
"deprecatedAlgorithms": ["RSA-2048", "ECDSA-P-256"],
"effectiveDate": "2025-01-01"
}
Enforcement:
# Attempt to generate RSA-2048 key (deprecated)
POST /api/v3/admin/tenants/{tenantId}/keys
{
"kid": "my-key",
"algorithm": "RSA-2048"
}
Response: HTTP 403 Forbidden
{
"error": "Algorithm RSA-2048 is deprecated by policy PQC-Transition-2025",
"allowedAlgorithms": ["ML-KEM-768", "ML-KEM-1024", ...]
}
Algorithm Rotation Policy
Purpose: Define migration timelines from deprecated to approved algorithms.
Example policy:
{
"policyName": "RSA-to-PQC-Migration",
"rotations": [
{
"fromAlgorithm": "RSA-2048",
"toAlgorithm": "ML-KEM-768",
"deadline": "2030-01-01",
"migrationPath": "reencrypt"
},
{
"fromAlgorithm": "ECDSA-P-256",
"toAlgorithm": "ML-DSA-65",
"deadline": "2030-01-01",
"migrationPath": "resign"
}
]
}
Enforcement:
- Phase 1 (Warning): API returns warning header:
X-Algorithm-Deprecated: RSA-2048 (migrate by 2030-01-01) - Phase 2 (Soft block): Require explicit override flag
- Phase 3 (Hard block): Reject operations after deadline
Key Lifecycle Policy
Purpose: Control key expiration, rotation frequency, and archival.
Example policy:
{
"policyName": "High-Security-Keys",
"maxKeyAge": "90 days",
"maxOperations": 1000000,
"rotationStrategy": "automatic",
"archivalPeriod": "7 years"
}
Behavior:
- Day 0-89: Key active
- Day 90: Key auto-rotated (new key generated, old key deprecated)
- Day 90+: Old key decrypts only (cannot encrypt)
- Year 7: Old key archived (cold storage)
See: Policy System Design*
Zero-Code Migration
The Goal
Migrate from Algorithm A to Algorithm B without:
- ❌ Modifying application code
- ❌ Exposing plaintext to client
- ❌ Storing plaintext on server disk
- ❌ Requiring application downtime
ANKASecure achieves this through server-side re-encryption and re-signing.
Re-Encryption (Algorithm Migration)
Problem: Data encrypted with RSA-2048, need to migrate to ML-KEM-768.
Traditional approach (INSECURE):
1. Decrypt with RSA-2048 → plaintext (client-side)
2. Encrypt with ML-KEM-768 → new ciphertext (client-side)
Problem: Plaintext exposed to client
ANKASecure approach (SECURE):
1. Send old JWE token to /api/v3/crypto/reencrypt
2. Server decrypts with RSA-2048 (in memory, never leaves server)
3. Server encrypts with ML-KEM-768 (in memory)
4. Return new JWE token
5. Plaintext NEVER sent to client or written to disk
Endpoint:
POST /api/v3/crypto/reencrypt
Request (the source key is read from the JWE header):
{
"jweToken": { "protected": "...", "recipients": [ ... ], "iv": "...", "ciphertext": "...", "tag": "..." },
"newKid": "mlkem-key"
}
Response:
{
"jweToken": { "protected": "...", "recipients": [ ... ], "iv": "...", "ciphertext": "...", "tag": "..." },
"oldKeyRequested": "rsa-key",
"oldKeyAlgorithmUsed": "RSA-2048",
"newKeyRequested": "mlkem-key",
"newKeyAlgorithmUsed": "ML-KEM-768"
}
Streaming mode (large files):
POST /api/v3/crypto/stream/reencrypt?newKid=mlkem-key
Request (multipart, IN THIS ORDER):
- header: [old JWET header JSON]
- file: [old ciphertext stream]
Response (multipart/mixed):
- PART 1: [new JWET header JSON + new ciphertext stream]
- PART 2: [end-of-stream verdict JSON]
Memory: O(1) constant (2 MiB dual-thread pipeline).
See: Flow 4 - Asymmetric Re-encrypt (Streaming)
Re-Signing (Algorithm Migration)
Problem: Data signed with RSA-PSS-256, need to migrate to ML-DSA-65.
Traditional approach (INSECURE):
1. Verify old signature with RSA-PSS-256
2. Send payload to client
3. Client signs with ML-DSA-65
Problem: Payload exposed to client
ANKASecure approach (SECURE):
1. Send old JWS + payload stream to /api/v3/crypto/resign
2. Server verifies old signature (RSA-PSS-256)
3. Server signs with new key (ML-DSA-65)
4. Return new JWS
5. Payload streamed through, never stored
Endpoint:
POST /api/v3/crypto/stream/resign
Request (multipart):
- metadata: {"oldJws": "[old detached JWS JSON]", "newKid": "mldsa-key"}
- file: [payload stream]
Response (multipart/mixed):
- PART 1: {"protected": "eyJhbGci...ML-DSA-65", "signature": "new-signature"}
- PART 2: [end-of-stream verdict JSON]
Key Rotation Strategies
Time-Based Rotation
Strategy: Rotate keys every N days/months.
Use cases:
- Compliance requirements (e.g., PCI-DSS: rotate every 90 days)
- Limit key exposure window
- Proactive security posture
Implementation:
Behavior:
- Day 0: Key
my-key-v1active - Day 90: Auto-generate
my-key-v2, deprecatemy-key-v1 - Day 90+: New encryptions use
my-key-v2, old ciphertexts decrypt withmy-key-v1 - Day 180: Auto-generate
my-key-v3, deprecatemy-key-v2
Usage-Based Rotation
Strategy: Rotate keys after N operations.
Use cases:
- High-volume systems (millions of operations/day)
- Limit cryptanalysis opportunities
- Reduce risk per key
Implementation:
Behavior:
- Operations counter: 0 → 1,000,000
- At 1,000,000: Auto-rotate key
- Old key: decrypt-only mode
Event-Based Rotation
Strategy: Rotate keys after security incidents or detected anomalies.
Use cases:
- Breach detection
- Suspicious activity alerts
- Insider threat mitigation
Implementation:
# Manual rotation trigger (the Stable KID in the path is kept; new material becomes primary)
POST /api/v3/admin/tenants/{tenantId}/keys/my-key/rotations
{
"newMaterial": {
"kty": "ML-KEM",
"alg": "ML-KEM-1024"
}
}
Response:
{
"kid": "my-key",
"kty": "ML-KEM",
"alg": "ML-KEM-1024",
"status": "active",
"createdAt": "2025-01-15T10:30:00Z",
"primaryMaterialVersion": 2
}
Algorithm Migration Rotation
Strategy: Rotate to upgrade algorithm (e.g., RSA → ML-KEM).
Use cases:
- CNSA 2.0 compliance (PQC by 2030)
- Algorithm deprecation
- Security level upgrade
Implementation:
# Generate new key with PQC algorithm
POST /api/v3/admin/tenants/{tenantId}/keys
{
"kid": "my-key-v2",
"kty": "ML-KEM",
"algorithm": "ML-KEM-768"
}
# Re-encrypt each stored JWE (one request per token; there is no batch route)
POST /api/v3/crypto/reencrypt
{
"jweToken": { "protected": "...", "recipients": [ ... ], "iv": "...", "ciphertext": "...", "tag": "..." },
"newKid": "my-key-v2"
}
See: Key Rotation Strategies*
Implementation Examples
Example 1: Simple Crypto-Agile Application
Configuration file (config.yml):
encryption:
keyId: my-encryption-key # Abstract KID, no algorithm
signature:
keyId: my-signing-key # Abstract KID, no algorithm
Application code:
// Load configuration
Config config = ConfigLoader.load("config.yml");
// Encrypt (algorithm determined by platform)
String ciphertext = client.encrypt(config.encryption.keyId, plaintext);
// Sign (algorithm determined by platform)
String signature = client.sign(config.signature.keyId, payload);
Migration (change config, not code):
# Before (RSA-2048)
encryption:
keyId: my-encryption-key-rsa
# After (ML-KEM-768) - only config changed
encryption:
keyId: my-encryption-key-mlkem
Application code: Unchanged.
Example 2: Automated Re-Encryption Pipeline
Scenario: Migrate 1 million encrypted records from RSA to ML-KEM.
Script:
import ankatech_sdk as anka
client = anka.Client(config)
# Fetch all encrypted records
records = database.query("SELECT id, jwe FROM encrypted_data")
# Re-encrypt in batches
for batch in chunks(records, batch_size=1000):
results = client.batch_reencrypt(
old_kid="rsa-key",
new_kid="mlkem-key",
jwes=[record.jwe for record in batch]
)
# Update database
for record, result in zip(batch, results):
database.update(
"UPDATE encrypted_data SET jwe = ? WHERE id = ?",
result.jwe, record.id
)
print("Migration complete: 1,000,000 records re-encrypted")
Time: ~2 hours (streaming mode, parallel processing).
Plaintext exposure: Zero (all operations server-side).
Example 3: Policy-Driven Key Generation
Policy-aware key generation:
// The application never names an algorithm. It provisions a key by PURPOSE --
// through the Admin Console, ankasecure-km or the Admin API -- and the
// deployment's algorithm policy decides what backs it. The data-plane SDK then
// names that key by kid and never sees the choice.
KeyMetadata key = client.getKeyMetadata("user-data-encryption");
System.out.println("Key: " + key.getKid());
System.out.println("Algorithm: " + key.getAlg()); // ML-KEM-768, selected by policy
Policy layer selects algorithm:
- Security Level 3 → NIST Level 3
- Encryption usage → KEM algorithm
- Current policy → ML-KEM-768 (PQC-approved)
Result: Application gets crypto-agile key without specifying algorithm.
Best Practices
1. Use Abstract KIDs
DO:
DON'T:
Reason: Algorithm should not be in identifier (prevents crypto-agility).
2. Store Algorithm in Metadata, Not Names
DO:
{
"kid": "my-key",
"algorithm": "ML-KEM-768",
"metadata": {
"purpose": "user-data-encryption",
"securityLevel": 192
}
}
DON'T:
3. Use Policies to Control Algorithms
DO: Define organizational policy, enforce via platform.
DON'T: Hardcode algorithm choices in application code.
4. Plan for Migration Windows
Recommendation: 6-12 month migration windows for algorithm changes.
Phases:
- Month 0-3: Generate new keys, dual-key operation
- Month 3-9: Re-encrypt/re-sign existing data
- Month 9-12: Deprecate old keys, verify complete migration
- Month 12+: Archive old keys (compliance retention)
5. Monitor Key Usage
Metrics to track:
- Operations per key (detect anomalies)
- Key age (trigger rotation)
- Algorithm distribution (track migration progress)
- Failed decryptions (detect issues)
6. Test Migration Before Enforcement
Approach:
- Generate test keys with new algorithm
- Test encryption/decryption in staging
- Benchmark performance
- Validate interoperability
- Only then enforce in production
7. Maintain Backward Compatibility
Rule: Always support decryption with old keys during migration.
Implementation:
- Keep deprecated keys in decrypt-only mode
- Don't delete keys until compliance retention period expires
- Support multiple key versions simultaneously
Quick Reference
Crypto-Agility Checklist
Design phase:
- [ ] Use abstract KIDs (no algorithms in names)
- [ ] Externalize key configuration (config files, not code)
- [ ] Design for multiple key versions
Implementation phase:
- [ ] Use platform APIs (not low-level crypto libraries)
- [ ] Never hardcode algorithms in code
- [ ] Implement configuration-driven key selection
Operations phase:
- [ ] Define algorithm availability policies
- [ ] Plan rotation schedules
- [ ] Monitor key usage metrics
- [ ] Test migration procedures
Migration phase:
- [ ] Use re-encryption/re-signing APIs
- [ ] Batch operations for large datasets
- [ ] Verify plaintext never leaves server
- [ ] Maintain audit trail
Related Documentation
Foundational Concepts
Key Management
- Key Rotation Strategies*
- Key Lifecycle Policy*
- Algorithm Availability Policy*
- Algorithm Rotation Policy*
- Policy System Design*
SDK Examples
- Flow 4 - Asymmetric Re-encrypt (Streaming)
- Flow 8 - ML-KEM-768 → ML-KEM-1024 Re-encrypt (Compact)
- Flow 9 - RSA-3072 → ML-DSA-87 Re-sign (Compact)
- Flow 12 - Stream Re-sign (ML-DSA-65 → SLH-DSA-SHA2-128S)
Use Cases
- Crypto-Agility (Technical)*
- Crypto-Agility (Executive)*
Document Status: ✅ ACTIVE
Last Updated: January 2025
Document Location: 02-concepts/crypto-agility-fundamentals.md
Target Audience: Solution Architects, Security Architects, Operations Engineers
Feedback: For corrections or additions, contact the documentation team.