SHA-1 Bug smash Cracker
DEV Community

SHA-1 Bug smash Cracker

Project Overview

SHA-1 Password Cracker - Browser Demo. A small, safe demo that demonstrates a corrected and optimized SHAโ€‘1 password cracking approach using a top-passwords list and optional salts. The demo runs entirely in the browser using the Web Crypto API and exposes the same algorithmic improvements implemented in the Python version:

  • Unsalted: precompute a hash โ†’ password map for constant-time lookups.
  • Salted: iterate salts outer loop and passwords inner loop with early exit to avoid building the full cross-product in memory.
  • Friendly UI to load custom top-10000-passwords.txt and known-salts.txt, or use the built-in sample lists for quick testing.

Bug Fix or Performance Improvement

Problem resolved

  • Inconsistent encoding and repeated hashing caused incorrect comparisons and wasted CPU cycles.
  • A naive salted implementation that materialized all saltร—password combinations used excessive memory and was slow.

What I fixed / optimized

  • Correctness: Always encode strings as UTFโ€‘8 bytes before hashing so the digest matches server-side/other-language implementations.
  • Performance (unsalted): Build a single hash -> password map once and use O(1) lookups for each query.
  • Performance (salted): Avoid building the full cross-product. Iterate salts outer loop and passwords inner loop, compute salted hashes on the fly, and return immediately on match.
  • Responsiveness: Batch hashing and await yields to keep the UI responsive during heavy work.

Code Files produced

  • index.html - UI and structure
  • style.css - styling and layout
  • script.js - core logic, hashing, caching, and UI wiring

Key implementation excerpts

Unsalted map builder (JS) - precomputes SHAโ€‘1 hex โ†’ password:

async function buildUnsaltedMap(passwords, progressCallback) {
  const map = Object.create(null);
  const batch = 256;
  for (let i = 0; i < passwords.length; i += batch) {
    const slice = passwords.slice(i, i + batch);
    const promises = slice.map(p => sha1HexFromString(p));
    const hashes = await Promise.all(promises);
    for (let j = 0; j < hashes.length; j++) map[hashes[j]] = slice[j];
    if (progressCallback) progressCallback(Math.round(((i + slice.length) / passwords.length) * 100));
    await new Promise(r => setTimeout(r, 0));
  }
  return map;
}

Salted search with early exit (JS):

async function saltedSearch(target, passwords, salts, progressCallback) {
  for (let s = 0; s < salts.length; s++) {
    const saltBytes = new TextEncoder().encode(salts[s]);
    for (let i = 0; i < passwords.length; i += 128) {
      const slice = passwords.slice(i, i + 128);
      const results = await Promise.all(slice.map(async pwd => {
        const pwdBytes = new TextEncoder().encode(pwd);
        const aBuf = new Uint8Array(saltBytes.length + pwdBytes.length);
        aBuf.set(saltBytes, 0);
        aBuf.set(pwdBytes, saltBytes.length);
        if (await sha1HexFromBytes(aBuf) === target) return pwd;
        const bBuf = new Uint8Array(pwdBytes.length + saltBytes.length);
        bBuf.set(pwdBytes, 0);
        bBuf.set(saltBytes, pwdBytes.length);
        if (await sha1HexFromBytes(bBuf) === target) return pwd;
        return null;
      }));
      for (const r of results) if (r) return r;
      await new Promise(r => setTimeout(r, 0));
    }
  }
  return null;
}

If you want the full files, they are the three artifacts created for this submission: index.html, style.css, and script.js (the full contents were generated and are ready to drop into a static site).

My Improvements (technical approach)

Deterministic encoding

Always use TextEncoder / UTFโ€‘8 before hashing. This prevents mismatches between environments and languages.

Memory vs. speed tradeoffs

  • For unsalted cracking, a single hash -> password map is the fastest approach and uses O(N) memory (N = number of passwords). This is ideal for repeated lookups.
  • For salted cracking, building a full saltร—password map is O(Sร—N) memory and unnecessary. Iterating salts outer loop and passwords inner loop keeps memory usage low and allows early exit on match.

UI responsiveness

  • Hashing is batched and await yields are used so the browser event loop can update the UI and remain responsive.
  • Progress updates are reported during both map building and salted searches.

Robust file handling

  • Uploaded files are parsed into trimmed, non-empty lines.
  • The demo falls back to small sample lists if no files are provided.

Caching

The unsalted map and loaded lists are cached in memory for the session to speed repeated queries. A "Clear cache" button is provided.

Best Use of Sentry

This submission is primarily a focused bug fix and optimization demo; it does not include a production backend. If you were to integrate this into a larger application, here's how Sentry would be used to improve reliability and observability:

  • Error Monitoring: Capture exceptions from the client (e.g., file parsing errors, Web Crypto failures) and group by stack trace to prioritize fixes.
  • Session Replay: Record user sessions where errors occur to reproduce UI states that led to failures (file formats, large lists, or slow devices).
  • Performance Monitoring / Tracing: Instrument the heavy operations (map building, salted search) to measure CPU time and identify slow devices or pathological inputs.
  • Logs: Attach structured logs for long-running operations (progress percentages, batch durations) to correlate with traces and errors.

Sample Sentry integration snippet (conceptual, client-side):

Sentry.init({ dsn: 'https://examplePublicKey@o0.ingest.sentry.io/0' });
Sentry.captureMessage('Started unsalted map build', { level: 'info', extra: { passwordCount: N } });

Best Use of Google AI

This project did not require generative AI to implement the core fix. However, Google AI tools could be used to:

  • Automated test generation: Generate edge-case test inputs for salted/unsalted combinations.
  • Performance analysis: Use AI to analyze profiling traces and recommend batching sizes or concurrency strategies for different device classes.
  • Documentation: Produce clear, accessible explanations and interactive tutorials for students learning about hashing and salts.

Closing notes

  • Ethics & safety: This demo is educational. It demonstrates why weak password choices and unsalted hashes are insecure. Do not use this tool for unauthorized access or malicious activity.
  • Next steps: If you'd like, I can:
    • Provide a small PR-style diff for the Python implementation.
    • Add caching persistence (e.g., IndexedDB) for the unsalted map.
    • Add a downloadable report of the cracking attempt (local-only, client-side).

Thanks for running the Summer Bug Smash - this submission focuses on a compact, high-impact correctness and performance improvement with a clear, testable demo.

Comments

No comments yet. Start the discussion.