← Guides

Developer Guide

Hash Algorithms for Password Storage

Store passwords with Argon2id, bcrypt, or scrypt — not SHA-256. The Hash Generator is for checksums only; use the Password Generator to mint new secrets.

password hashingargon2id bcrypt scryptdo not store sha-256 passwordpassword salt kdfhmac is not a kdf

If your user table holds SHA-256(password), you do not store passwords securely. SHA-256 is fast on purpose. A unique salt does not slow guessing enough when the function itself is cheap on GPUs. Password storage needs a slow, memory-hard key-derivation function: Argon2id, bcrypt, or scrypt, each with a unique salt per user.

The Hash Generator on this site is not that function. /tools/hash-generator computes SHA-1, SHA-256, SHA-384, SHA-512, and optional HMAC for text or a local file. It is a checksum and HMAC workbench. It does not offer MD5, and it is the wrong tool for a password column. Create the secret with /tools/password-generator; hash it in your application with a password KDF.

What a password hash is for

You never need the user’s password again. You need to check a candidate against what they set. A KDF turns the password plus a salt into a verifier you can store. On login you repeat the same KDF and compare in constant time. If the database leaks, the attacker must spend real work per guess, per user.

Reversible encryption is the wrong model here. /tools/encryption-decryption is AES-256-GCM for text you intend to read back. Passwords are not that. Do not encrypt passwords with a global key and call it hashing.

Argon2id, bcrypt, and scrypt

Argon2id is the current default recommendation in most new systems: configurable memory, time, and parallelism. bcrypt is widely supported and fine if you stay on a current cost factor and accept its 72-byte input limit. scrypt is the other memory-hard option, common in some ecosystems.

Libraries generate the salt and encode it into the stored string ($argon2id$v=19$m=…, $2b$12$…). Do not invent your own string format. Do not “just HMAC” the password and store hex. Tune cost so a single login is a fraction of a second on your hardware, then freeze the parameters in config — not in a blog post from five years ago.

Why SHA-256(password) is wrong

SHA-256('hello') is 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824. That is a useful demonstration of a digest. It is also the same digest every system in the world produces for hello, which is why unsalted SHA-256 tables exist. Adding a salt makes each row unique and still leaves the function too fast.

You can paste hello into /tools/hash-generator to see SHA-256, SHA-384, and SHA-512. That is how checksums look. It is not a password storage recipe. Do not write UPDATE users SET password = sha256($input).

HMAC is not a password KDF

HMAC-SHA-256 mixes a secret key with a message. That authenticates a payload when the key is a random API secret. A user password is not that key, and HMAC is still fast. Peppering (a server-side secret in addition to a per-user salt) is an advanced extra on top of Argon2id/bcrypt/scrypt, not a replacement.

The Hash Generator’s HMAC mode exists so you can reproduce an API signature locally. The secret never leaves the tab. That is unrelated to login.

Generate secrets, then store them properly

/tools/password-generator uses crypto.getRandomValues to build passwords and passphrases in the browser. Use it for account secrets, recovery codes, and the passphrase you type into /tools/encryption-decryption. Then, in your app, run Argon2id/bcrypt/scrypt on whatever the user chose or you generated.

Transmit the password over TLS once, hash it server-side, discard the plaintext. Client-side hashing is not a substitute for TLS and is easy to get wrong (the server would still need to treat the hash as a password).

Common pitfalls

Truncating bcrypt input, using a single global salt, storing SHA-256 “for now”, and logging the password field are the usual failures. So is copying a digest from /tools/hash-generator into a user row because the hex looked official.

MD5 is even worse than SHA-256 for this, and this site’s Hash Generator omits MD5 on purpose. If a tutorial tells you to md5(password) or sha256(password), close it.

  • Password column: Argon2id, bcrypt, or scrypt with a unique salt.
  • /tools/hash-generator is checksums and HMAC, not a KDF.
  • /tools/password-generator creates secrets; it does not store them.

Worked examples

What SHA-256 looks like (not for storage)

Input
hello
Output
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824

Produced by /tools/hash-generator. Do not store this as a password hash. It is here so you recognize a SHA-256 hex string.

What a real password verifier looks like

$argon2id$v=19$m=19456,t=2,p=1$c29tZXNhbHRzb21lc2FsdA$+n0D3g==

Illustrative Argon2id encoding: algorithm, version, memory, time, lanes, salt, digest. Use your language’s argon2 library — do not paste this string into production.

Frequently asked questions

Can I salt SHA-256 and call it done?

A unique salt is necessary and not sufficient. You still need a slow KDF. Salted SHA-256 is not password storage.

Does the Hash Generator store passwords?

No. It hashes text or a local file in the browser and offers no password mode. MD5 is not available there.

Where should I create a strong password?

/tools/password-generator — passwords or passphrases via crypto.getRandomValues. Nothing is uploaded.

When do I use the encryption tool instead?

When you need to recover the plaintext later. /tools/encryption-decryption is AES-256-GCM with a passphrase. Login passwords should not be recoverable.

Summary

Hash passwords with Argon2id, bcrypt, or scrypt and a unique salt. Use /tools/password-generator to mint secrets, /tools/hash-generator only to see what a SHA-256 checksum looks like, and /tools/encryption-decryption for data you must decrypt. Never store SHA-256(password).

Try it yourself

Put what you've learned into practice with our free browser-native tool.

Open Tool →