Applied Cryptography and Key Management Questions
Selecting and applying cryptographic primitives correctly: symmetric and asymmetric encryption, hashing, digital signatures, key derivation, secure random number generation, and public key infrastructure. Covers key lifecycle management, key exchange and distribution, choosing appropriate algorithms for a given constraint set including resource-constrained environments, and the forward-looking side of algorithm lifecycle: cryptographic agility and algorithm-migration strategy, forward secrecy, and the post-quantum cryptography transition and planning upgrades without breaking existing data or interoperability. The applied-crypto engineering layer, distinct from compliance-driven crypto standards.
Behavioral: describe a concrete project where you designed or implemented cryptography in production. Using the STAR format, explain the problem, what you built, the algorithms and libraries you used, the trade-offs you weighed (security, performance, developer ergonomics), and the measurable outcome. If you don't have direct experience, describe a hypothetical project in the same level of detail.
Sample Answer
A strong answer here uses the STAR method (Situation, Task, Action, Result) to walk through one concrete project: what security requirement forced a cryptography decision, exactly what you built, the specific algorithm and library you chose and why, and a rounded, honest outcome.
STAR framework
- Situation: name the system and the concrete requirement, for example "we stored customer payment metadata and a new compliance mandate required field-level encryption at rest."
- Task: your specific responsibility, for example selecting the primitive and library, implementing it, getting it reviewed, and shipping it.
- Action: what you actually built. Name the primitive (for example AES-256-GCM, an authenticated encryption mode that gives you both confidentiality and tamper detection in one step, used through a vetted library rather than a hand-rolled implementation), and the key management approach (envelope encryption: a per-record data encryption key wrapped by a key encryption key held in a cloud key management service, so the raw key never sits in application memory longer than one operation). Walk through the trade-offs you actually weighed: a stronger security margin versus added latency, a well-documented library API versus building from lower-level primitives, and rotation cost versus the blast radius of a single compromised key.
- Result: describe the outcome in qualitative, rounded terms, for example that the design passed security review with no findings on the cryptography path, or that a later incident on an application server did not expose customer data because the raw key never left the key management boundary. Avoid inventing precise before/after metrics you cannot actually substantiate.
Worked example
Say the project was field-level encryption for a payments-adjacent field. You chose AES-256-GCM with envelope encryption: a data encryption key (DEK) generated per batch of records, wrapped by a key encryption key (KEK) that lives only inside a cloud key management service (KMS) and is never exported in plaintext. The trickiest engineering decision was nonce management, since AES-GCM is completely broken if the same key and nonce pair is ever reused, so you derived the nonce deterministically from a monotonically increasing record ID rather than relying on randomness, and documented that invariant so future maintainers would not break it by reusing the DEK across an unrelated write path.
Trade-offs and pitfalls
Common wrong turns to avoid telling this story: describing a custom or "improved" cryptographic scheme instead of a well-reviewed standard construction, treating key rotation as an afterthought instead of a day-one design decision, and picking a project that is really a tour of everything you have touched rather than one focused story with real depth. Be ready with a second, smaller example in case the interviewer pushes for more detail on a specific part.
What assurances and features does a Hardware Security Module (HSM) provide for key management and cryptographic operations (tamper resistance/evidence, FIPS assurance levels, secure key generation, sealed storage, key wrapping, attestation)? How does that change operational practice compared to a software-only key store, and when do you actually need dedicated hardware rather than a cloud KMS, a Kubernetes secret store, or a self-hosted vault?
Sample Answer
Direct answer
An HSM's value is that key material is generated, used, and stored inside a certified, tamper-evident hardware boundary and never has to leave in plaintext form. A software-only key store can protect keys with access control and encryption, but the bytes still exist somewhere a sufficiently privileged process or root-level attacker can eventually read. You reach for dedicated hardware specifically when you need that non-extractability guarantee for compliance or blast-radius reasons, not for general secret storage, where a cloud KMS, a Kubernetes secret store, or a self-hosted vault is usually the right, cheaper answer.
Structured elaboration
What an HSM actually provides
- Tamper resistance and evidence: physical construction (potting, mesh sensors, voltage and temperature monitors) designed to destroy key material, or at minimum show visible evidence of intrusion, if the device is opened or attacked, rather than relying only on software access control.
- FIPS assurance levels: HSMs are commonly validated to FIPS 140-3, the current version of the standard (superseding FIPS 140-2), which defines four increasing levels. Level 1 requires only approved algorithms with no physical security requirement, Level 2 adds tamper evidence and role-based authentication, Level 3 adds tamper resistance and response with identity-based authentication and logical or physical separation between roles, and Level 4 adds environmental failure protection for hostile physical environments. Most production HSMs protecting high-value key material are validated to Level 3.
- Secure key generation: keys are generated inside the module using a validated, continuously health-tested random bit generator, not on a general-purpose host's less-scrutinized entropy pool.
- Sealed storage: private key material lives only inside the module's protected memory; even administrators typically cannot extract it, only invoke operations that use it.
- Key wrapping: keys can be securely exported in encrypted (wrapped) form for backup or transport to another HSM without ever existing in plaintext outside a hardware boundary.
- Attestation: the module can cryptographically prove its own identity and firmware state to a relying party, so trusting a given HSM instance with real key material doesn't rest on a vendor's claim alone.
How this changes operational practice compared to a software-only key store
- Every cryptographic operation becomes an API call to the module rather than reading a key into memory and computing locally, which changes both latency (a round trip per operation) and throughput planning (an HSM has a rated operations-per-second ceiling to capacity-plan against).
- Backup and disaster recovery require HSM-to-HSM wrapped export and import, or a quorum-based recovery ceremony, not a simple encrypted file copy.
- Compliance evidence gets much cleaner: "the key never left a FIPS-validated boundary" is a specific, auditable claim a software key store cannot make no matter how well access-controlled it is.
When you actually need dedicated hardware rather than a cloud KMS, a Kubernetes secret store, or a self-hosted vault
- A regulation or contract names FIPS 140-3 (or a specific level) or a hardware security boundary explicitly, common in payments, government, and parts of healthcare and finance.
- The key protects something catastrophic if extracted, a root CA key, a code-signing key, a payment HSM's PIN-block key, where the cost of dedicated hardware is small relative to that key's blast radius.
- You need non-extractability guaranteed even against a cloud provider's own privileged operators, a stronger, directly auditable boundary than most managed-KMS tiers offer, though many providers' hardware-backed tiers get close.
- A cloud KMS is the right default otherwise, giving most of the operational assurance without owning physical hardware and at dramatically lower cost and complexity.
- A Kubernetes secret store or self-hosted vault is right for general application secrets, database passwords, API tokens, that don't need hardware-bound non-extractability, forcing those through a dedicated HSM adds latency and cost with no matching risk reduction.
Worked example
A payment processor signing transaction authorizations needs that signing key to never exist outside FIPS 140-3 Level 3 hardware, because a leaked signing key would let an attacker forge authorizations indefinitely, so it uses a dedicated payment HSM. The same company's database credentials for a few dozen known internal services, rotated weekly, don't carry that blast radius; a cloud KMS or a self-hosted vault issuing short-lived dynamic credentials is the appropriate, far cheaper choice, and routing those through a payment HSM would add operational friction without reducing real risk.
Trade-offs and pitfalls
Common wrong turn: defaulting to "we should use an HSM" for every secret because it sounds more secure, when the actual risk being defended against doesn't need hardware non-extractability, needlessly adding cost, latency, and complexity. Common wrong turn: assuming a vendor's FIPS 140-3 validation on its overall product line automatically covers your specific configuration, validations are scoped to specific hardware, firmware version, and operating mode, so confirm the validated configuration actually matches what you deploy. Senior signal: naming the specific guarantee, non-extractability, attested firmware identity, sealed generation, rather than reaching for "HSM equals more secure" as an unexamined default.
Describe the purpose of a salt in password-based key derivation: what properties it needs (uniqueness, length, randomness), where it should be stored relative to the derived hash, and the operational risks of reusing or omitting it at scale. Then explain the difference between a salt and a pepper: how does adding a server-side secret pepper change the threat model for offline attacks, and what controls does protecting a pepper actually require?
Sample Answer
Direct answer
A salt is a unique, random, non-secret value stored alongside each password hash so identical passwords never produce identical stored hashes and precomputed lookup tables (rainbow tables) become useless. A pepper is a separate, secret value, shared across all users and stored outside the database, that adds a layer an attacker who only stole the database, and not the pepper's separate storage, cannot reproduce at all.
Salt properties
- Uniqueness: every stored hash gets its own salt, so no two hashes can ever be compared or looked up in a shared precomputed table, even if two users chose the same password.
- Length and randomness: generated fresh with a cryptographically secure random number generator, long enough (16 bytes is a common minimum) that collisions across an entire user base are effectively impossible.
- Storage: the salt is not secret and is stored right alongside the derived hash, often concatenated into the same stored string as most KDF libraries' output format does, because verification needs it: a login attempt cannot be checked without knowing which salt was used.
Operational risks of reusing or omitting a salt at scale
Reusing one salt across many users collapses back to the pre-salt world for that group: identical passwords produce identical hashes again, so one cracked hash cracks every account sharing that password. Omitting a salt entirely makes precomputed rainbow-table attacks viable against an entire user base at once, and is the single most common real-world password-storage mistake salting exists to prevent.
Salt vs pepper
A pepper adds an ingredient a salt deliberately lacks: it is the same value for every user, unlike a salt, and it is never stored in the same place as the password hashes, typically in application configuration, a secrets manager, or a hardware security module (HSM), specifically so that a database breach alone, a SQL injection or a stolen backup, does not hand an attacker everything needed to attempt offline cracking.
How a pepper changes the threat model
Without a pepper, stealing the password-hash database is sufficient to start an offline brute-force or dictionary attack immediately. With a pepper, the attacker also needs to compromise wherever the pepper is stored, a genuinely separate system with its own access controls, before offline attacks become possible at all; a database-only breach becomes far less immediately damaging.
Controls a pepper actually requires
A pepper only helps if it is genuinely harder to steal than the database: its own access control (ideally an HSM/KMS-backed secret, not an environment variable sitting next to application code that also has database access), its own rotation plan (rotating a pepper means re-verifying and re-deriving every stored hash, a real migration, not a config change), and monitoring, since a pepper stored in the same place, or reachable via the same compromise path, as the database it protects provides no real additional security at all.
Design a migration strategy to move a user database from PBKDF2 to Argon2id without forcing a mass password reset. Cover the schema changes needed to version hashes, the authentication-flow change that detects an old hash and re-hashes on successful login, options for migrating accounts that never log in again, and the metrics you'd watch to confirm the migration is succeeding.
Sample Answer
Direct answer
Store the algorithm and its parameters alongside every hash so old (PBKDF2) and new (Argon2id) records are distinguishable, verify a login against whichever algorithm the stored hash says it used, and silently re-hash with Argon2id the moment a login succeeds, since a successful login is the one moment the plaintext password is legitimately available in memory to spend the cost of the new, stronger hash on.
Schema changes to version hashes
Store a self-describing hash string rather than a bare hash value: the algorithm identifier, its parameters, the salt, and the derived hash, all together, for example the widely used PHC string format ($argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash>) versus a PBKDF2 equivalent naming its iteration count. This avoids a separate "algorithm version" column that could drift out of sync with the actual stored value; parsing the stored string alone tells you everything needed to verify it.
Authentication-flow change: detect old hash, re-hash on success
- On login, parse the stored hash string to determine which algorithm and parameters it used.
- Verify the submitted password against that algorithm (PBKDF2 for old records, Argon2id for already-migrated ones).
- If verification succeeds and the stored hash is not already the current target algorithm/parameters, immediately derive a new Argon2id hash from the plaintext password, available only during this one request, and overwrite the stored record with the new hash string.
- If verification fails, leave the stored record untouched; a failed login gives no legitimate opportunity to touch it, and doing so would be actively wrong.
Accounts that never log in again
Some accounts never trigger the natural re-hash-on-login path because they simply stop logging in. Options, usually combined: leave them on the old algorithm indefinitely, accepting the residual risk since these tend to also be the least active, lowest-value targets, with a monitoring dashboard tracking what fraction of the user base remains un-migrated over time; force a password reset for accounts that have not logged in, and therefore not migrated, after a defined long window, one of the rare cases where forcing a reset for a subset of users, rather than the whole base, is reasonable, trading a small, bounded friction against an indefinite tail of weakly hashed accounts; or, for genuinely dormant accounts past a retention policy, consider whether they should simply be deactivated rather than migrated at all.
Metrics to confirm the migration is succeeding
- Percentage of the user base still on the old algorithm, trending down over time as logins naturally trigger re-hashing; a stalled or flat trend signals the natural mechanism alone will not finish in a reasonable timeframe and the forced-reset path for dormant accounts needs to trigger sooner or more aggressively.
- Error rate on the re-hash step itself, distinct from the login verification step, since a bug here could silently fail to upgrade accounts while users still log in successfully, hiding the problem from ordinary login-success monitoring.
- Latency impact on logins that include a re-hash, since Argon2id's memory-hard computation adds real cost to that one request; this should show up as a small, bounded latency bump specifically on migrating logins, not a general regression across all logins.
Trade-offs and pitfalls
Never derive the new hash from anything except the plaintext password already available during a successful verification; there is no way to re-hash an existing PBKDF2 output into an Argon2id one without the original plaintext, since these are one-way functions by design. If the login endpoint is heavily rate-limited or load-shed under peak traffic, remember the re-hash step adds real, non-trivial compute cost, that is the point of Argon2id, so capacity-plan for a transition period where a meaningful fraction of logins carry that extra cost, not just the eventual steady state once migration is complete.
You're starting a greenfield system expected to run for more than 10 years. List the factors you'd weigh when selecting cryptographic algorithms and key sizes for symmetric encryption, public-key encryption, signatures, and key exchange. How would you build in algorithm agility from day one, and how would you document these choices so a future team can safely migrate them?
Sample Answer
Direct answer: For a system meant to run 10+ years, do not just pick "the strongest algorithm available today." Pick current, NIST-recommended algorithms with a comfortable security margin, design the ciphertext and protocol formats so the algorithm itself is a swappable, versioned field rather than baked into the wire format, and write down every choice with its assumptions and a review date. Agility and documentation matter as much as the initial algorithm choice, because you cannot predict what will need to change in year 6.
Factors per primitive
- Symmetric encryption: use AES-256-GCM (or ChaCha20-Poly1305 where hardware AES acceleration is unavailable). Rationale: Grover's algorithm gives quantum computers a quadratic speedup against brute-force key search, so a key of length k bits gives only about k/2 bits of security against a quantum attacker. AES-128 would degrade to roughly 64-bit post-quantum security, too thin for a decade-plus horizon. AES-256 still leaves roughly 128-bit margin. This is the cheapest form of "future-proofing" available: symmetric algorithms do not need new math, just a bigger key.
- Public-key encryption / key exchange: classical RSA-2048 or ECC (elliptic-curve cryptography, the main alternative to RSA) (X25519, P-256) is fine against today's computers but carries zero quantum margin: Shor's algorithm breaks the underlying math outright rather than merely halving it. For anything that must stay confidential for a decade, this is the "harvest now, decrypt later" risk: an adversary records ciphertext today and decrypts it once a cryptographically relevant quantum computer exists. Architect for a hybrid classical-plus-post-quantum key encapsulation mechanism (KEM) from day one, even if you cannot deploy it yet, so the wire format already has a slot for it.
- Signatures: ECDSA P-256 or Ed25519 (both elliptic-curve signature schemes; Ed25519 is a solid modern default) today, but if the data or documents being signed need long-term non-repudiation (contracts, archival records), plan a migration path to a post-quantum signature and consider independent timestamping, since a signature's cryptographic strength only needs to hold up to the moment it is verified, but verification might happen decades later.
- Key exchange: always use ephemeral exchange (ECDHE/DHE, the elliptic-curve and classical variants of ephemeral Diffie-Hellman key agreement), never static, for forward secrecy. This has nothing to do with the quantum question and everything to do with limiting the blast radius of any future key compromise.
Building in algorithm agility
- Version every ciphertext, token, and certificate format with an explicit algorithm identifier and key-version field up front (the way TLS cipher suites or a JOSE
algheader work), never a fixed-width blob with an implicit algorithm. - Put crypto operations behind a narrow internal interface (a
Signer, aKeyExchange) so callers never depend on one library's concrete types directly. Swapping an implementation becomes a change behind that interface, not a project-wide find-and-replace. - Support the current and previous algorithm simultaneously during any migration window (dual-read, single-write for new data), never a hard cutover.
- Reuse a standard container format that already treats algorithm identity as first-class (X.509, JOSE/COSE, TLS) instead of inventing your own byte layout.
Documentation
- Keep a living cryptographic inventory (sometimes called a cryptographic bill of materials): every algorithm, key size, library, and where each is used.
- Write an architecture decision record for each choice capturing the threat model assumed and an explicit "review by" date (for example, tied to a known deprecation milestone such as NIST's phased retirement of 112-bit-security algorithms).
- Maintain, and actually rehearse, a migration runbook rather than leaving it as an untested design document.
Worked example. The Grover's-algorithm halving is the one number worth internalizing: a k-bit symmetric key gives roughly 2^(k/2) post-quantum brute-force operations. For AES-128, that is 2^64, within reach of a well-resourced, patient attacker even setting aside classical improvements. For AES-256, that is 2^128, comfortably out of reach for the foreseeable future. That single fact is why "use AES-256, not AES-128" is close to a free future-proofing decision, while the same logic does not rescue RSA or ECC, whose underlying math (factoring, discrete log) is broken outright by Shor's algorithm rather than merely weakened.
Trade-offs and pitfalls. A common wrong turn is defaulting to the mathematically largest option everywhere (RSA-4096 for every signature) without addressing agility: a bigger classical key buys you nothing against a quantum adversary and costs real performance. The opposite failure is designing "agility" as an open-ended plugin architecture supporting dozens of algorithm combinations; that makes testing and certification infeasible. Bound agility to a short, deliberately curated allow-list with a clear default, not an unbounded menu.
Unlock Full Question Bank
Get access to all 24 Applied Cryptography and Key Management interview questions and detailed answers.
Sign in to ContinueJoin thousands of developers preparing for their dream job.