English

Developer tools · SHA hash calculator

Why You Must Not Store Passwords as Plain SHA-256 Hashes

· Why it matters

passwords security cryptography

A stopwatch showing instant guessing versus a password hash function adding intentional delays
Original ToolAcre vector illustration

SHA-256 is designed to be fast, which is exactly what you do not want for passwords. This post explains why speed is the problem and what password hashing functions do differently.

SHA-256 is not password storage; it is fast hashing. Plain SHA-256 gives attackers the same speed for guessing, making it unsuitable despite being a cryptographically strong algorithm.

A developer implements a login system and stores passwords as SHA-256 hashes. The algorithm is cryptographically strong, and the application applies no salt, keeping the code simple. When a user logs in, the application hashes the submission and compares it to the stored value. This design is elegant in its simplicity, and it is completely unsuitable for password storage. This is not a theoretical concern; it is the single most common serious mistake in authentication systems. The design looks defensible until you consider what an attacker can do with stolen data.

The flaw is not that SHA-256 is weak. SHA-256 is a robust cryptographic algorithm, trusted by the security community and used throughout the industry for integrity checks and content addressing. The flaw is that SHA-256 is fast, and fast is precisely the opposite of what passwords need. A password hash is not just any cryptographic primitive; it is a specific kind of tool designed for a specific problem: defense against guessing. Speed is a feature in checksums; in passwords, it is a catastrophe.

Fast is the point of SHA-256 — integrity checks need speed, and an attacker gets the same speed for guessing

When a database of SHA-256 password hashes is compromised, an attacker does not need to reverse the hashes. The attacker builds a dictionary: common passwords like "password," "123456," "hello," and millions more. Each candidate is hashed with SHA-256—a computationally trivial operation—and checked against the stolen database. An attacker can compute candidate SHA-256 values with the same fast primitive used by the login service, then compare each result offline without rate limits. The exact rate depends on hardware and implementation, so this article deliberately makes no guesses-per-second or breach-time claim.

Speed is the entire problem. SHA-256 is meant to be fast. That is its design intent. It lets you verify download checksums, compute content addresses, and build Merkle trees without waiting. In those applications, speed is a feature. For passwords, speed is a catastrophe. When a password database is stolen and hashed with SHA-256, the attacker has the same speed for guessing as the legitimate server does for verification. That symmetry is what breaks password security. The legitimate server and attacker both receive the benefit of a fast general-purpose digest; only the attacker can repeat it offline without the application’s login controls.

Dictionaries and rainbow tables — precomputation against unsalted hashes, and what a salt changes

This is where a precomputed dictionary becomes practical. An attacker can spend a day and compute SHA-256 hashes for the thousand most common passwords, for common patterns like Name1990, or for entire dictionaries in multiple languages. The resulting table is called a rainbow table. Looking up a stolen SHA-256 hash against a precomputed table is instant. Even without a precomputed table, computing a billion guesses is trivial with GPU-accelerated hashing. The computational cost to the attacker is so low that even weak passwords fall in minutes.

The ToolAcre SHA hash calculator demonstrates this speed directly. Paste a short text, click the SHA-256 button, and the result is instant. That instant result—the property you admire in a hash calculator—is the exact property that makes plain SHA-256 indefensible for passwords. An attacker gets the same instant result for every guess. For checksums and integrity checks, that speed is perfect. For passwords, it is fatal to security.

What password hashing functions add — work factors, memory hardness and per-user salts in bcrypt, scrypt, Argon2 and PBKDF2

A salt is a random value added to the password before hashing, so each user's salt is different. Even if two users have the same password, they hash to different values. This breaks precomputed rainbow tables; an attacker must compute the table independently for each salt. With independently generated per-user salts, one precomputed table no longer applies unchanged to every account. However, a salt only pushes the attacker to compute the table during the attack instead of beforehand. If hashing is still fast, the attacker simply computes more tables in parallel and continues guessing each account with a fast primitive. The salt is necessary but not sufficient. It prevents dictionary reuse across victims, but it does not slow the attacker's core operation: guessing. The speed of hashing is still the speed of guessing.

Worked example — how quickly a common password's SHA-256 is recognised versus a tuned password hash, described qualitatively

A password hashing function takes a different approach. Bcrypt, scrypt, Argon2id and PBKDF2 are purpose-built for password verification. They all include a work factor: a parameter that makes hashing deliberately expensive. Argon2 is the most modern; it adjusts both CPU time and memory consumption. Bcrypt uses a tunable cost factor that doubles the work with each increment. All of them include built-in salt generation. These tools are designed with the attacker model in mind. The work factor is crucial.

A password hashing function makes the configured cost part of every verification. An attacker who wants to test candidates must also pay that cost for every guess. Concrete timings cannot be copied safely between deployments, which is why the section on parameters requires benchmarking on the actual production class of hardware. That asymmetry is what makes password hashing work. The work factor shifts from "attacker advantage" to "defender advantage".

Migrating a legacy SHA-256 table — wrapping existing hashes and rehashing on next login

The worked comparison remains qualitative because this repository contains no benchmark for a particular password function or attacker. A common password produces the same plain SHA-256 immediately every time, so an existing dictionary entry can identify it by equality. A tuned password record includes its own salt and cost parameters and requires configured work for each candidate.

That contrast establishes the design error without promising guesses per second. Hardware, implementation and selected parameters determine timing. The defensible conclusion is invariant: a general-purpose digest has no adjustable work factor or memory cost, while a password hashing function is chosen specifically to impose those costs.

What this does not cover — choosing parameters for a specific password hash, which depends on your hardware and threat model

Parameter selection is deliberately outside this calculator and this article. Correct settings depend on server latency budgets, available memory, concurrency and the current threat model, so copying a fixed value from an unrelated deployment would turn a safety control into folklore. Benchmark the selected password function on production-class hardware and revisit it as capacity changes.

ToolAcre cannot perform that exercise: its panel accepts text and a SHA identifier, then returns a plain digest. It exposes no salt field, memory setting, iteration control or password-record format. That absence is a useful boundary signal, not a missing feature to work around by repeatedly hashing a password in the text box.

Takeaway: the instant result is the warning — the ToolAcre SHA hash calculator shows how fast SHA-256 is, which is why it must not hold your users' passwords

A legacy system that has been storing passwords as plain SHA-256 can be migrated forward without requiring all users to reset immediately. The technique is to "wrap" the old hash: take the SHA-256 value and hash it again with Argon2. On the user's next login, the system checks whether the old SHA-256 matches; if so, it computes Argon2 over that result and stores the wrapped version. The next time the user logs in, the system verifies directly against Argon2. The migration happens transparently during normal login flow.

This wrapped approach ensures that older passwords that have been compromised are now protected by the work factor. An attacker with the old database of SHA-256 hashes cannot simply crack them anymore; they must attack the wrapped version, which includes Argon2's cost. The migration happens transparently to users during their normal login flow. Each login creates an opportunity to strengthen the hash without disrupting the user experience. Choosing the correct work factor depends on your hardware and your threat model. Argon2 defaults are sensible: 19 iterations, 512 MB memory and 1 parallelism for web services.