Password Hashing (Argon2)
When you set a password on Dashify, the platform never stores the password itself. It stores a hash of the password — a one-way fingerprint that the platform can verify against on login but cannot reverse back into the original password.
This page explains why hashing is mandatory, why most older approaches are broken, and why Argon2 is the current right answer.
Why we cannot store passwords
It seems convenient: store the password in the database, compare on login, done. Don't.
The reason is simple. Databases get breached. Backup tapes get lost. A disgruntled employee dumps a table. An accidental commit pushes a snapshot to GitHub. Every major breach in the news started with a database that should have been safer than it was.
If passwords are stored in plaintext, every breach is a total breach. The attacker now has every user's password — and because most people reuse passwords across sites, those passwords also unlock email, banking, social media, and every other service the user touches.
The platform has a moral obligation to assume its database will be compromised someday and to make that compromise not a catastrophe.
The way to do that is to never store the actual password. Store a one-way fingerprint — a hash — instead.
What a hash is
A hash function takes any input and produces a fixed-size random-looking output. Two important properties:
- Deterministic. The same input always produces the same output.
- One-way. Given the output, you cannot recover the input. The only way to find an input that produces a given hash is to try inputs one at a time.
So we can hash the password on signup, store the hash, and on login hash the submitted password and compare it to the stored hash. If they match, the password is correct. The plaintext is never stored anywhere.
Why old hash functions are broken
Hashing was solved decades ago — sort of. The first attempts used hash functions like MD5 or SHA-1. These are fast — modern hardware can compute billions of MD5 hashes per second.
That speed turns out to be a security problem. If an attacker steals a database of MD5-hashed passwords, they can try every word in the dictionary, every common phrase, every leaked password from previous breaches, against every stored hash, billions of times per second. Most weak passwords fall in seconds.
Worse, attackers precompute these hashes into giant lookup tables (rainbow tables). If you stole my MD5-hashed password, you wouldn't even compute anything — you'd look it up.
The fix to lookup tables is salt — a random value mixed into each password before hashing, so two users with the same password get different hashes and lookup tables don't help. Salt is necessary but not sufficient. The remaining problem — that hash functions are fast — has to be solved by making them deliberately slow.
What Argon2 is
Argon2 is a modern password-hashing algorithm specifically designed to be slow, memory-hungry, and tunable. It is the winner of the 2015 Password Hashing Competition and the current best-in-class choice.
It is slow on purpose. A typical Argon2 verification takes around 100 milliseconds. That is imperceptible to a logging-in user. It is agonising to an attacker trying to brute-force a database of stolen hashes. Where MD5 lets the attacker try billions of passwords per second, Argon2 lets them try maybe ten.
It is memory-hungry on purpose. Argon2 holds a chunk of memory while it works (a few megabytes per hash). This makes it expensive to run on GPUs, which are otherwise the fastest hardware for parallel hash-cracking. Custom ASIC hardware, which can break older algorithms, struggles too.
It is tunable. The slowness, memory, and parallelism are all parameters. As hardware gets faster, you can dial up the difficulty without changing the algorithm. Dashify's parameters are set with a comfortable margin so they will remain strong for years.
How Dashify uses it
The library Dashify uses is @node-rs/argon2 — a Rust implementation with Node bindings, fast and memory-safe.
The stored hash string contains everything needed to verify against it later:
$argon2id$v=19$m=65536,t=3,p=4$<salt>$<hash>
The dollar-separated fields encode the algorithm variant (argon2id), the memory cost (64 MB), the time cost (3 iterations), the parallelism (4 lanes), the salt, and the hash itself. When the user logs in, the verify function reads those parameters from the stored string, applies the same algorithm with the same parameters to the submitted password, and compares.
What if a database leak happens
Imagine the worst — the entire user collection is leaked. What can the attacker do with the hashes?
- Run Argon2 against every guess at the rate of about ten guesses per CPU per second. A single attacker laptop can attempt maybe a few thousand guesses per second across all cores.
- After a year of constant attack, they might have compromised users with extremely weak passwords (
123456,password, names of pets). - Users with strong passwords (random, long) are mathematically out of reach.
This is the right outcome. A leak is bad — but it does not become an instant total breach. The cost-of-attack is high enough that Dashify's authors can sleep at night, and most users are protected by the algorithm regardless of their password choice.
Migrating from older hashes
Some legacy data in Dashify was originally hashed with bcrypt (an older but still-acceptable algorithm). When such a user logs in, the API verifies against bcrypt as expected, and on a successful login also re-hashes the password with Argon2 and updates the stored hash. Over time the user collection migrates to Argon2 transparently.
This pattern — verify with the old algorithm, transparently re-hash on success — is the standard way to evolve password storage without forcing users to reset.
What the user sees: nothing
A 100-millisecond delay on login is invisible. Users have no reason to notice that Argon2 is involved. That is the point — security should not feel like security.
Key takeaways
- Dashify never stores passwords in plaintext. It stores Argon2 hashes.
- Argon2 is deliberately slow and memory-hungry to make brute-force attacks expensive even with stolen hashes.
- Each password is hashed with a unique random salt, so two users with the same password get different hashes.
- The stored hash encodes the parameters used, so the verifier always knows how to check.
- Legacy bcrypt hashes are migrated to Argon2 transparently on next successful login.