Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Applied Cryptography for Developers  Module 1 – Foundations: goals, bytes and security levels

Security levels, key sizes and attack cost

What n bits of security means, brute-force cost, NIST key sizes for AES, RSA and elliptic curves, the birthday bound for IDs and nonces, and quantum risk.

  • Beginner
  • 25 minutes
  • Examples run with Node.js 24.21.0, Python 3.14.8, Pyodide 314.0.7 and quickjs 0.32.0
  • By MySmartCoPilot
Free lesson, Pro answers: 25 minutes
Free: the whole lesson. With a pass: the model answers to its 2 interview questions.

What you will learn

  • Explain what n bits of security means and estimate the cost of a brute-force search
  • Read NIST's comparable-strength table to pick RSA, elliptic-curve and symmetric key sizes
  • Use the birthday bound to size identifiers, nonces and hash outputs
  • Describe how large quantum computers would change these numbers, and what NIST plans for them

Before you start

What you’ll learn · Before you start

What you will learn

  • Explain what n bits of security means and estimate the cost of a brute-force search
  • Read NIST's comparable-strength table to pick RSA, elliptic-curve and symmetric key sizes
  • Use the birthday bound to size identifiers, nonces and hash outputs
  • Describe how large quantum computers would change these numbers, and what NIST plans for them

Before you start

On this page

A 56-bit key has about 72 quadrillion possible values, and a cluster that tests a trillion keys a second tries every one of them in 20 hours. Add 72 more bits and the same search takes longer than ten trillion years even at a million times that speed. Key sizes are a statement about that arithmetic, and so is every “at least 128 bits” in a standard.

This lesson turns it into numbers you can check. You compute brute-force times, read NIST’s table that makes AES-128, RSA-3072 and a 256-bit curve equal, use the birthday bound to size random identifiers and nonces, and see what a large quantum computer would change, ending with a two-step code lab that turns the strength table and the birthday bound into code.

What n bits of security means, in years of guessing

NIST defines security strength: The work needed to break an algorithm, in bits: s bits means about 2^s operations. NIST uses the levels 112, 128, 192 and 256 to compare unlike algorithms, such as AES-128 and RSA-3072. as the amount of work needed to break an algorithm: an algorithm with s bits of strength takes about 2ˢ operations to break, where s is 112, 128, 192 or 256 (SP 800-57 and the draft NIST IR 8547). The simplest attack is an exhaustive key search: Trying every possible key until one works, also called brute force. Each extra key bit doubles its cost; for a well-designed cipher no attack does better.: try every key until one works. For a well-designed cipher no known attack does much better, so its strength is its key size. Each extra bit doubles the number of keys, and ten extra bits multiply it by 1,024. The program below turns key sizes into time at three guessing rates. The rates are assumptions, not measurements: about one fast machine, a large cluster, and a rate far beyond both, the margin designers use to be safe. Change them and run it again:

Time to try every key, at three guessing rates Python · brute/brute_force.py
"""How long trying every key takes, at three assumed guessing rates (estimates, not measurements)."""

YEAR = 365.25 * 24 * 3600  # seconds in a year of 365.25 days


def readable(seconds):
    """A duration in the unit that keeps its number short."""
    years = seconds / YEAR
    if years >= 1e12:
        return f"{years:.1e} years".replace("e+", "e")
    for unit, size in [(1e9, "billion years"), (1e6, "million years"), (1, "years")]:
        if years >= unit:
            amount = years / unit
            return f"{amount:,.0f} {size}" if amount >= 10 else f"{amount:.1f} {size}"
    for name, size in [("days", 86400), ("hours", 3600), ("minutes", 60), ("s", 1), ("ms", 1e-3), ("µs", 1e-6)]:
        if seconds >= size:
            amount = seconds / size
            return f"{amount:,.0f} {name}" if amount >= 10 else f"{amount:.1f} {name}"
    return f"{seconds * 1e9:.1f} ns"


RATES = [10**9, 10**12, 10**18]  # guesses a second: one fast machine, a large cluster, far beyond both
print(f"{'Key':<10}{'Keys to try':<13}{'at 10^9 a second':<19}{'at 10^12 a second':<19}at 10^18 a second")
for bits in [40, 56, 64, 80, 112, 128]:
    keys = 2**bits
    times = [readable(keys / rate) for rate in RATES]
    print(f"{str(bits) + ' bits':<10}{keys:<13.2e}{times[0]:<19}{times[1]:<19}{times[2]}")
