Back to the journalNOTES BY FAJAR
Cryptography7 min read

[Crypto: age] How Long Does a Passphrase Attack Take?

Calculate age passphrase attack times, understand the assumptions, and see why random selection matters more than password length alone.

PART 6 OF 6Crypto: age
  1. 01[Crypto: age] From Password to Ciphertext
  2. 02[Crypto: age] Reading the Header
  3. 03[Crypto: age] scrypt, From Password to Key
  4. 04[Crypto: age] ChaCha20-Poly1305, Sealing the Body
  5. 05[Crypto: age] Passphrase or Key Pair
  6. 06[Crypto: age] How Long Does a Passphrase Attack Take?You are here
In this article 7 sections

An attacker with a copy of an age file can try passphrases on their own computer. No server limits the number of attempts. The time depends on the attempt rate and how soon the attacker tries the correct passphrase.

The scrypt post gave the cost of one calculation. This final post uses recorded measurements to calculate example attack times. The calculations are estimates under stated assumptions, not expiry dates for passwords.

What one attempt does

In this series, a guess means one candidate passphrase. A brute force attack tries each candidate in a defined set. A dictionary attack tries likely candidates, such as common passwords, first.

An attacker can use this procedure for an age passphrase file:

  1. Read the salt and work factor from the header.
  2. Derive a wrapping key with scrypt and a candidate passphrase.
  3. Try to decrypt the file key with that wrapping key.
  4. Test the authentication tag on the encrypted file key.

An incorrect candidate fails at the file key. The attacker does not have to decrypt the complete payload for each attempt. The cipher post shows this authentication check.

A generic scrypt benchmark measures the expensive part of the attempt. It does not measure the complete age decryption process. Support for the age format in a specified attack tool is a separate question.

The recorded laptop measurements

The initial measurements used an Apple M5 with 10 cores and work factor 18. A core is a processor unit that executes program instructions. A parallel test runs multiple operations at the same time.

The recorded rates were:

MethodRecorded rate each second
age command, one decryption attempt at a time2.6 attempts
scrypt calculation, one core2.7 calculations
scrypt calculations, all 10 cores in parallel8.2 calculations

These are the measurements recorded for the initial article. The series includes the code for the sequential scrypt measurement. It does not include the initial parallel test program or raw timing records.

The tables below use 8.2 attempts each second as an example rate based on the parallel scrypt result. They do not establish the performance of an optimized attack implementation.

The parallel rate was about three times the sequential rate in those results. That observation alone does not prove a memory bandwidth limit. Scheduling, memory access, and implementation details can affect the result.

What the memory requirement tells us

At the example parameters, the primary scrypt memory area is about 256 MiB for each attempt. Ten calculations at the same time use about 2.5 GiB, plus other program memory.

A graphics processing unit, or GPU, can perform many calculations in parallel. Its available memory still limits how many scrypt calculations fit at once.

For a hypothetical device with 24 GiB of usable memory:

text
24 GiB = 24576 MiB
24576 MiB / 256 MiB per calculation = 96 calculations

This memory capacity gives a maximum of 96 calculations at the same time, before other memory allocations. It is not a rate of 96 attempts each second. The time for each calculation is also necessary to calculate a rate.

The recorded measurements do not include a GPU benchmark. The memory calculation does not prove that a GPU provides no advantage. A faster implementation, more hardware, or different memory tradeoffs can change the result.

Calculate an exhaustive search time

An exhaustive search tries all combinations in a set. For a random string of a fixed length, the number of combinations is:

text
combinations = alphabet size raised to the power of string length
full search time = combinations / attempts per second

For example, an alphabet with 26 lowercase letters and a length of 6 gives 308,915,776 combinations. At 8.2 attempts each second, a full search takes about 1.2 years.

The tables use these assumptions:

  • Each character comes from an independent random selection.
  • Every character in the stated alphabet has the same probability.
  • The attacker knows the alphabet and exact length.
  • The attack rate stays constant, with no repeated candidates.
  • One year is 365.25 days.

Each cell gives the time for the complete set. Under these assumptions, the average time to reach the correct candidate is approximately half that value. A successful first attempt is still possible.

