From grimoire
Guides password hashing with Argon2id, bcrypt, or scrypt, including work factor tuning and migration from legacy hashes like MD5/SHA-1.
How this skill is triggered — by the user, by Claude, or both
Slash command
/grimoire:apply-password-hashingThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Store passwords with a memory-hard, salted, slow hash function (Argon2id, bcrypt, or scrypt) — never MD5, SHA-1, SHA-256, or unsalted hashes.
Store passwords with a memory-hard, salted, slow hash function (Argon2id, bcrypt, or scrypt) — never MD5, SHA-1, SHA-256, or unsalted hashes.
Adopted by: NIST SP 800-63B (authoritative US federal standard for digital identity) mandates slow hashing for memorized secrets. OWASP Top 10 2021 A07 (Authentication Failures) cites weak password storage as a primary failure mode. Django defaults to Argon2, ASP.NET Core Identity defaults to PBKDF2, Spring Security defaults to bcrypt. PCI DSS v4.0 Requirement 8.3.2 mandates strong hashing for stored passwords. Impact: Every major password breach demonstrates the cost of weak hashing — LinkedIn (2012, SHA-1, 117M cracked in days), RockYou (2009, plaintext, 32M passwords), Adobe (2013, 3DES ECB, trivially reversible). bcrypt with cost factor 12 requires ~300ms per attempt; modern GPU rigs crack MD5 at 100 billion hashes/second. Proper hashing makes offline cracking economically infeasible for strong passwords. Why best: Fast hashes (MD5, SHA-256) are designed for speed and destroy security — a single GPU cracks billions per second. Argon2id wins over bcrypt by resisting GPU attacks via memory-hardness; it wins over PBKDF2 by resisting ASICs. bcrypt is the safe fallback when Argon2 is unavailable.
Sources: OWASP Password Storage Cheat Sheet; NIST SP 800-63B; HaveIBeenPwned breach analysis; CWE-916
Choose the right algorithm by priority:
| Priority | Algorithm | Use when |
|---|---|---|
| 1st | Argon2id | Modern apps — best resistance to GPU/ASIC cracking |
| 2nd | bcrypt | Argon2 unavailable; widely supported; proven 25+ years |
| 3rd | scrypt | Alternative memory-hard option |
| 4th | PBKDF2-HMAC-SHA256 | FIPS compliance required |
| Never | MD5, SHA-*, plain | Not password hashing algorithms |
Configure Argon2id with secure parameters — OWASP minimum (2023):
from argon2 import PasswordHasher
ph = PasswordHasher(
time_cost=2, # iterations
memory_cost=19456, # 19 MB memory
parallelism=1,
hash_len=32,
salt_len=16
)
hash = ph.hash(password)
Tune memory_cost and time_cost so hashing takes ≥500ms on your hardware.
Configure bcrypt with work factor ≥12:
import bcrypt
salt = bcrypt.gensalt(rounds=12) # never use rounds < 10
hashed = bcrypt.hashpw(password.encode(), salt)
const bcrypt = require('bcrypt');
const ROUNDS = 12;
const hash = await bcrypt.hash(password, ROUNDS);
Benchmark: increase rounds until hashing takes ~300–500ms on your hardware.
Never manage salts manually — Argon2, bcrypt, and scrypt generate and embed a random salt automatically. The output string includes the salt. Do NOT add a separate global "pepper" without understanding the implications.
# bcrypt output embeds the salt — store the full string:
# $2b$12$LQv3c1yqBWVHxkd0LHAkCOYz6TtxMQJqhN8/LewdBPj9bIyZzAQm.
Verify correctly — never re-hash and compare:
# Argon2
try:
ph.verify(stored_hash, provided_password)
if ph.check_needs_rehash(stored_hash):
# rehash with updated parameters on next login
new_hash = ph.hash(provided_password)
update_hash_in_db(user_id, new_hash)
except argon2.exceptions.VerifyMismatchError:
raise AuthenticationError()
Migrate legacy hashes without forcing password resets — wrap old hashes:
# On login: detect old bcrypt hash, rehash with Argon2, store new
if is_legacy_bcrypt(stored_hash):
if bcrypt.checkpw(password, stored_hash):
new_hash = ph.hash(password)
update_to_argon2(user_id, new_hash)
Enforce a maximum password length of 64–128 characters — bcrypt silently truncates at 72 bytes; Argon2 does not, but extremely long passwords can cause DoS. Validate before hashing:
if len(password) > 128:
raise ValueError("Password too long")
bcrypt(sha256(password))) — introduces new vulnerabilities without benefit.sha256(password + salt) and calling it "secure" — fast hashing with a salt is still fast; bcrypt with no salt is still better than SHA-256 with a salt.hex instead of the full output string — loses the embedded parameters and salt.npx claudepluginhub jeffreytse/grimoire --plugin grimoireGuides secure password hashing with Argon2id (preferred) or bcrypt, including cost tuning, salt/pepper, and hash upgrade paths.
Select appropriate cryptographic algorithms and parameters for encryption, hashing, key derivation, and digital signatures.
Provides cryptography guidance on encryption (AES-256-GCM, ChaCha20), password hashing (Argon2id, bcrypt), signatures (Ed25519), TLS config, key management. Use for implementing or reviewing crypto.