print()
print("A search that stops at the key needs half the keys on average, so half these times.")
print("Each extra bit doubles the work: 2**129 // 2**128 =", 2**129 // 2**128)

Output

Key       Keys to try  at 10^9 a second   at 10^12 a second  at 10^18 a second
40 bits   1.10e+12     18 minutes         1.1 s              1.1 µs
56 bits   7.21e+16     2.3 years          20 hours           72 ms
64 bits   1.84e+19     585 years          214 days           18 s
80 bits   1.21e+24     38 million years   38,309 years       14 days
112 bits  5.19e+33     1.6e17 years       1.6e14 years       165 million years
128 bits  3.40e+38     1.1e22 years       1.1e19 years       1.1e13 years

A search that stops at the key needs half the keys on average, so half these times.
Each extra bit doubles the work: 2**129 // 2**128 = 2

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py

At a trillion guesses a second, a 56-bit key falls in 20 hours and a 64-bit key in 214 days. An 80-bit key holds for 38,309 years at that rate but only 14 days at a billion billion. From 112 bits on, even the fastest rate needs 165 million years, and 128 bits needs 1.1 × 10¹³ years. A search that stops when it finds the key needs half the tries on average, which changes nothing at these scales.

Numbers this large do not fit ordinary integers, so code that computes them needs exact arithmetic. JavaScript’s Number is exact only up to 2⁵³; BigInt keeps every digit:

Exact key counts with BigInt JavaScript · brute-js/brute_force.mjs
// Key counts are too big for ordinary numbers: JavaScript's Number is exact only up to 2^53.
// BigInt keeps every digit, so the years below are exact whole numbers (at an assumed 10^12 guesses a second).
const YEAR = 31_557_600n; // seconds in a year of 365.25 days
const RATE = 10n ** 12n; // guesses a second, an estimate for a large cluster

console.log('2 ** 128 as a Number: ', (2 ** 128).toString());
console.log('2n ** 128n as a BigInt:', (2n ** 128n).toString());
console.log('Number keeps 2^53 + 1? ', 2 ** 53 + 1 === 2 ** 53 ? 'no, it rounds to 2^53' : 'yes');
console.log();
for (const bits of [56n, 80n, 112n, 128n]) {
  const seconds = 2n ** bits / RATE; // BigInt division rounds down
  const time = seconds < YEAR ? `${(seconds / 3600n).toLocaleString('en-US')} hours` : `${(seconds / YEAR).toLocaleString('en-US')} years`;
  console.log(`${bits} bits: ${time} to try every key`);
}

Output

2 ** 128 as a Number:  3.402823669209385e+38
2n ** 128n as a BigInt: 340282366920938463463374607431768211456
Number keeps 2^53 + 1?  no, it rounds to 2^53

56 bits: 20 hours to try every key
80 bits: 38,308 years to try every key
112 bits: 164,533,958,809,758 years to try every key
128 bits: 10,782,897,524,556,318,080 years to try every key

Recorded with Node.js 24.21.0 on macOS 26 arm64. To run it yourself: mise exec node@24.21.0 -- node brute_force.mjs

Reading the key size as the strength

Wrong: “RSA-2048 has 2,048 bits of security, far more than AES-256.” Right: RSA-2048 gives 112 bits, because factoring its modulus is far cheaper than trying 2²⁰⁴⁸ keys. Only for a good symmetric cipher do the key size and the strength match.

Checkpoint

Check: Bits of security and brute force

  1. Question 1 of 2 How many times as many keys does a 66-bit key have as a 56-bit key?

    Type a number.

    A hint

    Every extra bit doubles the number of keys.

    Show the answer: Question 1 of 2

    Answer: 1024 times as many

    Ten extra bits double the count ten times: 2¹⁰ = 1,024. That is why each step of the program's table, from 56 to 64 to 80 bits, moves the search time by orders of magnitude.

  2. Question 2 of 2 The program puts a full search of 80-bit keys at 38,309 years at 10¹² guesses a second, and 14 days at 10¹⁸. What does that say about 80-bit keys for data that must stay secret for years?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: They are too weak, because the margin depends on an attacker's speed, and a faster attacker erases it

    That is the reason NIST no longer allows strengths of 80 bits or less for new protection: the rates in the table are estimates, and the margin has to survive the high one.

Why RSA needs 3072-bit keys to match AES-128

Algorithms of different kinds are broken in different ways, so equal security takes very different key sizes. NIST’s key-management recommendation, SP 800-57 Part 1, lines them up in its Table 2, and SP 800-186 places the named curves:

Strength Symmetric RSA modulus (k) Elliptic curve order (f) and named curves
80 or less two-key triple DES 1024 160 to 223 bits, none recommended
112 three-key triple DES 2048 224 to 255 bits: P-224
128 AES-128 3072 256 to 383 bits: P-256, Curve25519, Edwards25519
192 AES-192 7680 384 to 511 bits: P-384
256 AES-256 15360 512 bits and more: P-521

AES has no known attack much better than trying keys, so AES-128 gives 128 bits. RSA falls to methods that factor its modulus far faster than any key search; SP 800-57 notes that strength and key length differ for exactly this reason. That is why RSA must grow to 3,072 bits for 128 bits of strength, and to 15,360 for 256. Elliptic curves sit in between: the best known attacks need about the square root of the size of the curve’s group, so, as SP 800-186 puts it, a curve gives about half the bit length of its group order. A 256-bit curve gives 128 bits with private keys of 32 bytes.

Hash functions get two numbers in SP 800-57’s Table 3. Where collisions matter, as in digital signatures, SHA-256 gives 128 bits; where only finding an input for a given output matters, as in HMAC and key derivation, SHA-256 gives 256. The next section shows where the halving comes from.

OWASP’s ASVS 5.0 sets a floor worth adopting for any new design: every primitive at 128 bits or more, its requirement 11.2.3, which gives a 256-bit elliptic-curve key against RSA-3072 as its own example.

Defaults for a new design

AES-128 or AES-256 for data, X25519 for key agreement, Ed25519 or P-256 for signatures, and RSA only where a system demands it, at 3,072 bits or more.

Checkpoint

Check: Comparable key sizes

  1. Question 1 of 2 Which RSA modulus size gives 128 bits of security in NIST SP 800-57's Table 2?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: 3,072 bits

    RSA needs 3,072 bits for 128 bits of strength and 15,360 for 256, because factoring the modulus is far cheaper than trying keys.

  2. Question 2 of 2 About how many bits of security does an elliptic curve give whose group order is a 384-bit number?

    Type a number.

    A hint

    SP 800-186 says a curve gives about half the bit length of its group order.

    Show the answer: Question 2 of 2

    Answer: 192 bits

    Half of 384 is 192, and SP 800-186 lists P-384 at 192 bits, the same row as AES-192 in SP 800-57's table.

The birthday bound: collisions arrive at the square root

In a room of 23 people, the chance that two share a birthday is 50.7 %, although a year has 365 days. That surprise, recorded in the Handbook of Applied Cryptography as the birthday bound: The rule that random values of b bits start to repeat after about 2^(b/2) of them. It is why a 256-bit hash gives about 128 bits of collision resistance and why random nonces have usage limits., decides the size of anything chosen at random. Among n random values of b bits, the chance that at least two are equal is about 1 − e^(−n(n − 1)/2^(b+1)), and it reaches one half after about 1.18 × 2^(b/2) values: the square root of the number of possibilities, not the number itself. Run the program, then put in your own counts:

Collision chances for random values of 32 to 128 bits Python · birthday/birthday.py
"""The birthday bound: how likely two random values collide, exactly for small cases and by the usual formula."""
import math


def exact(n, m):
    """1 - m(m-1)...(m-n+1) / m**n: the chance that n draws from m values repeat at least once."""
    unique = 1.0
    for i in range(n):
        unique *= (m - i) / m
    return 1 - unique


def approx(n, bits):
    """1 - exp(-n(n-1) / 2^(bits+1)), computed with expm1 so that tiny chances do not round to 0."""
    return -math.expm1(-n * (n - 1) / 2 ** (bits + 1))


print(f"23 people, 365 birthdays, exact:  {exact(23, 365):.3f}")
print(f"30 people, 365 birthdays, exact:  {exact(30, 365):.3f}")
print(f"The formula for 23 people:        {-math.expm1(-23 * 22 / (2 * 365)):.3f}")
print()
counts = [10**6, 10**9, 2**32, 10**12]
print(f"{'Random bits':<13}" + "".join(f"{label:<12}" for label in ["10^6 values", "10^9", "2^32", "10^12"]) + "50 % at about")
for bits in [32, 64, 96, 122, 128]:
    cells = "".join(f"{approx(n, bits):<12.2g}" for n in counts)
    half = math.sqrt(2 * math.log(2)) * 2 ** (bits / 2)
    print(f"{bits:<13}{cells}{half:.2g} values")
print()
x = 1e-20
print("Why expm1: 1 - exp(-1e-20) =", 1 - math.exp(-x), "but -expm1(-1e-20) =", -math.expm1(-x))

Output

23 people, 365 birthdays, exact:  0.507
30 people, 365 birthdays, exact:  0.706
The formula for 23 people:        0.500

Random bits  10^6 values 10^9        2^32        10^12       50 % at about
32           1           1           1           1           7.7e+04 values
64           2.7e-08     0.027       0.39        1           5.1e+09 values
96           6.3e-18     6.3e-12     1.2e-10     6.3e-06     3.3e+14 values
122          9.4e-26     9.4e-20     1.7e-18     9.4e-14     2.7e+18 values
128          1.5e-27     1.5e-21     2.7e-20     1.5e-15     2.2e+19 values

Why expm1: 1 - exp(-1e-20) = 0.0 but -expm1(-1e-20) = 1e-20

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 birthday.py

The exact product reproduces the Handbook’s 0.507 for 23 people and 0.706 for 30, and the formula gives 0.500 for 23. The table then shows why the square root matters:

  • Hash outputs. Finding any two inputs with the same SHA-256 digest takes about 2¹²⁸ tries, not 2²⁵⁶, which is the 128 bits of collision resistance in SP 800-57’s Table 3.
  • Nonces. AES-GCM usually takes a 96-bit nonce: A value used only once with a given key, such as the 96-bit nonce of AES-GCM. Repeating one can break the protection, so nonces come from a counter or from enough random bits., and drawn at random, 2³² of them collide with a chance of about 1.2 × 10⁻¹⁰. NIST SP 800-38D requires that chance to stay at 2⁻³² or below, and so caps a key at 2³² encryptions when its nonces are random.
  • Identifiers. Random 64-bit identifiers collide with a chance of 0.39 by 2³² of them, and become even odds near 5.1 billion. A version 4 UUID has 122 random bits (RFC 9562), so a trillion of them collide with a chance of about 9.4 × 10⁻¹⁴.

The last line of the output is a trap worth knowing: for tiny chances, 1 - exp(-x) rounds to 0, while expm1 keeps the value. The second step of the code lab below asks for exactly that.

Key idea

Random values of b bits start to repeat after about 2^(b/2) of them, so size hashes, nonces and identifiers for the square root of their space, not for its full size.

Checkpoint

Check: The birthday bound

  1. Question 1 of 2 Why does NIST SP 800-38D cap an AES-GCM key at 2³² encryptions when its 96-bit nonces are random?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: By the birthday bound, 2³² random 96-bit nonces repeat with a chance of about 2⁻³³, and the standard keeps that chance at 2⁻³² or below

    Random values collide after about the square root of their space: 2⁴⁸ for 96 bits gives even odds, so the standard stops far earlier, at 2³² encryptions, where the chance is about 2⁻³³.

  2. Question 2 of 2 A system will create a trillion (10¹²) random identifiers over its life, and the chance of any two being equal must stay below one in a billion. Using the program's table, which is the smallest size here that is enough?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: 122 random bits, as in a version 4 UUID

    Solve the bound for the bits: n²/2^(b+1) ≤ 10⁻⁹ with n = 10¹² needs 2^(b+1) ≥ 10³³, so b ≥ 109. Of the sizes listed, 122 is the first that meets it; 128 random bits would too.

What a large quantum computer would change

None exists that can attack today’s cryptography, and RFC 9958, the IETF’s guide to post-quantum cryptography for engineers, still calls such machines theoretical. Two algorithms explain why planning has started anyway. Shor's algorithm: A quantum algorithm that factors numbers and computes discrete logarithms efficiently. On a large enough quantum computer it would break RSA, Diffie-Hellman and elliptic-curve cryptography at any key size. factors numbers and solves discrete logarithms efficiently, so it would break RSA, Diffie-Hellman and every elliptic curve outright, and longer keys would not save them. Grover's algorithm: A quantum search algorithm with a quadratic speed-up: in theory a search of 2^128 keys would take about 2^64 steps. It weakens symmetric keys and hashes only modestly in practice. speeds up search quadratically, so in theory a 128-bit key search would need about 2⁶⁴ quantum steps. RFC 9958 argues that this matters far less in practice, because the steps cannot be split well across many machines, and concludes that AES-128 remains secure, while noting that some agencies recommend AES-256 anyway.

The urgency comes from recordings. Traffic encrypted today with RSA or elliptic-curve key exchange can be stored and decrypted once a large enough machine exists, which NIST IR 8547 and RFC 9958 both call harvest now, decrypt later: Recording encrypted traffic today in order to decrypt it once a large quantum computer exists. It makes quantum-resistant key exchange urgent for secrets that must last for years.. Data that must stay secret for years needs quantum-resistant key exchange now. NIST’s draft plan for the change, step by step:

Timeline · 5 events in order Where each security level stands in NIST's guidance Walk through the levels from the retired ones to the post-quantum plan. The last two steps come from a draft that may still change.
  1. 80 bits or less

    Retired for new protection retired

    SP 800-57 puts RSA-1024, two-key triple DES, curves of 160 to 223 bits and SHA-1 signatures at 80 bits or less, no longer good enough to encrypt or sign anything new. Data already protected with them may still be decrypted or verified when the owner accepts the risk.

  2. 112 bits

    The lowest level still in use

    RSA-2048 and curves of 224 to 255 bits give 112 bits. They still protect new data under NIST's rules, but they are the bottom of the scale, and ASVS 5.0 already asks for 128.

  3. 128 bits and up

    Today's floor for new designs

    AES-128, RSA-3072, P-256 and Curve25519 give 128 bits; P-384 and AES-192 give 192; AES-256 and P-521 give 256. Against classical computers, 128 bits is far beyond any search: the program puts it at about 11 trillion years at a billion billion guesses a second.

  4. After 2030

    112-bit public keys deprecated draft

    NIST IR 8547, an initial public draft, deprecates RSA, ECDSA and the Diffie-Hellman schemes at 112 bits after 2030: still usable where the data owner accepts the risk. NIST's few 112-bit symmetric standards are disallowed in 2030.

  5. After 2035

    Quantum-vulnerable public keys disallowed draft

    The same draft disallows RSA, ECDSA, EdDSA, DH and ECDH at every key size after 2035, because a large quantum computer running Shor's algorithm would break them whatever their length. AES-128 and SHA-256 stay, as post-quantum security categories 1 and 2.

The timeline has 5 events, from 80 bits or less to After 2035.

The replacements are measured against the symmetric primitives. The draft’s post-quantum security categories use AES as their yardstick: category 1 is as hard to break as AES-128, category 3 as AES-192 and category 5 as AES-256. FIPS 203 puts ML-KEM-768, the key-encapsulation mechanism NIST recommends as the default, in category 3.

Checkpoint

Check: Quantum computers and NIST's plan

  1. Question 1 of 2 Would moving RSA from 3,072-bit to 6,144-bit keys protect it against a large quantum computer?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: No: Shor's algorithm factors efficiently, so a longer modulus would not keep RSA safe

    Against Shor's algorithm, RSA and elliptic curves fail at any practical size. That is why NIST's draft plans to disallow them after 2035 and points to ML-KEM and ML-DSA.

  2. Question 2 of 2 Which of these needs quantum-resistant key exchange most urgently?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: Medical records sent over the network today that must stay secret for 25 years

    What matters is how long the data must stay secret against traffic recorded now. Long-lived secrets sent with RSA or elliptic-curve key exchange are the first to move.

Pick sizes for a new design in three questions

Three questions decide most choices: the floor your design must meet, what the key does, and how long the protection must last. Answer them in the table below, which marks what fits and says why the rest does not:

Interactive · answer and compare Which algorithms and key sizes fit your design? Answer three questions about the floor you must meet, what the key does and how long the protection must last. The table marks what fits and says why the rest does not.
Which floor must every primitive meet?
What does the key do?
Must the protection hold after 2035, against someone who records traffic today?

Answer the questions above: the table then marks what fits your case and says why the rest does not.

Seven choices against classical strength, a 128-bit floor, a large quantum computer and NIST's draft plan
Choice Classical strength Meets a 128-bit floor A large quantum computer NIST's draft, after 2035
RSA-2048 Used for: signatures, key transport Mixed 112 bits (SP 800-57 Table 2) Poor 112 bits, under 128 Poor Shor's algorithm breaks it at any size Poor deprecated after 2030, disallowed after 2035
RSA-3072 Used for: signatures, key transport Good 128 bits Good 128 bits, the example ASVS gives Poor Shor's algorithm breaks it at any size Poor disallowed after 2035
P-256, X25519 or Ed25519 Used for: signatures, key agreement Good 128 bits (SP 800-186 Table 1) Good 128 bits, with 32-byte X25519 keys Poor Shor's algorithm breaks elliptic curves too Poor disallowed after 2035
P-384 Used for: signatures, key agreement Good 192 bits Good above the floor Poor broken like every curve, whatever its size Poor disallowed after 2035
AES-128 Used for: data under a key both sides hold Good 128 bits Good exactly the floor Mixed Grover halves it in theory; RFC 9958 calls it secure in practice Good stays: post-quantum category 1
AES-256 Used for: data under a key both sides hold Good 256 bits Good twice the floor Good about 128 bits even under Grover Good stays: post-quantum category 5
ML-KEM-768 with X25519 Used for: post-quantum key agreement (hybrid) Good X25519 gives 128 bits while ML-KEM is new Good ML-KEM-768 is category 3 (FIPS 203) Good built to resist known quantum attacks Good the draft's replacement; encapsulation keys of 1,184 bytes
How the answers decide
  • “Which floor must every primitive meet?” 128 bits, as ASVS 5.0 asks: rules out RSA-2048. RSA-2048 gives 112 bits in SP 800-57 Table 2, under the 128-bit floor of ASVS 5.0 requirement 11.2.3.
  • “What does the key do?” Encrypts or authenticates data with a key both sides hold: rules out RSA-2048, RSA-3072, P-256, X25519 or Ed25519, P-384 and ML-KEM-768 with X25519. Public-key algorithms sign or set up keys. The data itself is encrypted and authenticated with a symmetric key such as AES.
  • “What does the key do?” Signs, or agrees a key with a party you share no key with: rules out AES-128 and AES-256. AES needs a key that both sides already hold. Agreeing on one with a stranger, or signing, takes a public-key algorithm.
  • “What does the key do?” Signs, or agrees a key with a party you share no key with and “Must the protection hold after 2035, against someone who records traffic today?” Yes, the data or signatures must last: rules out RSA-2048, RSA-3072, P-256, X25519 or Ed25519 and P-384. Shor's algorithm breaks RSA and curves at any size, and traffic recorded today can be decrypted then. Use ML-KEM in a hybrid with X25519; post-quantum signatures are a later module.
  • “What does the key do?” Encrypts or authenticates data with a key both sides hold and “Must the protection hold after 2035, against someone who records traffic today?” Yes, the data or signatures must last: adds a caveat to AES-128. RFC 9958 judges 128-bit keys safe in practice against Grover, but some national agencies recommend AES-256 anyway, and it costs little more.

In short: at a 128-bit floor, AES-128 or AES-256 protects data under a shared key; X25519, Ed25519 or P-256 handle key agreement and signatures for data that need not outlive 2035; RSA-2048 falls short of the floor; and anything that must stay secret past 2035 against recorded traffic needs ML-KEM, in a hybrid with X25519, for its key exchange. Whatever you choose, write it into a cryptographic inventory, as ASVS 5.0 asks in requirement 11.1.2, so that the next change of algorithm or key size is a known list of places rather than a search through the code.

Checkpoint

Check: Choosing sizes for a design

  1. One question A health service must meet a 128-bit floor, and records it sends today must stay secret for 25 years. Which key exchange fits best?

    Choose one answer.

    Show the answer: One question

    Answer: ML-KEM-768 in a hybrid with X25519

    The three questions decide it: a 128-bit floor, a public-key job (agreeing a key), and protection past 2035. Only the post-quantum hybrid passes all three.

Practise: encode the tables in code

Two exercises turn the lesson’s tables into functions with sample tests that run on this page. The first looks up the strength of a key the way SP 800-57 and SP 800-186 give it, and its starter code makes the key-size mistake on purpose. The second computes collision chances with the birthday bound, including the 2³² nonce limit of SP 800-38D:

Code lab · 2 steps

Build a key-size and collision checker

Look up the security strength of a key from NIST's tables, then compute the chance that random values collide.

  1. Look up the security strength of a key To do
  2. Size random identifiers with the birthday bound To do

Exercise · Easy · Python, JavaScript

Look up the security strength of a key

Write security_bits(name) in strength.py (JavaScript: securityBits(name) in strength.mjs). It returns the security strength in bits of an algorithm and key size, the way the lesson's tables give it:

  • AES-128, AES-192 and AES-256 give their key size.
  • RSA-<k> follows Table 2 of NIST SP 800-57 Part 1: 80 bits from k = 1024, 112 from 2048, 128 from 3072, 192 from 7680 and 256 from 15360. A size between two rows gets the lower row: RSA-4096 gives 128.
  • The named curves follow SP 800-186: P-224 112; P-256, X25519 and Ed25519 128; P-384 192; X448 and Ed448 224; P-521 256.

Anything else, an RSA key below 1024 bits, an AES size that does not exist or a name the tables do not list, raises ValueError (JavaScript: throws an Error). The starter code makes the classic mistake of treating the key size as the strength, and the sample tests catch it at RSA-2048 and P-256.

Python · Starter code · strength.py

def security_bits(name):
    """The security strength in bits of a name such as 'AES-128', 'RSA-3072' or 'P-256'."""
    # The classic mistake: the key size is not the strength. Replace this with the lesson's tables.
    return int(name.split("-")[1])
The sample tests · test_strength.py
from strength import security_bits


def raises_value_error(name):
    try:
        security_bits(name)
    except ValueError:
        return True
    return False


def test_symmetric_keys():
    """AES keys give their own size"""
    assert security_bits("AES-128") == 128
    assert security_bits("AES-256") == 256


def test_rsa_rows_of_sp_800_57():
    """RSA follows the rows of SP 800-57 Table 2, with sizes between rows rounded down"""
    expected = {"RSA-1024": 80, "RSA-2048": 112, "RSA-3072": 128, "RSA-4096": 128, "RSA-7680": 192, "RSA-15360": 256}
    for name, bits in expected.items():
        assert security_bits(name) == bits, f"{name} gives {bits} bits"


def test_named_curves_of_sp_800_186():
    """the curves follow SP 800-186"""
    expected = {"P-224": 112, "P-256": 128, "X25519": 128, "Ed25519": 128, "P-384": 192, "Ed448": 224, "P-521": 256}
    for name, bits in expected.items():
        assert security_bits(name) == bits, f"{name} gives {bits} bits"


def test_unknown_names_raise():
    """names and sizes the tables do not list raise ValueError"""
    for name in ["RSA-512", "AES-100", "DES", "P-255", "RSA-abc", "RSA-"]:
        assert raises_value_error(name), f"{name!r} should raise ValueError"

JavaScript · Starter code · strength.mjs

/** The security strength in bits of a name such as 'AES-128', 'RSA-3072' or 'P-256'. */
export function securityBits(name) {
  // The classic mistake: the key size is not the strength. Replace this with the lesson's tables.
  return Number(name.split('-')[1]);
}
The sample tests · strength.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { securityBits } from './strength.mjs';

test('AES keys give their own size', () => {
  assert.equal(securityBits('AES-128'), 128);
  assert.equal(securityBits('AES-256'), 256);
});

test('RSA follows the rows of SP 800-57 Table 2, with sizes between rows rounded down', () => {
  const expected = { 'RSA-1024': 80, 'RSA-2048': 112, 'RSA-3072': 128, 'RSA-4096': 128, 'RSA-7680': 192, 'RSA-15360': 256 };
  for (const [name, bits] of Object.entries(expected)) assert.equal(securityBits(name), bits, `${name} gives ${bits} bits`);
});

test('the curves follow SP 800-186', () => {
  const expected = { 'P-224': 112, 'P-256': 128, X25519: 128, Ed25519: 128, 'P-384': 192, Ed448: 224, 'P-521': 256 };
  for (const [name, bits] of Object.entries(expected)) assert.equal(securityBits(name), bits, `${name} gives ${bits} bits`);
});

test('names and sizes the tables do not list throw', () => {
  for (const name of ['RSA-512', 'AES-100', 'DES', 'P-255', 'RSA-abc', 'RSA-']) assert.throws(() => securityBits(name), `"${name}" should throw`);
});
A hint

Keep the curves in a dictionary (an object in JavaScript), and the RSA rows in a list from the largest size down: return the strength of the first row whose size the key reaches. Split a name such as RSA-3072 at the hyphen and check that the part after it is all digits before you turn it into a number.

The sample tests run on this device, in your browser (Pyodide, QuickJS): nothing is sent to mysmartcopilot.com. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Exercise · Easy · Python, JavaScript

Size random identifiers with the birthday bound

Write collision_probability(count, bits) in birthday.py (JavaScript: collisionProbability(count, bits) in birthday.mjs): the chance that at least two of count values, each drawn at random from 2**bits possibilities, are the same. Use the lesson's formula, 1 − exp(−n(n − 1) / 2^(bits + 1)) with n = count.

Two things decide whether your answer is useful. The chances that matter in security are tiny, such as 1.5 × 10⁻²¹ for a billion 128-bit identifiers, and 1 - exp(-x) rounds them to 0, so compute it with expm1. And the result must never be negative or above 1. A count below 0 or bits below 1 raises ValueError (JavaScript: throws). The starter code makes both classic mistakes, and the sample tests include the limit of NIST SP 800-38D: 2³² random 96-bit nonces under one key.

Python · Starter code · birthday.py

import math


def collision_probability(count, bits):
    """The chance that count random values of the given number of bits are not all different."""
    # Two classic mistakes: 2 ** bits where the formula has 2 ** (bits + 1), and 1 - exp(...),
    # which rounds every tiny chance to 0. Fix both.
    return 1 - math.exp(-count * count / 2**bits)
The sample tests · test_birthday.py
import math

from birthday import collision_probability


def close(got, want):
    return math.isclose(got, want, rel_tol=1e-9, abs_tol=0.0)


def raises_value_error(count, bits):
    try:
        collision_probability(count, bits)
    except ValueError:
        return True
    return False


def test_nist_sp_800_38d_nonce_limit():
    """2**32 random 96-bit nonces under one key: about 2**-33, the limit of NIST SP 800-38D"""
    assert close(collision_probability(2**32, 96), 1.164153217930535e-10)


def test_64_bit_identifiers():
    """2**32 random 64-bit identifiers collide with a chance of about 0.39"""
    assert close(collision_probability(2**32, 64), 0.3934693402167571)


def test_tiny_chances_are_not_zero():
    """a billion and a million 128-bit identifiers: tiny chances, but not 0"""
    assert close(collision_probability(10**9, 128), 1.4693679370584914e-21)
    assert collision_probability(10**6, 128) > 0


def test_edges():
    """no value or one value cannot collide; huge counts give a chance of 1"""
    assert collision_probability(0, 64) == 0
    assert collision_probability(1, 64) == 0
    assert close(collision_probability(10**12, 32), 1.0)


def test_bad_arguments_raise():
    """a negative count or fewer than 1 bit raises ValueError"""
    assert raises_value_error(-1, 64)
    assert raises_value_error(10, 0)

JavaScript · Starter code · birthday.mjs

/** The chance that count random values of the given number of bits are not all different. */
export function collisionProbability(count, bits) {
  // Two classic mistakes: 2 ** bits where the formula has 2 ** (bits + 1), and 1 - exp(...),
  // which rounds every tiny chance to 0. Fix both.
  return 1 - Math.exp((-count * count) / 2 ** bits);
}
The sample tests · birthday.test.mjs
import { test, assert } from 'mysmartcopilot:test';
import { collisionProbability } from './birthday.mjs';

const close = (got, want) => Math.abs(got - want) <= 1e-9 * Math.abs(want);

test('2**32 random 96-bit nonces under one key: about 2**-33, the limit of NIST SP 800-38D', () => {
  assert.ok(close(collisionProbability(2 ** 32, 96), 1.164153217930535e-10), String(collisionProbability(2 ** 32, 96)));
});

test('2**32 random 64-bit identifiers collide with a chance of about 0.39', () => {
  assert.ok(close(collisionProbability(2 ** 32, 64), 0.3934693402167571), String(collisionProbability(2 ** 32, 64)));
});

test('a billion and a million 128-bit identifiers: tiny chances, but not 0', () => {
  assert.ok(close(collisionProbability(1e9, 128), 1.4693679370584914e-21), String(collisionProbability(1e9, 128)));
  assert.ok(collisionProbability(1e6, 128) > 0, 'a million 128-bit values');
});

test('no value or one value cannot collide; huge counts give a chance of 1', () => {
  assert.ok(collisionProbability(0, 64) === 0, 'no values');
  assert.ok(collisionProbability(1, 64) === 0, 'one value');
  assert.ok(close(collisionProbability(1e12, 32), 1));
});

test('a negative count or fewer than 1 bit throws', () => {
  assert.throws(() => collisionProbability(-1, 64));
  assert.throws(() => collisionProbability(10, 0));
});
A hint

Python: -math.expm1(-x) equals 1 - math.exp(-x) but keeps its precision when x is tiny. JavaScript has Math.expm1 too. Check the arguments first, then compute x = count * (count - 1) / 2 ** (bits + 1).

The sample tests run on this device, in your browser (Pyodide, QuickJS): nothing is sent to mysmartcopilot.com. The first run of each language downloads it: Python (about 13.5 MB) or JavaScript (about 0.6 MB), which is kept for the next runs. A check in your browser is feedback for you, not proof that the code is right for every input.

Password Strength Checker See how many bits of guessing a password resists, and set it against the 128 bits of an AES-128 key.

Then take a mixed run through all five ideas: the first questions target your weakest idea, a right answer raises the level, and anything you miss comes back before you finish:

Practice that adapts to you

Practise this lesson

12 questions about 5 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 12 What does it mean that an algorithm gives 128 bits of security?

    Choose one answer.

    Show the answer: Question 1 of 12

    Answer: The best known attack takes about 2¹²⁸ operations

    Strength in bits compares unlike algorithms by the work needed to break them: about 2ˢ operations for s bits.

  2. Question 2 of 12 Attackers' hardware becomes 1,000 times faster. About how many bits of a key's margin does that take away?

    Choose one answer.

    Show the answer: Question 2 of 12

    Answer: About 10 bits

    Every factor of two in speed is one bit. A thousandfold speed-up is about ten bits, which is why designs keep a wide margin above any estimate.

  3. Question 3 of 12 How many bits of security does RSA-2048 give in NIST SP 800-57's Table 2?

    Type a number.

    Show the answer: Question 3 of 12

    Answer: 112 bits

    RSA-2048 sits in the 112-bit row with three-key triple DES and curves of 224 to 255 bits. For 128 bits RSA needs 3,072.

  4. Question 4 of 12 In digital signatures, where collisions matter, how many bits of security does SHA-256 give according to SP 800-57's Table 3?

    Choose one answer.

    Show the answer: Question 4 of 12

    Answer: 128

    The same hash has two strengths: 128 bits against collisions and 256 against finding an input for a given output.

  5. Question 5 of 12 An audit checks ASVS 5.0 requirement 11.2.3, at least 128 bits for every primitive. Which configuration fails?

    Choose one answer.

    Show the answer: Question 5 of 12

    Answer: Firmware signed with RSA-2048

    Of the four, only RSA-2048 falls short. Moving to RSA-3072, or to Ed25519 for new signatures, meets the requirement.

  6. Question 6 of 12 What chance does the exact product give that two of 23 people share a birthday, with 365 days in the year?

    Choose one answer.

    Show the answer: Question 6 of 12

    Answer: About 0.507

    The surprise comes from the pairs: 23 people make 253 of them. Random values work the same way, which is why collisions arrive near the square root of the space.

  7. Question 7 of 12 Why does a 256-bit hash give only about 128 bits of collision resistance?

    Choose one answer.

    Show the answer: Question 7 of 12

    Answer: By the birthday bound, about 2¹²⁸ random inputs are enough to make two of them share a digest

    With n inputs there are about n²/2 pairs, so a collision becomes likely once n²/2 approaches 2²⁵⁶, at n near 2¹²⁸.

  8. Question 8 of 12 A function that computes 1 - math.exp(-x) returns 0.0 for a billion 128-bit identifiers. What is wrong, and what is the fix?

    Choose one answer.

    Show the answer: Question 8 of 12

    Answer: exp(-x) rounds to exactly 1.0 when x is tiny, so the difference is 0; use -math.expm1(-x)

    Subtracting from 1 throws away every digit below about 10⁻¹⁶. expm1 computes eˣ − 1 directly, so tiny chances keep their value.

  9. Question 9 of 12 What does RFC 9958 conclude about AES-128 against Grover's algorithm?

    Choose one answer.

    Show the answer: Question 9 of 12

    Answer: It remains secure in practice, though some agencies recommend AES-256

    In theory Grover would take a 128-bit key search to about 2⁶⁴ quantum steps; in practice RFC 9958 judges AES-128 safe, and AES-256 is the choice where a policy demands extra margin.

  10. Question 10 of 12 In NIST's draft IR 8547, what happens to ECDSA on P-256, a 128-bit configuration, after 2035?

    Choose one answer.

    Show the answer: Question 10 of 12

    Answer: It is disallowed, like every quantum-vulnerable public-key algorithm

    The draft separates two steps: 112-bit public keys deprecated after 2030, and quantum-vulnerable public keys of every size disallowed after 2035. It is still a draft and may change.

  11. Question 11 of 12 A design adopts a 128-bit floor. Which of these choices does that floor rule out?

    Choose one answer.

    Show the answer: Question 11 of 12

    Answer: RSA-2048 signatures

    The floor removes every 112-bit option, of which RSA-2048 is the one still common in practice.

  12. Question 12 of 12 Once two sides share a key, which kind of algorithm encrypts the data itself?

    Choose one answer.

    Show the answer: Question 12 of 12

    Answer: A symmetric cipher such as AES

    Real systems combine the two: a public-key step agrees or moves a key, and a symmetric cipher such as AES-GCM encrypts the data with it.

Interview questions

Warm-up (fresher to mid level): what does it mean that RSA-3072 and AES-128 both give 128 bits of security?

It means that the best known attack on each takes about 2¹²⁸ operations, so both are equally far out of reach, not that their keys are alike. For AES-128 the best attack is close to trying every key, so its 128-bit key gives 128 bits. RSA is attacked by factoring its modulus, which is much cheaper than trying keys, so it needs a 3,072-bit modulus to reach the same level, as NIST SP 800-57’s Table 2 shows; RSA-2048 only reaches 112. An elliptic curve needs about 256 bits for 128. The number lets you compare unlike algorithms and set one floor for a whole system, such as the 128 bits of ASVS 5.0. Against a large quantum computer the comparison breaks: RSA would fall outright, while AES-128 would stay secure in practice, because Grover’s search cannot be spread well across machines.

Model answers open with any pass: ₹79 for 1 week ($2.99), one payment that never renews.

  1. Fresher to senior

    A multi-region service gives random identifiers to 10 billion records over its life, with no central check for duplicates. How many random bits do the identifiers need so that the chance of any duplicate stays below one in a million? Show the calculation.

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  2. Mid to staff

    An audit against a 128-bit floor flags RSA-2048 in three places: TLS certificates, signatures on firmware for devices that stay in the field for 15 years, and key transport for backups that must stay confidential for 20 years. Prioritise and plan the changes.

    Model answer, Pro. First step and follow-ups

Flashcards · 8 cards

Recall it, then check

Say the answer to yourself before you look: recalling it is what makes it stick.

  1. What does n bits of security mean, and how long does searching a 56-bit and a 128-bit key take?

    NIST defines security strength as the work needed to break an algorithm: s bits means about 2^s operations (112, 128, 192 or 256). Each extra bit doubles the work. At a trillion guesses a second a 56-bit key falls in 20 hours; a 128-bit key needs about 1.1 × 10^13 years even at a billion billion a second.

  2. Why is RSA-2048 not 2,048 bits of security?

    Strength follows the best attack, not the key size. Factoring the modulus is far cheaper than trying 2^2048 keys, so RSA-2048 gives 112 bits. Only for a good symmetric cipher do the key size and the strength match.

  3. Which AES, RSA and elliptic-curve sizes give 112, 128, 192 and 256 bits of security?

    112: three-key triple DES, RSA-2048, P-224. 128: AES-128, RSA-3072, P-256 or Curve25519. 192: AES-192, RSA-7680, P-384. 256: AES-256, RSA-15360, P-521. These are the pairings of NIST SP 800-57 Part 1, Table 2.

  4. Why does a 256-bit elliptic curve give 128 bits of security?

    The best known attacks need about the square root of the size of the curve's group, so a curve gives about half the bit length of its group order (SP 800-186). A 256-bit curve therefore gives 128 bits, with private keys of 32 bytes.

  5. How many bits of security does SHA-256 give, and why are there two answers?

    128 bits where collisions matter, as in digital signatures, and 256 bits where only finding an input for a given output matters, as in HMAC and key derivation (SP 800-57, Table 3). Finding any two inputs with the same digest takes about 2^128 tries, not 2^256.

  6. After how many random b-bit values does a repeat become likely?

    After about 1.18 × 2^(b/2): the square root of the number of possibilities, not the number itself. Among 23 people the chance of a shared birthday is already 50.7 %, although a year has 365 days. Size hashes, nonces and identifiers for the square root of their space.

  7. How many encryptions may one AES-GCM key make when its 96-bit nonces are random?

    At most 2^32. Among 2^32 random 96-bit nonces a repeat has a chance of about 1.2 × 10^-10, and NIST SP 800-38D requires that chance to stay at 2^-32 or below. A repeated nonce with one key can break the protection.

  8. What would a large quantum computer change for RSA, elliptic curves and AES, and what is 'harvest now, decrypt later'?

    Shor's algorithm would break RSA, Diffie-Hellman and every elliptic curve outright; longer keys would not save them. Grover's search is only quadratic, and RFC 9958 argues AES-128 stays secure. Traffic recorded today can be decrypted later, so data that must stay secret for years needs quantum-resistant key exchange now.

Key takeaways

  • n bits of security means about 2ⁿ operations to break it; each extra bit doubles the work, and 128 bits is far beyond any search, even at a billion billion guesses a second.
  • Key size equals strength only for a good symmetric cipher: AES-128, RSA-3072 and a 256-bit curve all give 128 bits, while RSA-2048 gives 112.
  • Random values of b bits collide after about 2^(b/2) of them, which is why a 256-bit hash gives 128 bits of collision resistance and a key of AES-GCM with random nonces is capped at 2³² encryptions.
  • Shor’s algorithm would break RSA and elliptic curves at any size and Grover’s would weaken symmetric keys only modestly, so key exchange for long-lived secrets moves to ML-KEM first.
  • For a new design: a 128-bit floor, AES and modern curves today, and a hybrid post-quantum key exchange wherever data must stay secret beyond 2035.

Terms in this lesson

birthday bound
The rule that random values of b bits start to repeat after about 2^(b/2) of them. It is why a 256-bit hash gives about 128 bits of collision resistance and why random nonces have usage limits.
exhaustive key search
Trying every possible key until one works, also called brute force. Each extra key bit doubles its cost; for a well-designed cipher no attack does better.
Grover's algorithm
A quantum search algorithm with a quadratic speed-up: in theory a search of 2^128 keys would take about 2^64 steps. It weakens symmetric keys and hashes only modestly in practice.
harvest now, decrypt later
Recording encrypted traffic today in order to decrypt it once a large quantum computer exists. It makes quantum-resistant key exchange urgent for secrets that must last for years.
nonce
A value used only once with a given key, such as the 96-bit nonce of AES-GCM. Repeating one can break the protection, so nonces come from a counter or from enough random bits.
security strength
The work needed to break an algorithm, in bits: s bits means about 2^s operations. NIST uses the levels 112, 128, 192 and 256 to compare unlike algorithms, such as AES-128 and RSA-3072.
Shor's algorithm
A quantum algorithm that factors numbers and computes discrete logarithms efficiently. On a large enough quantum computer it would break RSA, Diffie-Hellman and elliptic-curve cryptography at any key size.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.