Skip to main content
๐Ÿ“œ WAYPOINT LESSON

Auth primitives

โญโญโญ advancedโณ 16 min read๐Ÿ“ Lesson 170 of 180

Timing-safe comparison and per-user salts โ€” the two primitives behind every credential store.

Two primitives, both about information leakage:

Timing attacks compare secrets character-by-character and stop early โ€” the TIME of the failure leaks how many characters matched. String.equals is an early-exit compare. Secrets must be compared in constant time:

static boolean safeEquals(byte[] a, byte[] b) {
    return MessageDigest.isEqual(a, b);   // JDK built-in: constant-time
}

Rainbow tables attack unsalted hashes: a precomputed digest of "hunter2" matches every user who ever used "hunter2". The fix is a PER-USER random salt mixed into the digest โ€” same password, different stored bytes per user:

byte[] salt = SecureRandom.getInstanceStrong()
    .generateSeed(16);
byte[] hash = sha256(salt, passwordBytes);   // store BOTH

Verify by recomputing with the STORED salt and comparing constant-time. For production password storage the stronger shape is a slow KDF (bcrypt/ scrypt/Argon2/PBKDF2) โ€” the sandbox course teaches the salted-digest shape; the principle scales: cost per guess is a design parameter.