Skip to content
Back to Blog
·9 min read·technology

Password Hashing: bcrypt, scrypt and Argon2 for Indian Devs

Password hashing requires Argon2id, not MD5 or SHA-256. Covers bcrypt, scrypt, Argon2id parameters, DPDP compliance and safe migration for Indian developers.

BR

Bachao.AI Research Team

Cybersecurity Research

Scan Your Attack Surface

Security exposure this creates

Unpatched vulnerabilities in your tech stack are the #1 entry point for breaches targeting Indian businesses. Here's what to watch.

Password hashing done right means using a slow, adaptive, memory-hard algorithm — bcrypt, scrypt, or Argon2id — never a fast general-purpose hash like MD5 or SHA-256. When an attacker steals your database, the work factor is the only thing standing between your users and mass account takeover. Indian developers building under the DPDP Act 2023 are legally required to implement "reasonable security safeguards" — and storing passwords in plaintext or MD5 is neither reasonable nor defensible. This guide explains the correct approach, the right parameters, and how to migrate legacy systems safely.

81%Percentage of hacking-related breaches involving weak or stolen passwords (Verizon DBIR 2024)
60%Share of Indian organisations that reported a data breach in the prior year (IBM Cost of a Data Breach 2023)

Why Plaintext and Fast Hashes Are Catastrophic

In 2016, LinkedIn confirmed that 117 million passwords stored as unsalted SHA-1 hashes had been compromised in a 2012 breach and were cracked once the data surfaced publicly. In 2009, RockYou had already demonstrated what happens with plaintext storage: 32 million credentials, fully readable. These are not edge cases — they are the industry's recurring lesson.

Fast hashing algorithms — MD5, SHA-1, SHA-256, SHA-512 — were designed for data integrity verification: checksums, digital signatures, certificate fingerprints. They are engineered to be as fast as possible. A modern GPU can compute billions of SHA-256 hashes per second. An attacker who steals your user table can run an offline dictionary attack against every account simultaneously, at no cost to your detection systems, at the speed of their hardware.

Three concrete failure modes:

    1. Plaintext storage: breach equals instant access to every account.
    2. Unsalted fast hash: a rainbow table (precomputed hash-to-password mapping) reverses millions of common passwords in milliseconds.
    3. Salted fast hash (SHA-256 + random salt): eliminates rainbow tables but does nothing to slow GPU brute-force. With 10 billion guesses per second, an 8-character password is cracked in under an hour.
The correct mental model: the hash must be expensive enough that cracking one password costs meaningful time and money, multiplied across millions of accounts becomes economically infeasible.

Cryptographic Fundamentals: Salt, Pepper, and Work Factor

Salt is a random value generated per-user and stored alongside the hash. Its job is to ensure that two users with identical passwords produce different hash outputs, defeating rainbow tables and preventing batch cracking. Salts are not secret — they live in the database. Their value is uniqueness, not secrecy.

Pepper is a secret value stored outside the database — in an environment variable, a secrets manager, or an HSM. It is added to the input before hashing. If an attacker steals the database but not the pepper, they cannot crack any hash at all. Pepper is optional but recommended as defence-in-depth, particularly for regulated environments.

Work factor (also called cost factor, iteration count, or rounds depending on the algorithm) is the tunable parameter that makes password hashing adaptive. Increase it each year as hardware improves. The goal: each hash computation should take 100–500 milliseconds on your server under normal login load, while being parallelisable at scale only on expensive hardware.

⚠️
WARNING
Never implement your own password hashing scheme. Rolling a custom combination of salted SHA-512 and HMAC is not "extra security" — it is an untested, unreviewed algorithm. Use bcrypt, scrypt, or Argon2id from a well-audited library for your language.

bcrypt: The Proven Workhorse

bcrypt was published by Niels Provos and David Mazières in 1999 and remains widely deployed and well-understood. It is Blowfish-based and includes a built-in salt. Its cost factor is expressed as a log-2 exponent: cost 12 means 2^12 = 4,096 internal rounds.

OWASP recommended minimum for 2024: cost factor 10 on modern hardware, with 12 preferred for new systems. Benchmark on your target hardware to confirm the hash completes in 100–300 ms.

