Security8 min read

Cryptography for Developers

Apply cryptographic primitives correctly: hash passwords with bcrypt/Argon2, encrypt data with AES-GCM, sign JWTs, and configure TLS properly.

cryptographyencryptionhashingtls

Cryptography is the foundation of data confidentiality, integrity, and authenticity. Most breaches stem from misuse-rolling your own crypto, using weak algorithms, or mismanaging keys-rather than flaws in the primitives themselves.

Never implement cryptographic algorithms from scratch. Use well-audited libraries. Follow the principle of using the highest-level abstraction available: prefer libsodium/NaCl APIs over raw AES, and JWT libraries over manual HMAC.

Workflow

  1. Hash passwords with a slow KDFbcrypt/Argon2 are intentionally slow, making brute-force attacks impractical even after a DB breach.
  2. Encrypt data at rest with AES-256-GCMGCM mode provides both confidentiality AND authenticity (AEAD), preventing tampering.
  3. Sign and verify data with asymmetric keysAsymmetric signatures prove authenticity without sharing a secret key.
  4. Configure TLS correctlyTLS 1.0/1.1 have known vulnerabilities; weak cipher suites enable downgrade attacks.
  5. Manage secrets and keys securelyKey exposure negates all cryptographic protections.

Output Format

Passwords hashed with Argon2id, sensitive data encrypted with AES-256-GCM+KMS, JWT signed with RS256/Ed25519, TLS 1.3 configured, key rotation documented.

Examples

Argon2id hash: `const hash = await argon2.hash(pw, { type: argon2.argon2id, memoryCost: 2**16, timeCost: 3, parallelism: 1 })`
AES-GCM encrypt: `const iv = crypto.randomBytes(12); const cipher = crypto.createCipheriv("aes-256-gcm", key, iv); const enc = Buffer.concat([cipher.update(data), cipher.final()]); const tag = cipher.getAuthTag()`
Ed25519 sign: `const sig = crypto.sign(null, Buffer.from(message), { key: privateKey, dsaEncoding: "der" })`

Edge Cases & Gotchas

  • Never reuse an IV/nonce with the same key in GCM mode-this breaks authenticity completely
  • JWT "alg: none" attack: always explicitly verify algorithm type, reject "none"
  • Timing attacks on string comparison: always use `crypto.timingSafeEqual()` for secret comparison

When to Break These Rules

  • Use simpler symmetric encryption for non-sensitive internal data where performance is critical and integrity is enforced by other means (e.g., database transactions).

Reference Files

  • libsodium: https://libsodium.gitbook.io/
  • OWASP Cryptographic Storage Cheat Sheet: https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
  • Argon2 spec: https://github.com/P-H-C/phc-winner-argon2

More skills in this library

Browse all technical skills - Mobile, AI/ML, Web, Backend, Design, and Product.