Modern Cryptography & Secure Hashing: Argon2id, Bcrypt, HMAC & Symmetric Encryption Engineering
A practitioner guide to modern cryptographic primitives: why fast hashes destroy passwords, Argon2id vs Bcrypt memory hardness, timing-safe HMAC webhook verification, and authenticated AES-256-GCM encryption.
1. The Triad: Hashing vs Encryption vs Encoding
| Concept | Reversible? | Key Required? | Primary Engineering Purpose | Copy |
|---|---|---|---|---|
| Encoding (Base64, Hex, URL) | Yes (anyone can decode it) | No | Safe transmission over ASCII-only mediums (data representation only; ZERO security) | |
| Hashing (SHA-256, Bcrypt, Argon2) | No (mathematically one-way) | No (password hashes use a salt; HMAC uses a secret key) | Data integrity checks, digital signatures, and secure credential storage | |
| Encryption (AES-256, RSA, ChaCha20) | Yes (only with the matching key) | Yes (shared secret key, or a public/private key pair) | Confidentiality of sensitive data in transit (TLS) or at rest (databases) |
2. Modern Password Storage: Argon2id vs Bcrypt vs PBKDF2
import bcrypt from 'bcrypt';
const password = 'SuperSecretUserPassword2026!';
const saltRounds = 12; // 2^12 = 4,096 iterations (~250ms computation time)
// Hash creation:
const hash = await bcrypt.hash(password, saltRounds);
// Output format: $2b$12$e8uq... (contains algorithm, cost factor, salt, and hash)
// Constant-time password verification:
const isMatch = await bcrypt.compare(candidatePassword, hash);Salt is randomly generated and embedded directly into the resulting string.
3. Message Authentication with HMAC & Timing Attacks
import crypto from 'crypto';
function verifyWebhook(rawPayload, headerSignature, webhookSecret) {
const expectedSignature = 'sha256=' + crypto
.createHmac('sha256', webhookSecret)
.update(rawPayload, 'utf8')
.digest('hex');
const expectedBuffer = Buffer.from(expectedSignature, 'utf8');
const actualBuffer = Buffer.from(headerSignature, 'utf8');
if (expectedBuffer.length !== actualBuffer.length) {
return false;
}
// Prevents timing side-channel attacks by always checking all bytes:
return crypto.timingSafeEqual(expectedBuffer, actualBuffer);
}Uses crypto.timingSafeEqual to prevent microsecond timing leak attacks.
4. Symmetric Encryption with AES-256-GCM
5. Asymmetric Signatures & Keys: RSA vs Ed25519 / X25519
| Algorithm | Key Size | Performance & Speed | Recommendation | Copy |
|---|---|---|---|---|
| Ed25519 (Digital Signatures) | 32-byte (256-bit) public key | Very fast signing and verification; constant-time design resists timing side-channels | Preferred for SSH keys and Git commit signing | |
| X25519 (Key Exchange / ECDH) | 32-byte (256-bit) key | Fast Diffie-Hellman key agreement | Preferred key exchange in TLS 1.3 and WireGuard | |
| RSA-4096 (Legacy Universal) | 512-byte (4096-bit) key | Slow signing; large keys and signatures | Acceptable for backwards compatibility; prefer Ed25519/X25519 for new systems | |
| ECDSA (NIST P-256) | 32-byte (256-bit) key | Fast, but every signature needs a unique, unbiased random nonce | Use where standards require it (TLS certificates, WebAuthn); a reused or biased nonce leaks the private key |
6. High-Risk Cryptographic Mistakes Checklist
| Dangerous Mistake | Vulnerability Consequence | Engineering Solution | Copy |
|---|---|---|---|
| Using Math.random() for secrets | PRNG is completely predictable and seeded by system clock | Always use crypto.randomBytes() or crypto.getRandomValues() (CSPRNG) | |
| Reusing IV in AES-GCM | Reusing IV with the same key destroys authenticity and allows plaintext recovery | Generate a fresh crypto.randomBytes(12) for every single encryption operation | |
| Rolling your own crypto algorithm | Hidden mathematical flaws, cache-timing leaks, and entropy issues | Use established primitives vetted by cryptographers (Libsodium, Node crypto, OpenSSL) | |
| Hardcoding encryption keys in code | Leaks into git commits, CI/CD logs, and source distribution bundles | Inject keys at runtime via AWS KMS, HashiCorp Vault, or encrypted env vars |
Related Free Online Tools
Put these techniques into practice immediately with our privacy-first browser utilities:
Generate salt-hardened Bcrypt hashes and verify passwords against stored hashes.
Compute keyed hash message authentication codes with SHA-256 and SHA-512.
Calculate cryptographic SHA-256 checksums to verify payload and binary file integrity.