Critical limitation: bcrypt silently truncates input at 72 bytes. A password of 73 characters is treated identically to one of 72 characters. For most users this is inconsequential, but long passphrase users or applications that pre-hash input before passing to bcrypt must account for this. Never SHA-256 the password before bcrypt — this reintroduces the fast-hash problem for short outputs; use a proper pre-hashing scheme documented in the OWASP Password Storage Cheat Sheet.

Python (passlib — wraps bcrypt correctly):

python
from passlib.hash import bcrypt

hashed = bcrypt.using(rounds=12).hash(password)
verified = bcrypt.verify(password, hashed)

Node.js (bcryptjs — pure JS, or bcrypt native):

typescript
import bcrypt from 'bcryptjs';

const hashed = await bcrypt.hash(password, 12);
const match  = await bcrypt.compare(password, hashed);

Know your vulnerabilities before attackers do

Run a free VAPT scan — takes 5 minutes, no signup required.

Book Your Free Scan

scrypt: Memory-Hard Hashing

scrypt (Colin Percival, 2009) extended the adaptive-hash model with a memory-hard property: cracking requires not just CPU cycles but significant RAM. This directly raises the cost of ASIC and GPU attacks, which can be highly parallelised on CPU but face memory bandwidth limits.

Parameters: N (CPU/memory cost, power of 2), r (block size), p (parallelisation factor).

OWASP recommendation: N=32768 (2^15), r=8, p=1 as minimum; N=65536 for higher-assurance systems.

scrypt suits workloads needing stronger GPU resistance than bcrypt when infrastructure can support the memory overhead (32–64 MB per hash at recommended settings).

Argon2 won the Password Hashing Competition in 2015 and is the current recommendation from both OWASP and NIST SP 800-63B. It comes in three variants:

    1. Argon2d: optimised against GPU cracking, but vulnerable to side-channel attacks. Not for password hashing.
    2. Argon2i: side-channel resistant, used for key derivation.
    3. Argon2id: hybrid — first pass uses Argon2i (side-channel safe), subsequent passes use Argon2d (GPU resistant). Use this for password hashing.
OWASP minimum parameters for Argon2id:
ParameterMinimumRecommended
Memory (m)19 MB (19456 KiB)64 MB (65536 KiB)
Iterations (t)23
Parallelism (p)14 (match CPU cores)
Output length32 bytes32 bytes
Salt length16 bytes16 bytes
Python (argon2-cffi):
python
from argon2 import PasswordHasher

ph = PasswordHasher(time_cost=3, memory_cost=65536, parallelism=4)
hashed = ph.hash(password)
ph.verify(hashed, password)  # raises VerifyMismatchError on failure
typescript
// Node.js — @node-rs/argon2 (native binding, recommended)
import { hash, verify } from '@node-rs/argon2';

const hashed = await hash(password, {
  memoryCost: 65536, timeCost: 3, parallelism: 4
});
const match = await verify(hashed, password);
💡
TIP
Argon2id encodes all parameters (salt, version, memory, time, parallelism) inside the output string. You do not need to store parameters separately — the library reads them from the stored hash, which makes future parameter upgrades transparent.

Login Flow and Offline Attack Resistance