At the example rate of 8.2 attempts each second:

Alphabet6 characters8 characters10 characters12 characters
26 lowercase letters1.2 years807 years545,526 years369 million years
26 lowercase letters and 10 digits8.4 years10,902 years14.1 million years18.3 billion years
52 uppercase and lowercase letters and 10 digits219 years843,754 years3.24 billion years12.5 trillion years

A second table uses a hypothetical rate of 1,000 attempts each second. This rate is about 122 times faster. It is an assumption, not a measured age benchmark.

Alphabet6 characters8 characters10 characters12 characters
26 lowercase letters3.6 days6.6 years4,473 years3.02 million years
26 lowercase letters and 10 digits25.2 days89.4 years115,857 years150 million years
52 uppercase and lowercase letters and 10 digits1.8 years6,919 years26.6 million years102 billion years

The Python code reproduces the calculations before rounding. It also calculates the random word examples in the next section.

python
seconds_per_year = 365.25 * 24 * 60 * 60

for rate in (8.2, 1000):
    print(f"\nAttempts per second: {rate}")
    for alphabet_size in (26, 36, 62):
        for length in (6, 8, 10, 12):
            combinations = alphabet_size ** length
            seconds = combinations / rate
            years = seconds / seconds_per_year
            print(alphabet_size, length, f"{years:.3g} years")

for word_count in (4, 5, 6):
    combinations = 7776 ** word_count
    years = combinations / 8.2 / seconds_per_year
    print(word_count, f"{combinations:.3g} combinations", f"{years:.3g} years")

Why a common password does not fit those tables

A person often chooses a name, a date, or a familiar word. An attacker can try those choices before unrelated strings of the same length. Thus, the full character set is the wrong model for that password.

At 8.2 attempts each second, a list of one million candidates takes about 33.9 hours to complete. If the correct candidate is near the start, the attack finishes much earlier.

Passwords such as password1 and summer2026 follow familiar patterns. Their lengths do not justify the random string estimates above. scrypt adds a cost to each attempt, but it does not change the order in which an attacker tries candidates.

Random words increase the number of combinations

A passphrase can use words from a list. For the calculation below, the list contains 7,776 words. Each word must come from an independent random selection, with equal probability for each word.

Four such words give 7776^4 combinations, or about 3.66 quadrillion. The estimate assumes that the attacker knows the list, the word count, and the separator.

Number of random wordsCombinationsFull search at 8.2 attempts each second
4About 3.66 quadrillionAbout 14.1 million years
5About 2.84 × 10^19About 110 billion years
6About 2.21 × 10^23About 854 trillion years

In scientific notation, 2.84 × 10^19 means 2.84 multiplied by 10 raised to the power 19. The notation keeps very large numbers readable.

Words that form a favorite quotation or a sentence you invent do not meet the random selection assumption. Adding more words helps only according to the choices those words add. A short passphrase is not automatically stronger than a long password.

The EFF dice method gives a procedure for random word selection and recommends six words. The four word row above is a calculation example, not that recommendation.

Choose a method you can keep secure

The key pair post shows encryption without a human passphrase. In that path, the recipient must keep the secret key private and available for decryption.

For passphrase encryption, age can generate a random passphrase at its prompt. A password manager can store it. The reader does not have to memorize a predictable phrase to make decryption convenient.

mermaid
graph TD
    A["Who must encrypt the file?"] --> B{"A script or another person?"}
    B -->|Yes| C["Consider a public key recipient"]
    C --> D["Keep a secure backup of the secret key"]
    B -->|No| E["A random passphrase is an option"]
    E --> F["Store the passphrase securely"]

I trust a passphrase that I can measure more than one that I hope is strong. The useful measure is how the passphrase was selected, together with an explicit model of the attack. The tables cannot predict the lifetime of an individual password.

FILED UNDER

THANKS FOR READING

Did this resonate?

A reaction or a conversation is always welcome.

Loading reactions…

Pass it along

Loading comments...

KEEP EXPLORING

One thought leads to another.

All writing
Back to all writingOne note at a time.