Crypto Agility (Hardcoded Algorithm Selection)
ID |
kotlin.crypto_agility |
Severity |
info |
Remediation Complexity |
medium |
Remediation Risk |
low |
Remediation Effort |
medium |
Resource |
Cryptography |
Language |
Kotlin |
Tags |
ASVS50:v11.2.1, ASVS50:v11.6.1, CWE:327, NIST.IR.8547, OWASP:2025:A04, crypto, crypto-agility, pqc, quantum |
Description
Flags a cryptographic API call that selects a quantum-relevant algorithm with the choice hardcoded in
source — whether passed as a literal argument (e.g. getInstance("RSA")) or fixed by the chosen API /
function / type itself (e.g. rsa.GenerateKey, hashlib.sha256(), P256.Signing.PrivateKey()). When
the algorithm is baked into code, changing it — most importantly the migration to post-quantum
cryptography — becomes a code change rather than a configuration change. This is the crypto-agility
axis of post-quantum readiness, complementary to pqc_readiness (which algorithms must migrate) and
pqc_weak_keylength (which key sizes are too small).
Rationale
Crypto-agility is the ability to swap a cryptographic algorithm with minimal disruption. A call that
hardcodes its algorithm — whether as a literal argument (KeyPairGenerator.getInstance("RSA")) or by
calling an algorithm-specific API/function/type directly (rsa.GenerateKey, hashlib.sha256(),
P256.Signing.PrivateKey()) — ties the choice to the source: every algorithm change requires editing,
rebuilding and redeploying code. Externalizing the choice — reading the algorithm from configuration,
or selecting it through a provider/factory abstraction — turns the post-quantum migration (and any
future change) into a configuration update.
A finding is raised when the algorithm is statically determined in source (a literal/compile-time constant argument, or fixed by the chosen API); a value read from runtime configuration does not resolve and is treated as already agile. Only quantum-relevant primitives are reported — algorithms broken by Shor’s algorithm (public-key) or weakened by Grover’s (symmetric/hash) — since those are the ones that will need to change; an already quantum-safe choice (e.g. ML-KEM) is not flagged.
In Kotlin the algorithm is hardcoded as the JCA factory argument; reading it from configuration instead keeps the choice swappable:
KeyPairGenerator.getInstance("RSA") // hardcoded — the PQC swap is a code change
Cipher.getInstance("AES/CBC/PKCS5Padding") // hardcoded algorithm selection
KeyPairGenerator.getInstance(cfg.keyAlgorithm()) // agile — algorithm comes from configuration
Remediation
Externalize the algorithm selection so it is not hardcoded at the call site: read the algorithm name from configuration, or obtain the primitive through a provider/factory abstraction whose algorithm is configurable. The goal is that the next algorithm change — notably the post-quantum migration to ML-KEM / ML-DSA (optionally in a classical+PQC hybrid) — is a configuration change, not a code change.
References
-
CWE-327 : Use of a Broken or Risky Cryptographic Algorithm.
-
NIST IR 8547 : Transition to Post-Quantum Cryptography Standards.
-
NIST SP 1800-38 : Migration to Post-Quantum Cryptography.