Dictionary attack — Comprehensive operation

Project reference document Time2Crack
Recipients: developers, security researchers, advanced users

Contents

  • Overview
  • Historical and academic background
  • Conceptual foundations: why dictionaries work
  • Architecture of a modern dictionary attack
  • The corpus of real passwords
  • K-Anonymity HIBP verification: a real-time attack
  • Time2Crack Language Wordlists
  • Dictionary Detection in Time2Crack: isDictWord()
  • De-leetification: how the attacker decodes substitutions
  • Calculation of cracking time: addDictionaryAttacks()
  • High fidelity calibration: applyHighFidelityCalibration()
  • Likelihood of applicability and confidence score
  • Bloom filter RockYou : local detection of widespread passwords
  • Comparison with derived attacks
  • Limitations of attack dictionary
  • Effective defences
  • References

  • 1. Overview

    Dictionary attack is the oldest password cracking method, the simplest conceptually, and statistically most effective on the majority of real human passwords. Its principle is to test, in descending order of probability, a pre-compiled list of candidates — the "dictionary" — rather than exhaustively enumerate all possible combinations as the raw force does.

    Why it's dreadfully effective Humans do not choose their passwords randomly. Decades of data leaks reveal that the actual distribution of passwords is extremely concentrated: the most common 1,000 passwords represent about 5 to 10% of all online accounts. The most common 1 million cover 40 to 60%. A well-built dictionary attack will test these candidates in milliseconds to seconds — where gross force would take millions of years.

    In Time2Crack, the dictionary attack models two distinct but complementary mechanisms:

  • HIBP verification (Have I Been Pwned): Confrontation of the password to the ~14 billion unique credentials from historical data leaks. If the password is there, an attacker would discover it in a fraction of a second.
  • Language Wordlist Detection A common language word — "sun" or "sunshine" — is vulnerable even if it is not in HIBP.
  • These two detections are independent and complementary: HiBP covers the exact compromise credentials, the wordlist covers the common words not yet leaked.


    2. Historical and academic background

    2.1 Origins

    The dictionary attack precedes the modern era of computer security. The first Unix systems stored passwords in plain language in /etc/passwd, making any dictionary attack trivial as soon as the file was accessible.

    Chronology of milestones : YearEvent ------------------- 1979Morris & Thompson: First academic article on Unix password security. See that 1/3 of passwords choose common English words 1988Morris Worm: partially propagates via a 432 word dictionary + host /usr/share/dict/words 1993Crack 5.0 (Alec Muffett): First public dictionary attack tool on Unix, includes mutation rules 2000John the Ripper: popularizes wordlists combined with hashcat rules (wordlist + rules mode) 2009RockYou leak: 14.3 million clear passwords reveal the real distribution of human choices 2012Have I Been Pwned (Troy Hunt): first public audit service for compromised credentials 2013Adobe break: 153 million accounts — top passwords become identifiable by frequency analysis even on unsalted hashs 2016Hashcat open source v3.0: massive optimization of wordlist attacks on GPU (MD5: 2 TH/s on 8 GPU cluster) 2019Collection #1–5: 2.7 billion login/password pairs compiled, publicly distributed 2024HIBP v8: ~14 billion unique passwords indexed

    2.2 Founding leaks

    Some leaks have transformed the landscape of the attack by dictionary by revealing the actual distribution of human passwords:

    RockYou (2009) A developer had stored 14.3 million passwords in plain language.
  • The first 10 passwords covered ~5% of accounts
  • First 1,000: ~20% of accounts
  • Distribution follows a power law — confirming that humans "think the same"
  • LinkedIn (2012) — 6.5 million non-salted SHA-1. Adobe (2013) — 153 million accounts. Have I Been Pwned (2013–present) - Progressive aggregation of public leaks, allowing Troy Hunt to create a reference base used worldwide.

    2.3 Reference Benchmarks for Dictionary Attack

    A wordlist of 200,000 entries tested at the speed of a RTX 4090:

    AlgorithmSpeedTime for 200k candidates ------------------------------------------------ MD5168.9 GH/s~1,2 nanosecond SHA-150.86 GH/s~3.9 nanoseconds SHA-25622.68 GH/s~8.8 nanoseconds NTLM288.5 GH/s~0,7 nanosecond bcrypt (cost 5)184 kH/s~1.09 second Argon2id~67 H/s~50 minutes

    The dictionary attack is therefore almost instantaneous for MD5, SHA-1 and NTLM — and remains very fast even for bcrypt on small lists.


    3. Conceptual foundations: why dictionaries work

    3.1 The Power Law of Human Passwords

    All empirical studies converge towards the same observation: the distribution of human passwords is not uniform — it follows a law of power (Zipf). Some passwords concentrate an disproportionate fraction of choices.

    Formally : if all passwords are classified by decreasing frequency, the frequency of the rank password r is proportional to r^(-α) with α 1.5 to 2 According to the corpus.

    Direct consequence: 10 most common passwords An attacker who tests only 10 candidates already has a chance in 20 to succeed — statistically, it's huge for the amount of noise generated.

    3.2 Cognitive Bias in Password Creation

    Humans do not choose at random. They systematically apply heuristics that make their passwords predictable:

  • Memory Bias : the words easy to remember (common names, first names, terms of popular culture) are overrepresented
  • Availability Bias The password reflects the immediate environment (domestic animal name, sports team, serial character)
  • Predictable substitution biases : "e" → "3", "a" → "@", "o" → "0" — the user believes the password to be strong, but these substitutions are exactly the first that the attacker tries to do
  • Complete Bias : addition of a number or symbol at the end of a word (password1, sunshine!)
  • Cultural bias Common passwords are linked to the language and culture of the user ("Soleil123" in France, "Sommer123" in Germany)
  • 3.3 The concept of "password already in the lists"

    A password may be in an attack list for two different reasons:

    Reason 1 — He's in HIBP The exact credential has been compromised in a past leak. The attacker does not need to guess — it tests the known credentials one by one, in order of frequency. If the target server accepts the credential, it is finished. Reason 2 — It is in a linguistic wordlist The password is an ordinary word of common vocabulary. Even if it has never fled, it is in all attack wordlists because it is an obvious candidate. "Paillon" may not be in HiBP, but it is in the French wordlist of any serious cracking tool.

    These two cases correspond to attacks of a different nature, with different speeds — and this is precisely what Time2Crack models.


    4. Architecture of a modern dictionary attack

    4.1 General pipeline

    A modern dictionary attack takes place in several phases:

    Phase 1 : Constitution de la wordlist
        ├── Mots de passe fuités (HIBP, RockYou, Collections)
        ├── Wordlists linguistiques (dictionnaires, prénoms, lieux)
        ├── Wordlists thématiques (sport, pop culture, tech, religion)
        └── Wordlists contextuelles (domaine de l'entreprise cible, noms d'employés)
    

    Phase 2: Wordlist Preprocessing - Sort by frequency (most likely first) - - Deduplication (not twice the same candidate) - - Length filtration (target length + ±2) - - Standardization (lowercase, Unicode NFC)

    Phase 3: Calculation of Candidate Hashs For each candidate w in the wordlist: │ hashcandidate = hashalgo(w) Promotional │ if hashcandidate== hashTarget : FINDED - - Speed: 168 GH/s for MD5 on RTX 4090

    Phase 4: Analysis of results Report of cracked passwords, coverage statistics

    4.2 Hardware optimizations

    Modern dictionary attacks are massively paralleled on GPU:

  • Hashcat (reference tool): exploits the CUDA cores of the GPU to parallelize billions of hash simultaneous computations
  • Vector Pipeline : on a RTX 4090, a single SIMD instruction calculates 8 to 16 MD5 hashs in parallel
  • GPU cache : the wordlist is loaded in VRAM to minimize memory latency
  • Batching : the candidates are sent to the GPU in batches of millions to maximize the flow
  • For a wordlist of 14 billion entries (HIBP size) on 12× RTX 4090:

  • MD5 : 14e9 / (168.9e9 × 12) 6.9 seconds
  • bcrypt cost 5 : 14e9 / (184000 × 12) 6,337 years
  • This difference of ~9 orders of magnitude between MD5 and bcrypt explains why the choice of the hash algorithm is critical.

    4.3 Test order of candidates

    The wordlist is not tested in alphabetical order — it is sorted by decreasing probability :

  • The most common escape passwords (RockYou top 100)
  • Common multi-fault passwords (HIBP priority list)
  • Common words of target language
  • The proper names (first names, cities, celebrities)
  • Target-related thematic terms
  • Variations and conjugations
  • This sort ensures that if the password is "low", it will be found in the first milliseconds — whatever the hash speed.


    5. The corpus of real passwords

    5.1 Have I Been Pwned (HIBP)

    Size ~14 billion unique passwords (2024) Source : aggregation of public leaks since 2013 Format : SHA-1 sorted by frequency of appearance Public access : k- anonymity API, full hash download available for defenders

    HiBP is the global reference because:

  • It covers almost all major public leaks
  • The hashs are sorted by frequency — the most common passwords are tested first
  • It is actively maintained (new leaks added continuously)
  • An attacker with the complete HIBP dump can first test the ~14 billion candidates in descending order of frequency. For non-salted algorithms (MD5, SHA-1), this list covers in the order of 50-70% of all real online passwords.

    5.2 RockYou (2009) — Founding corpus

    Size : 14.3 million clear passwords Key characteristics : RankPasswordOccurrences% of corpus ------------------------------------------------ 1123456290 7312.03% 21234579 0780.55% 312345678976 7900.54% 4password59 4620.42% 5iloveyou49 9520.35% Top 10—~650,000~4.5% Top 100—~1 200 000~8.4% Top 1 000—~2 500 000~17.5% Top 10,000—~4 500 000~31.5% Education Test only 10,000 candidates (100 μs MD5 speed) compromises ~31% of a database of MD5 protected accounts.

    5.3 Collections of specialized wordlists

    SecLists (Daniel Miessler): open-source collection of ~4 GB wordlists covering:
  • Passwords (RockYou, top passwords various leaks)
  • Current uses
  • Passwords sorted by language
  • Technical terms, product names, celebrities
  • Kaonashi : 1.3 billion entries wordlist compiled since public leaks Crackstation : 1.5 billion entries including words from all Wikipedia dictionaries in several languages Weakpass : aggregation of ~8 billion single real password entries

    These corpuses are publicly downloadable — their existence is an established fact of offensive security.


    6. K-Anonymity Verification HIBP: A Real-Time Attack

    6.1 Protocol k- anonymity

    Time2Crack incorporates a real-time HIBP check that reproduces exactly what an attacker would do with the HIBP database — but never transmit the password in plain language or its full hash.

    The k-anonymity protocol works as follows:

    1. Calculer SHA-1(password)      → par exemple "CBFDAC6008F9CAB4083784CBD1874F76618D2A97"
    
  • Send only the first 5 characters to the HIBP API: "CBFDA"
  • The API returns ALL SHA-1 suffixes starting with "CBFDA" (approximately 400-600 hashes)
  • Search locally if the rest of the hash ("C6008F9CAB4083784CBD1874F76618D2A97") is in the list
  • If found: password has been compromised (HIBP also returns the number of leaks)
  • Guarantee of confidentiality The HIBP server never sees the complete hash (so it cannot identify the password), let alone the clear password. The final calculation is done locally. What this means for the attack : if HIBP returns a match with a high count (e.g. 9,547,236 appearances for "123456"), this means that an attacker with the HIBP database testing this credential would find him in a very high position on his list sorted by frequency — in a fraction of nanoseconds.

    6.2 Implementation in Time2Crack (app.js)

    The HIBP check is asynchronous and non-blocking. The password is immediately analyzed by local methods, and the HIBP check completes the result:

    // Pseudo-code simplifié
    async function checkHIBP(password) {
      const sha1 = await sha1Hash(password);
      const prefix = sha1.substring(0, 5);   // 5 premiers chars
      const suffix = sha1.substring(5);       // reste du hash
    

    const response = await fetch( https://api.pwnedpasswords.com/range/${prefix} ); const lines = await response.text();

    for (const line of lines.split('\n')) { const [hashSuffix, count] = line.split(':'); if (hashSuffix.toLowerCase() = suffix.toLowerCase()) { return parseInt(count); // number of leaks } } return 0; // not found }

    HIBP performance data :
  • Typical API latency: 50–200 ms (network)
  • Volume of suffixes returned: ~400–600 per query
  • False positive: 0 (SHA-1 is deterministic)
  • False negative: 0 (if in HiBP, always returned)
  • 6.3 Interpretation of Count HIBP

    The count returned by HiBP indicates the number of times this exact password appeared in indexed leaks:

    CountInterpretationCrack time (MD5, 12× RTX 4090) ------------------------------------------------------------ > 1 000 000Top 100 World< 1 nanosecond 10,000–1,000,000Very common< 10 nanoseconds 1 000–10 000Common< 100 nanoseconds 100–1,000Uncommon but known< 1 microsecond 1–100Rare but compromised< 10 microseconds

    Even a count of 1 (the password appeared only once in a leak) indicates a vulnerability: if an attacker targets this account specifically and has the list of credentials of the leak in question, he will find it.


    7. Time2Crack Language Wordlists

    7.1 Why language wordlists in addition to HIBP

    HiBP covers the exact compromise credentials — but not the common words never run away yet. A francophone user who chooses "ephemeral" as a password may not be in HiBP (the word is unlikely in anglophone credentials), but it is in the French wordlist of any attacker targeting a francophone system.

    Time2Crack's language wordlists cover this gap:

    LanguageSourceEstimated size -------------------------------- EnglishSecLists Wikipedia EN~200,000 entries French (fr)SecLists Wikipedia EN~150,000 entries SpanishSecLists Wikipedia ES~150,000 entries Portuguese (pt)SecLists Wikipedia PT~120,000 entries GermanSecLists Wikipedia DE~180,000 entries Turkish (tr)SecLists Wikipedia TR~100,000 entries Italian (it)kkrypt0nn~100,000 entries Polish (pl)kkrypt0nn~80 000 entries Netherlands (nl)kkrypt0nn~80 000 entries Filtering applied Only words of ≥ 4 characters are retained (the 1–3 characters are too short to be a realistic password, and their inclusion would inflate the list without added value).

    7.2 Lazy loading

    Wordlists are not included in the code — they are loaded on request when changing language, to meet the network budget:

    // app.js - loadDictionary()
    async function loadDictionary(lang) {
      if (DICTlang & DICTWORDS) return;  // Déjà chargé
      if (DICTLOADING) {
    DICTPENDINGLANG = lang; // Waiting file
    return;
    }
    DICTLOADING = true;
    

    const res = await fetch(data/wordlists/${lang}.txt); const text = await res.text();

    // Convert to Set<string> for O(1) lookup DICTWORDS = new Set( text.split("\n") .map(w => w.normalize("NFC").trim().toLowerCase()) .filter(w => w.length >= 4) ); DICTLANG = Lang; DICTLOADING = false; }

    Why a Set ? Structure Set JavaScript guarantees O(1) lookups — regardless of dictionary size (50,000 or 200,000 entries), verification DICTWORDS.has(word) takes the same constant time. Array would require O(n) per lookup, i.e. up to 200,000 comparisons per check.

    Loading queue

    The DICTPENDINGLANG avoids race conditions during rapid language changes:

    Scénario : l'utilisateur switche rapidement EN → FR → DE
    ├── EN demandé : DICTLOADING = false → start of the fetch EN
    FR requested during fetch EN : DICTLOADING = true → DICTPENDINGLANG = "fr"
    ├── DE demandé pendant fetch EN : DICTLOADING = true → DICTPENDINGLANG = "de" (crash "fr")
    - Fetch Ends: DICTLANG = "en", puis lance loadDictionary("de")
    └── Résultat : seule la dernière langue demandée est chargée

    This behaviour is intentional: the most recently requested language is loaded, not all intermediate languages.


    8. Dictionary Detection in Time2Crack: isDictWord()

    8.1. Detection operation

    The function isDictWord(pw) determines whether a password is or is derived from a current dictionary word:

    // app.js - ligne 2181
    function isDictWord(pw) {
      if (!DICT(WORDS) return false;
    

    // Standardization: NFC + Lowercase const l = pw.normalize("NFC").toLowerCase();

    // Direct verification if (DICT)

    WORDS.has(l) || DICTWORDS.has(deLeet(pw)) return true;

    // Morphological variations const deleetWord = deLeet(pw); const variations = getMorphVariations(deleetWord);

    for (const variation of variations) { if (DICT)

    WORDS.has(variation)) return true; }

    return false; }

    3 layer detection line :
  • Direct correspondence : Is the standard password in the dictionary as it stands?
  • "sun" → direct hit
  • "SOLEIL" → standard in "sun" → hit
  • After-leetification correspondence : Does the password contain standard let substitutions?
  • "s0l3il" → deLeet → "sun" → hit
  • "p@ssw0rd" → deLeet → "password" → hit
  • Morphological variations : is the password a known morphological variant?
  • "sun" → plural variation of "sun" → hit
  • "passwords" → variation of "password" → hit
  • 8.2 Unicode Standardization (NFC)

    Standardization normalize("NFC") ensures that accented characters are treated consistently:

  • "e" can be represented in Unicode as a single point code (U+00E9) or as "e" + combining accent (U+0065 + U+0301)
  • Without standardization, "coffee" and "coffee" (different encodings) would not match
  • This standardization is applied both when creating the dictionary and when checking — ensuring correct correspondence for accent languages (FR, ES, DE, PT, etc.).

    8.3 Impact on vulnerability detected

    When isDictWord() Go back trueseveral attacks become applicable:

  • Dictionary attack self: confidence score 0.85 (vs 0 if absent)
  • Hybrid attack : hybridVuln = true → 1000 mutations tested on dictionary basis
  • PCFG attack : increased confidence score (lexical base detected)
  • Morphological attack : high priority if morphological variant detected

  • 9. De-leetification: how the attacker decodes substitutions

    9.1 Leetspeak and its limitations as protection

    The leetspeak (or "1337 speech") is a practice of replacing letters with visually similar numbers or symbols: a→@, e→3, i→1 or !, o→0, s→$. Users use it to "strengthen" common words.

    Example : "password" → "p@$$w0rd"

    The reality: these substitutions are the first rules applied in any dictionary attack with rules of mutation. They do not constitute a real defense against a competent attacker.

    9.2 Implementation of deLeet() in Time2Crack

    // app.js - ligne 3622
    const LEETBASE = {
    a: ["@", "4"],
    e: ["3"],
    o: ["0"],
    s: ["$", "5"],
    t: ["+", "7"],
    h: ["#"],
    g: ["9"],
    };
    

    function ofLeetWith(pw, oneMap) { let r = pw.normalize("NFC").toLowerCase(); for (const [ch, reps] of Object.entries(LEET)

    BASE)) for (const c of reps) r = r.split(c).join(ch); // Appliquer la résolution ambiguë (i ou l) en dernier for (const [ch, reps] of Object.entries(oneMap)) for (const c of reps) r = r.split(c).join(ch); return r; }

    function ofLeet(pw) { // Ambiguity: "1" may be "i" or "l" const withI = deLeetWith(pw, { i: "1!", l: "" }); const withL = deLeetWith(pw, { l: "1", i: "!" });

    // If the dictionary is loaded, prefer the variant that matches if (DICT)WORDS) { if (DICT)WORDS.has(withL)) return withL; if (DICT)WORDS.has(withI) return withI; }

    // Otherwise: prefer the variant with the least remaining numbers const digestsI = (withI.match(/\d/g) const digestsL = (withL.match(/\d/g) return digit L <= digit I ? withL: withI; }

    9.3 Ambiguity Management "1" → "i" or "l"

    The substitution "1" is ambiguous: "1" can represent "i" (as in "1nfo" → "info") or "l" (as in "p1ayer" → "player"). Time2Crack resolves this ambiguity by:

  • Testing both variants ("withI" and "withL")
  • If the dictionary is loaded, preferring the variant that gives a dictionary match
  • Without a dictionary, preferring the variant that leaves the fewest residual numbers (assumption: complete de-leetification is more likely)
  • Example :
  • "b1ue" → withI = "biue" (not in dict), withL = "blue" (in dict) → returns "blue"
  • "f1le" → withI = "file" (in dict), withL = "flle" (not in dict) → returns "file"
  • 9.4 Substitutions not covered (intentionally)

    Time2Crack does not cover rare or ambiguous substitutions beyond LEETBASE patterns. It is a design choice: covering too many cases would increase the false positives (detecting a password as a "current word" while it is not). The included patterns cover >95% of the actual leetifications observed in the corpus.


    10. Calculation of cracking time: addDictionaryAttacks()

    Calculation logic

    // app.js - ligne 3848
    function addDictionaryAttacks(rows, common, weak, dictWord) {
      for (const a of ALGOS) {
        let sec;
        if (weak)     sec = 100 / a.rate;     // Top ~100 entrées
        else if (common) sec = 10000 / a.rate; // HIBP priority list ~10k
        else if (dictWord) sec = 200000 / a.rate; // Scan wordlist complète ~200k mots
        else sec = null;                        // Non applicable
    

    const note = weak ? t("nWeakPassword") : common ? t("nInLeaks") : dictWord ? t(nDictHit) : t(nAbsentLeaks);

    rows.push({ atk: t("aDict"), hash: a.name, spleen: a.rate, sec, note, cat: "dict" }); } }

    10.2 Three levels of vulnerability

    Level 1 — Ultra-weak (weak = true) : ~100 / spleen The password is in the world's Top 100 ("password", "123456", "qwerty"...). An attacker testing these 100 priority candidates finds it in the first pass. For MD5: 100 / 168.9e9 0.6 nanosecond. Level 2 — Common (common = true) : ~10 000 / spleen The password is in the reference HIBP list of the ~10,000 most frequent passwords. These candidates are tested in the first microseconds. For MD5: 10,000 / 168,9e9 59 nanoseconds. Level 3 — DictWord (dictWord = true) : ~200,000 / spleen The password is a word from the current language dictionary (local wordlist ~50k–200k entries). A complete scan of the wordlist is almost instantaneous for fast algorithms. For MD5: 200 000 / 168,9e9 1.18 microsecond. Level 4 — Not applicable (sec = null) : the password is neither ultra-weak, nor common, nor a word from the current dictionary. The dictionary attack alone is not applicable — other attacks (gross force, Markov, PCFG) become the main threat.

    10.3 Why these numbers (100, 10,000, 200,000)?

    These values are calibrated to actual data:

  • 100 The first 100 RockYou passwords represent ~10% of the corpus. All serious tools test them as a priority.
  • 10 000 : HiBP sorts its ~14 billion entries by frequency. The top 10,000 cover about 30–40% of the real passwords in use. Any competent attacker starts with this subset.
  • 200 000 : typical size of a complete language wordlist after filtering. This is sufficient to cover the current vocabulary of a language without exceeding the reasonable load capacity in memory.
  • Reference Weir et al. (2009) show that dictionary words are found in the first 200,000 attempts at a well-ordered attack. Ur et al. (2012) confirm that common passwords are found in the first 10,000 attempts.

    10.4 Complete numerical example

    For the "sun" password (current French word, detected as dictWord) :

    AlgorithmSpeed (12× RTX 4090)FormulaTime --------------------------------------------------- NTLM3,462 GH/s200 000 / 3 462e957.8 picoseconds MD52 027 GH/s200 000 / 2 027e998.7 picoseconds SHA-1610 GH/s200 000 / 610e9327.9 picoseconds SHA-256272 GH/s200 000 / 272e9735 picoseconds bcrypt (cost 5)2.2 MH/s200 000 / 2 200 00090.9 milliseconds Argon2id800 H/s200 000 / 800250 seconds

    Even for Argon2id, 250 seconds is less than 5 minutes — for a simple word from the French dictionary.


    11. High fidelity calibration: applyHighFidelityCalibration()

    11.1 Why additional calibration?

    The gross calculation addDictionaryAttacks() gives an estimate of the "worst case" — as if the attacker was testing the entire wordlist uniformly. ordered by probability : the most common passwords arrive first.

    High fidelity calibration applies a corrective multiplier based on empirical observations:

    // app.js - ligne 4442
    case "dict":
      // Ur et al. 2012 : mots communs trouvés dans les 100-10k premiers essais
      // Weir 2009 : mots dict trouvés dans les 200k premiers essais (scan ordonné)
      m = context.common ? 0.15: context.dictWord ? 0.5: 1.0;
    Break;
    Multiplier common (0.15) : if the password is in the common priority list, it is found on average at the 15th percentile of the list — that is ~1,500 tests of the 10,000 listed. Time is multiplied by 0.15 → 6.7× faster than the uniform scan. Multiplier dictWord (0.5) : a common dictionary word is found on average mid-term of a well-ordered list. Multiplier 0.5 → 2× faster than the uniform scan.

    11.2 Academic Sources of Calibration

  • Ur et al. (2012) — How Does Your Password Measure Up? (USENIX Security): analysis of the distribution of passwords in real corpus. Common words: found in the first 10,000 trials for 95% of cases.
  • Weir et al. (2009) — Password Cracking Using Probabilistic Context-Free Grammars (IEEE S&P): Pure dictionary words are found in the first 200,000 trials of an orderly attack.

  • 12. Likelihood of applicability and confidence score

    12.1 Scoring system

    Time2Crack does not just calculate a time — it also evaluates the probability that the dictionary attack is actually the fastest attack, via a multi-factor scoring system:

    // Score d'applicabilité (0-1)
    case "dict":
      return context.common ? 0.99 : context.dictWord ? 0.85 : 0;
  • 0.99 if common The password is in HIBP → the dictionary attack applies with maximum confidence.
  • 0.85 if dictWord Only: high probability. A dictionary word is vulnerable, but an attacker must have the right linguistic wordlist.
  • 0 Otherwise: the dictionary attack does not apply (no lexical vulnerability detected).
  • 12.2 Evidence score

    In parallel with the applicability score, a "evidence" score records the observed signals:

    case "dict":
      return Number(!!context.common) + Number(!!context.dictWord);
      // 0 : aucun signal
      // 1 : un signal (common OU dictWord)
      // 2 : deux signaux (common ET dictWord)

    An evidence score of 2 (word in both HIBP and the linguistic dictionary) boosts the final confidence of 0.08 (2 × 0.04).

    12.3 Final Confidence Score

    const base = confidenceBase["dict"] || 0.6;  // confiance de base
    const evidenceBoost = Math.min(0.12, row.evidenceScore  0.04);
    const speculativePenalty = speculativeCats.has("dict") ? 0.08 : 0;  // dict n'est pas spéculatif
    

    row.confidence = Math.max(0, Math.min(1, Math.max(applicability, base) + evidenceBoost - specificPenalty ));

    For a password common with dictWord also detected:

  • applicability = 0.99
  • evidenceBoost = min(0.12, 2 × 0.04) = 0.08
  • confidence = min(1, max(0.99, 0.6) + 0.08) = min(1, 1.07) = 1.0
  • Maximum confidence: The dictionary attack is the primary attack unambiguously.


    13. Bloom filter RockYou: local detection of widespread passwords

    13.1 Background

    In addition to the HIBP verification (which requires a network call), Time2Crack incorporates a bloom filter A bloom filter is a probabilistic data structure that allows you to test belonging to a set with a probability of false positives (~1%), without storing the elements themselves.

    13.2 Benefits of the bloom filter

    CriteriaHIBP k- anonymityBloom filter local --------------------------------------------- Coverage~14 billion~14 million (RockYou) Latency50–200 ms (network)<1 ms (local) Confidentialityk- anonymity (5 SHA-1 tanks)100% local, nothing transmitted False positive0%~1% SizeAPI~2–5 MB (bloom filter binary)

    13.3 Operation of double hashing

    // app.js - ligne 1962
    function bloomHas(filter, word) {
      if (!filter) return false;
      const { bitArray, m, k } = filter;
      const w = word.toLowerCase();
    

    // Double-hashing: h1 and h2 are two independent hash functions const h1 = fnv1a32(w, 2166136261); // FNV1a with standard seed const h2 = fnv1a32(w, 0x811c9dc5); // FNV1a with alternative seed

    for (let i = 0; i < k; i++) { const pos = (h1 + (i (h2) >>> (0)) % m; // k positions in the bit array const byteIdx = Math.floor(pos / 8); const bitIdx = pos % 8;

    // If a bit is 0: the word is DEFINITLY absent if ((bitArray[byteIdx] & (1 << bitIdx)) = 0) return false; } // All bits are at 1 : the word is PROBABLY present (with 1% of FP) return true; }

    The FNV1a double-hashing ensures a uniform distribution of positions in the bit array, minimizing collisions and keeping the false positives rate close to 1%.

    13.4 Loading and binary format

    The bloom filter is stored in data/rockyou.bloom — a binary file with:

  • Header (20 bytes): magic number (0x424c4f4f = "BLOO"), version, m (bit array size), k (number of hash functions), n (number of elements)
  • Payload : bit array (m/8 bytes)
  • The load is triggered manually by the user (button in the UI), not automatically at the page loading — to preserve the initial performance.


    14. Comparison with derived attacks

    The "pure" dictionary attack is the first of a family of attacks that all share a common root: a lexical wordlist. Time2Crack implements 7 offline cracking models (gross force, dictionary, hybrid, mask, PCFG, Markov, combinator), each attacking the password from a different angle.

    14.1 Dictionary vs Hybrid

    CriteriaDictionaryHybrid (dict+rules) ---------------------------------------------- CandidatesDictionary Words asWords + ~1000 mutations per word Keyspace200,000 candidates~200 million candidates Cracked examples"password", "sun""P@ssw0rd!", "s0l3il2024" Relative speed1000× fasterMuch wider coverage Applicable ifexact word in listPassword derived from a dict word

    The hybrid attack begins where the pure dictionary stops: it takes every word from the wordlist and applies systematic mutation rules (hashcat "best64.rule" in mind).

    14.2 Dictionary vs PCFG

    CriteriaDictionaryPCFG ------------------------------ ModelFixed list of candidatesProbabilistic structure grammar ForceAccurate wordsWord+Digits structures, Cap+lower+sym Example"password" → ✓"Password123" → ✓ (structure detected) CoverageKnown vocabularyGeneric human structures

    A password like "Password123" can go unnoticed in a dictionary (the exact word "Password123" may not be listed) but will be cracked very quickly by PCFG which recognizes the structure [Majuscule][minuscules][digits].

    14.3 Dictionary vs Markov

    CriteriaDictionaryMarkov -------------------------------- CandidatesPre-compiled listFly-generated by statistical model CoverageKnown vocabularyAny probable "human" sequence AdvantageVery fast on exact wordsCovers unknown vocabulary words Example"sunshine" → ✓"sunsh1ne" potentially ✓

    Markov covers cases where the password looks like a human word without being in any list.

    14.4 Dictionary vs Credential Stuffing

    CriteriaDictionaryCredential Stuffing --------------------------------------------- ObjectiveCracking a hashTest a specific login MechanismHash local computationRemote connection attempts SourceGeneric WordlistPair login/password leaks DefenceStrong hash algorithmRate limiting, MFA, IP blocking

    Credential stuffing does not attack a hash — it directly tries login/password pairs on remote services. It is conceptually different from cracking, but shares the same data source (HIBP/fail).


    15. Limitations of attack dictionary

    15.1 Intrinsic limits

    1. Known vocabulary only A invented password that does not resemble any existing word and is not in HiBP is impervious to pure dictionary attack. "Xqz7mK9pL" will never be in any wordlist. 2. Language coverage An attacker targeting a French-speaking user without a French wordlist will miss words such as "ephemeral", "grenouille", or "bricolage" that are not in standard English wordlists. 3. New passwords A credential that has just been created and has never fled will not be in HiBP — even if it is very common, it will have to wait until the next leak to find it. 4. Very long passwords A password consisting of a long invented phrase ("MaGrandeAventure2024SousLesEtoiles") will be in no wordlist — even if each word taken separately is trivial. This is the idea behind the passphrases, treated by other attacks (Combinator, PRINCE).

    15.2 What Time2Crack's Calculation Does Not Model

    Context Wordlists : an attacker targeting a specific sector will build adapted wordlists (medical terms for hospitals, video game slang for gaming platforms). Time2Crack uses generic wordlists. Combined gross force Wordlists : Tools such as CeWL (Custom Word List Generator) can extract terms from the target website to build a custom wordlist. This level of targeting is not modelled. Recent leaks not yet in HIBP between the moment a leak occurs and its integration into HIBP, the compromised credentials circulate in private forums without being accessible via the public API. Hash algorithms not covered Time2Crack models 6 algorithms (MD5, SHA-1, SHA-256, NTLM, bcrypt, Argon2id). Algorithms such as SHA-512, scrypt, or PBKDF2 have different profiles.

    16. Effective defences

    16.1 What protects against dictionary attack

    Modern hash algorithm (bcrypt, Argon2id) This is the most effective defense on the server side.
  • MD5: crack in ~1 microsecond
  • bcrypt cost 12 : crack in 35 hours
  • Argon2id (recommended parameters): crack in years
  • The difference of 10+ orders of magnitude between MD5 and Argon2id makes the dictionary password "sun" immune in practice if protected by Argon2id — even if the attacker knows it is a French word.

    Single salt per account A salt prevents pre-calculated table attacks and forces the attacker to recalculate individually for each account. It does not protect targeted wordlist attacks (the attacker can still test the 200,000 words with the salt), but invalidates the rainbow tables and makes massive attacks on large databases impracticable. Password length A password of a single dictionary word (8-10 characters) is vulnerable. A passphrase of 4-5 words ("cheval-lumière-forest-voyage") is resistant to the pure dictionary attack but not to the Combinator attack — hence the importance of the length AND the randomity. Randomly generated passwords The real solution: use a password manager that generates long random passwords (20+ characters of all types). These passwords will never be in any dictionary. Multifactor authentication (MFA) The MFA does not prevent crack offline (the attacker recovers hashs and cracks offline), but protects against credential stuffing (use cracked credentials to connect). Rate limiting and detecting anomalies Protects against online attacks (direct connection attempts), not against offline cracking of stolen hashs.

    16.2 What does not protect

    Simple leet substitutions : "password" → "p@ssw0rd" — see section 9. Added numbers at the end : "password" → "password1" — among the first rules tested. Initial payment : "password" → "Password" — standard capitalization rule. Figures and symbols if the word remains recognizable "sunshine!" is in any wordlist that includes "sunshine" with basic rules. Complexity imposed without length "P@s1w" meets the complexity criteria (maj, min, number, symbol) but is shorter and more predictable than "correcthorsebaterystaple".

    16.3 Practical recommendations

  • Use a password manager (Bitwarden, 1Password, KeePass) — generates random passwords, you only have to remember the master password.
  • Enable MFA everywhere — even if the password is compromised, the attacker cannot connect.
  • Check HIBP regularly — whether his email is in known leaks.
  • Never reuse a password — credential stuffing exploits cross-services reuse.
  • For memorizable passwords : 5+ words passphrases random (not "horse-correct-battery-agrafe-violet" but words really drawn by lot).

  • 17. References

    Primary sources (academic studies)

    Morris, R., & Thompson, K. (1979). Password security: A case history. Communications of the ACM, 22(11), 594–597.
  • First academic analysis of Unix password distribution
  • Recognizes that ~1/3 passwords are common English words
  • Klein, D.V. (1990).
    Foiling the cracker: A survey of, and improvements to, password security. UNIX Security Symposium Proceedings, 5–14.
  • 15,000 Unix password crack: 25% cracked in a few hours
  • Document first wordlists and mutation rules
  • Weir, M., Aggarwal, S., de Medeiros, B., & Glodek, B. (2009).
    Password cracking using probabilistic context-free grammars. IEEE Symposium on Security and Privacy.
  • Basic reference on PCFG attack and comparison with pure dictionary attack
  • Determines that dictionary words are found in the first 200,000 attempts of an orderly attack
  • Cited in Time2Crack for the HF calibration of the dictionary attack (multiplier 0.5)
  • Ur, B., Kelley, P. G., Komanduri, S., Lee, J., Maase, M., Shay, R., Vaniea, K., Bauer, L., & Cranor, L. F. (2012).
    How Does Your Password Measure Up? The Effect of Strength Meters on Password-User Choice. 21st USENIX Security Symposium.
  • Analysis of the distribution of common words in real corpus
  • Common words found in the first 100–10 000 attempts
  • Cited in Time2Crack for HF calibration common ? 0.15 (top 10k level)
  • Bonneau, J (2012).
    The science of singing: Analyzing an anonymous corpus of 70 million passwords. IEEE Symposium on Security and Privacy.
  • Study of 70 million anonymized Yahoo passwords
  • Quantifies the actual distribution of passwords, confirms the power law
  • Measuring the effectiveness of credential stuffing (2–5% hit rate on real accounts)
  • Ma, J., Yang, W., Luo, M., & Li, N. (2014).
    A study of probabilistic password models. IEEE Symposium on Security and Privacy.
  • Comparison of probabilistic models (dictionary, Markov, PCFG) on real corpus
  • Best64.rule prioritized → ~40% reduction in average time for dictionary words
  • Cited in Time2Crack for HF calibration of hybrid attack
  • Wheeler, D.L. (2016).
    zxcvbn: Low-budget password strength estimate. 25th USENIX Security Symposium, 157–173.
  • Force estimation system using wordlists and patterns
  • Analysis of cognitive biases in password creation
  • Measure the effectiveness of wordlists in relation to gross force
  • Pasquini, D., Cianfriglia, M., Ateniese, G., & Bernaschi, M. (2021).
    Reducing bias in modelling real-world password strength via deep learning and dynamic dictionaries. 30th USENIX Security Symposium.
  • Assessment of estimation models for actual attacks
  • Confirms that dictionaries remain the most effective tool for common human passwords
  • Industrial sources

    Have I Been Pwned. (2024).
    Pwned Passwords. https://haveibeenpwned.com/Passwords
  • Basis of ~14 billion unique passwords from documented leaks
  • k- anonymity API used by Time2Crack for real-time verification
  • Hive Systems. (2025).
    2025 Hive Systems Password Table.
  • Benchmarks 12× RTX 4090: MD5 2,027 GH/s, NTLM 3,462 GH/s, bcrypt cost 5 : 2,2 MH/s
  • Main source of hash rates used in Time2Crack
  • Hashcat. (2025).
    Hashcat — Advanced password recovery.
  • Reference tool for GPU benchmarks
  • Documentation of mutation rules (best64.rule, OneRuleToRuleThemAll)
  • Gosney, J (2012).
    Strictures on Lee et al. and Probabilistic Password Cracking. Passwordscon proceedings.
  • First publicly documented multi-GPU benchmarks
  • Reference for calibration of rule-based attacks
  • Miessler, D. (2024).
    SecLists — A collection of multiple types of lists used during security assessments. GitHub.
  • Source of Wikipedia language wordlists used in Time2Crack
  • Wordlists in English, French, Spanish, Portuguese, German, Turkish
  • Secondary sources (context)

    Troy Hunt. (2013).
    Introduction 306 Million Freely Downloadable Pwned Passwords. troyhunt.com.
  • Initial establishment of the HIBP service and explanation of the k-anonymity protocol
  • Thomas, K., et al. (2019).
    Protecting accounts from credential stuffing with password break alerting. 28th USENIX Security Symposium.
  • Google/Stanford study on the protection of compromised credentials
  • Confirms the effectiveness of k-anonymity as a privacy mechanism
  • Wang, D., Cheng, H., Wang, P., Huang, X., & Jian, G. (2016).
    Zipf's law in passwords. IEEE Transactions on Information Forensics and Security, 12(11), 2776–2791.
  • Mathematical formalization of power law in password distribution
  • Confirms that Zipf distribution holds on all known large corpus
  • Web sources cited in the Time2Crack application

    IEEE Xplore (dictional reference). https://ieeexplore.ieee.org/document/6234435
  • Related source in descDict (app.js) for the order of coverage of top dictionaries.
  • HIBP API range (k- anonymity). https://api.pwnedpasswords.com/range/
  • Endpoint actually used by Time2Crack for k-anonymity verification (sha1 prefix request).
  • HIBP call pattern in code. https://api.pwnedpasswords.com/range/${prefix}
  • The exact form of the URL called in the document code examples (interpolated SHA-1 prefix).

  • Document generated for Time2Crack Project — Version 1.0 — 2026-04-01 Source code: app.js (functions addDictionaryAttacks, isDictWord, deLeet, loadDictionary, applyHighFidelityCalibration, bloomHas)*