graph TD A[User submits password] --> B[Fetch salt from DB record] B --> C[Compute Argon2id hash
with stored params] C --> D{Constant-time
comparison} D -->|Match| E[Login success
Check rehash needed] D -->|No match| F[Login failed
Increment rate-limit counter] E --> G{Params outdated?} G -->|Yes| H[Rehash with new params
Update DB record] G -->|No| I[Session issued] A2[Attacker obtains stolen DB] --> B2[Offline cracking attempt] B2 --> C2[Each guess requires
full Argon2id computation] C2 --> D2[64 MB RAM consumed
per guess attempt] D2 --> E2[Cracking 1 account
takes hours on GPU] E2 --> F2[Cracking millions
becomes economically infeasible] style A fill:#1e3a5f,stroke:#3B82F6,color:#e2e8f0 style B fill:#1e3a5f,stroke:#3B82F6,color:#e2e8f0 style C fill:#1e3a5f,stroke:#3B82F6,color:#e2e8f0 style D fill:#1e3a5f,stroke:#3B82F6,color:#e2e8f0 style E fill:#1e3d2f,stroke:#10B981,color:#e2e8f0 style F fill:#5f1e1e,stroke:#EF4444,color:#e2e8f0 style G fill:#1e3a5f,stroke:#3B82F6,color:#e2e8f0 style H fill:#1e3a5f,stroke:#3B82F6,color:#e2e8f0 style I fill:#1e3d2f,stroke:#10B981,color:#e2e8f0 style A2 fill:#5f1e1e,stroke:#EF4444,color:#e2e8f0 style B2 fill:#5f1e1e,stroke:#EF4444,color:#e2e8f0 style C2 fill:#5f1e1e,stroke:#EF4444,color:#e2e8f0 style D2 fill:#5f1e1e,stroke:#EF4444,color:#e2e8f0 style E2 fill:#5f1e1e,stroke:#EF4444,color:#e2e8f0 style F2 fill:#1e3d2f,stroke:#10B981,color:#e2e8f0

Relative Cracking Resistance Across Algorithms

pie title Relative Offline Cracking Resistance — Qualitative "MD5 unsalted" : 1 "SHA-256 salted" : 5 "bcrypt cost-12" : 40 "Argon2id recommended" : 54

The proportions above are illustrative of relative ordering, not empirical hash-rate measurements. MD5 and SHA-256 are orders of magnitude faster than bcrypt; Argon2id at recommended parameters adds memory-hardness on top of time cost, making it the strongest of the four for offline-cracking resistance.

Migrating Legacy Password Hashes

Running MD5 or SHA-1 hashes in production is common in Indian startups that inherited older codebases. Migration does not require forcing all users to reset their passwords simultaneously — an online migration is safer:

  1. Add a hash_algorithm column to your users table (values: md5_legacy, sha1_legacy, bcrypt_v1, argon2id_v1).
  2. On each successful login, verify the password against the legacy hash. If it matches, immediately rehash with Argon2id and update the record.
  3. After 90 days, any account that has not logged in still holds a legacy hash. At this point you have three choices: force a password reset on next login, email a reset prompt, or accept that inactive accounts remain legacy until they return.
  4. Never store the plaintext during migration. The plaintext is only available at the login moment — use it and discard it.
🚨
DANGER
Do not attempt to "upgrade" existing hashes by hashing the hash. Argon2id(MD5(password)) is not a valid migration — it simply applies Argon2id to a fast hash of unknown character, and an attacker who knows the scheme can still exploit it. The only valid upgrade path is at login time with the original plaintext.

Rate Limiting and MFA: Defence in Depth

Password hashing protects your stored credentials after a breach. Rate limiting and MFA protect the login endpoint before a breach.

ControlWhat It StopsImplementation Note
Progressive delay on failed loginsOnline brute-forceExponential backoff after 5 failures
Account lockout with unlock tokenCredential stuffingLock after 10 failures; email unlock
TOTP / FIDO2 MFACredential reuse from other breachesRequired for admin and finance roles
Device fingerprinting + anomaly alertAccount takeover post-credential theftFlag unfamiliar device on first login
Pepper rotationDB-only exfiltrationRe-login triggers rehash with new pepper
NIST SP 800-63B discourages mandatory periodic password rotation (it produces weaker passwords) and requires checking credentials against known-compromised lists. HaveIBeenPwned exposes a k-anonymity API for this without exposing the full hash.
🛡️
SECURITY
Rate limiting must be applied at the infrastructure layer — not just application code. An attacker distributing requests across IP ranges bypasses per-IP limits. Combine per-IP, per-account, and global request-rate checks. Include your CDN or WAF in the control surface.

DPDP Act Compliance and "Reasonable Security Safeguards"

India's Digital Personal Data Protection Act 2023 (DPDP) requires data fiduciaries to implement reasonable security safeguards. Passwords are personal data. Storing them in a reversible or weakly hashed form is not a reasonable safeguard — it is a known-bad practice with documented attack paths.

CERT-In guidelines under the IT Act require protecting authentication credentials. A breach disclosure revealing MD5-stored passwords will draw scrutiny over whether due diligence was exercised.

