Finding: RSA-OAEP encryption
src/billing_export.py:10
- Business context
- Customer records must stay secret for 25 years (declared in the repository's
quantsiv.yml) - Why it ranks here
- Protects data that must stay confidential for 25 years.
- The risk
- RSA-based public-key cryptography is vulnerable to sufficiently capable quantum computers. Data intercepted today may become decryptable in the future if the relevant encryption or key-establishment mechanisms are compromised.
- Move to
- Replace RSA encryption/key transport with ML-KEM (FIPS 203) plus an AEAD.
- Authority
- EO 14412 (22 Jun 2026): post-quantum key establishment on high-value assets and high-impact systems by 31 Dec 2030. NIST IR 8547 (ipd): 112-bit RSA/ECC/DH deprecated after 2030, all quantum-vulnerable public-key algorithms disallowed after 2035.
Quantsiv AI: migration analysis
Analysis complete In your CI, on the model you choose Simulated output
The current implementation uses RSA-OAEP to protect exported customer records with a 25-year confidentiality requirement.
Not a drop-in swap. Here RSA-OAEP wraps the AES key that encrypts each export. ML-KEM does not encrypt a chosen key: it establishes a shared secret, and the data key is derived from it. AES-256-GCM keeps encrypting the records.
Recommended migration
- Review the existing RSA-OAEP encryption and key-management flow.
- Evaluate ML-KEM (FIPS 203) for post-quantum key establishment, including hybrid approaches where appropriate.
- Use an authenticated symmetric encryption scheme such as AES-GCM for payload encryption.
- Identify affected dependencies, integrations, certificates, and compatibility requirements.
- Prioritise the migration based on confidentiality lifetime and cryptographic exposure.
- Validate the updated implementation and run regression checks.
- Priority
- Critical, 25-year confidentiality
- Affected
src/billing_export.pyand the partner's decryption code, outside this repository- Standards
- FIPS 203 (ML-KEM-768) for key establishment; AES-256-GCM for the records
- Compatibility
- The export format changes, and the partner needs an ML-KEM key pair. Exports already sent stay as they were.
Draft change
@@ -4,10 +4,11 @@
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
-from cryptography.hazmat.primitives.asymmetric import padding
+from cryptography.hazmat.primitives.kdf.hkdf import HKDF
def seal_export(records, partner_key, export_id):
- data_key = AESGCM.generate_key(bit_length=256)
- wrapped_key = partner_key.encrypt(data_key, padding.OAEP(mgf=padding.MGF1(hashes.SHA256()), algorithm=hashes.SHA256(), label=None))
+ # Key establishment: ML-KEM-768 (FIPS 203); the records stay encrypted with AES-256-GCM
+ kem_ciphertext, shared_secret = partner_key.encapsulate()
+ data_key = HKDF(algorithm=hashes.SHA256(), length=32, salt=None, info=b"billing-export v2").derive(shared_secret)
nonce = os.urandom(12)
body = AESGCM(data_key).encrypt(nonce, json.dumps(records).encode(), export_id.encode())
- return {"wrapped_key": wrapped_key, "nonce": nonce, "body": body}
+ return {"kem_ciphertext": kem_ciphertext, "nonce": nonce, "body": body}
Validation
Checks on the draft change
- target is a post-quantum alternative: ML-KEM-768
- rescanned: RSA is gone
- nothing quantum-vulnerable added
- policy passes
Real output of Quantsiv's checks for the draft above. Your own tests run too when you set a check command; this sample sets none. A person reviews the change, and nothing is committed.
On every later build
A later pull request adds an RSA key. The change check compares it with the latest main-branch build:
- gate
- fail
- new asset
RSA-2048atsrc/partner_upload.py:6, high