Implementing Argon2id at OWASP-recommended parameters, enforcing rate limiting, and logging authentication anomalies provides a documented, defensible security posture. For a detailed assessment of your authentication implementation and the rest of your attack surface, the Bachao.AI blog covers practical security engineering for Indian developers, and you can run a free VAPT scan to identify exposed endpoints and configuration weaknesses.

Dhisattva AI Pvt Ltd builds automated VAPT tooling specifically for Indian SMBs navigating DPDP, CERT-In, and SEBI compliance requirements.

Quick Reference: Algorithm Selection

AlgorithmMemory HardGPU Resistant72-byte LimitOWASP RecommendedUse Case
MD5NoNoNoNeverLegacy only — migrate immediately
SHA-256 saltedNoNoNoNeverNever for passwords
bcrypt (cost 12)NoPartiallyYes — 72 bytesYes (minimum)Existing bcrypt systems; maintain
scrypt (N=65536)YesYesNoYesSystems needing memory-hardness
Argon2id (recommended params)YesYesNoPrimaryAll new systems
🎯Key Takeaway
Use Argon2id with memory 64 MB, time cost 3, parallelism 4 for all new password storage. Migrate legacy MD5/SHA-1/SHA-256 hashes at login time, not in batch. Add rate limiting and MFA as independent layers — password hashing is your last line of defence after a breach, not a substitute for preventing one.

External References

Frequently Asked Questions

Why can I not use SHA-256 with a salt for password storage?
SHA-256 is a fast general-purpose hash — a modern GPU can attempt billions of guesses per second against a salted SHA-256 hash. The salt prevents rainbow table attacks but does nothing to slow brute-force speed. Adaptive algorithms like Argon2id are designed to be slow and memory-hungry, making GPU cracking economically infeasible.
What Argon2id parameters should I use in a Node.js application?
OWASP recommends a minimum of 19 MB memory, 2 iterations, and parallelism 1. For new production systems prefer 64 MB, 3 iterations, parallelism 4. Use the @node-rs/argon2 package (native binding) or argon2 npm package. Benchmark on your server to confirm hashing completes in under 500 ms under expected login concurrency.
Does bcrypt have a known vulnerability I should worry about?
bcrypt has no known cryptographic vulnerability, but its 72-byte input truncation is a gotcha for applications using long passphrases. For all new systems, prefer Argon2id — it has no analogous limitation, is memory-hard, and is the current OWASP primary recommendation.
How do I migrate 500,000 MD5 password hashes without forcing a mass reset?
Implement an online migration: on each successful login, verify against the MD5 hash, then immediately rehash with Argon2id and update the record. After 90 days, prompt inactive accounts to reset on next login. Never batch-hash the MD5 hashes — hash the original plaintext available only at login time.
Is password hashing enough to meet DPDP Act 2023 requirements?
Password hashing is a necessary but not sufficient control. DPDP's "reasonable security safeguards" requirement covers the full authentication surface: hashing algorithm strength, rate limiting, MFA for privileged roles, breach monitoring, and anomaly detection. Document your controls and be prepared to demonstrate them to a Data Protection Board if a breach occurs.
What is the difference between a salt and a pepper?
A salt is a random per-user value stored in the database alongside the hash — its purpose is uniqueness, defeating precomputed attacks. A pepper is a secret value stored outside the database (in an environment variable or secrets manager) applied globally before hashing. If the database is stolen but the pepper is not, the hashes are uncrackable. Both should be used together for highest assurance.
BR

Bachao.AI Research Team

Cybersecurity Research

AI-powered security research and threat intelligence from the Bachao.AI team. Covering the latest vulnerabilities, CVEs, and cybersecurity developments affecting Indian businesses.

Get cybersecurity insights for Indian SMBs

Weekly vulnerability alerts, DPDP compliance tips, and security guides. No spam — unsubscribe anytime.

We respect your privacy. Your email is never shared.

Find out if you're exposed to this class of threat

Free automated scan — risk score in under 2 hours. No credit card required.

Scan Your Attack Surface
Find your vulnerabilitiesStart free scan →