You turn on two-factor authentication and suddenly you’re typing six-digit codes from your phone every time you log in. You know it’s “more secure.” But do you know what’s actually happening when that code appears? Why it changes every 30 seconds? Why the SMS version is worse? Why a $25 USB stick makes phishing mathematically impossible?

Here’s the full picture — from the HMAC math to the SIM swap to the passkey that might finally make all of this irrelevant.

The TLDR

Two-factor authentication adds a second proof of identity on top of your password — something you physically have. The 30-second code on your authenticator app is generated by feeding the current time and a shared secret into an HMAC function. SMS codes work similarly but travel through the phone network, which is riddled with exploitable holes. Hardware security keys use public-key cryptography tied to the specific website domain, making phishing cryptographically impossible — not just “harder,” but impossible. Passkeys are the consumer-friendly evolution of hardware keys, backed by Apple, Google, and Microsoft. The hierarchy from worst to best: no 2FA, SMS, authenticator app, hardware key / passkey. Every step up the ladder eliminates entire categories of attacks.

The Reality

In 2019, Google published a study showing that SMS-based 2FA blocked 100% of automated bot attacks, 96% of bulk phishing attacks, and 76% of targeted attacks. Hardware security keys blocked 100% across all three categories. Those numbers tell you two things: any 2FA is dramatically better than none, and not all 2FA is created equal.

The problem is that most folks think “I turned on 2FA, I’m good.” And compared to having just a password, you absolutely are better off. But the threat landscape has adapted. Tools like EvilGinx act as real-time phishing proxies that capture your password and your TOTP code simultaneously, replaying them to the real site before the 30-second window closes. SIM swapping — where an attacker social-engineers your carrier into porting your number to their SIM — turns SMS 2FA into a liability for high-value targets. The FBI’s IC3 reported a massive surge in SIM swap complaints, with losses exceeding $68 million in a single year.

So “turn on 2FA” is incomplete advice. You need to understand what each type actually does, what it protects against, and where the walls end.

How It Works

HOTP — The Counter-Based Foundation

Everything starts with RFC 4226 — HOTP, the HMAC-based One-Time Password algorithm, published in 2005. The concept is simple: you and the server share a secret key. You both maintain a counter. To generate a code, you feed the secret key and the counter value into an HMAC-SHA1 function, then extract a 6-digit number from the output.

Here’s the math in plain English:

  1. You and the server agree on a secret key (usually 20 bytes of random data, encoded as base32).
  2. You both keep a counter that starts at 0.
  3. To get a code: HMAC-SHA1(secret_key, counter) produces a 20-byte hash.
  4. Take 4 bytes from a specific offset in that hash (determined by the last nibble).
  5. Convert those 4 bytes into a 31-bit integer.
  6. Modulo 10^6 gives you a 6-digit code.
  7. After each successful authentication, both sides increment the counter.

The problem with HOTP is synchronization. If you generate a code on your device but don’t use it, your counter gets ahead of the server’s counter. Most implementations handle this by looking ahead a small window (say, 10 counter values), but it’s clunky.

TOTP — Adding the Clock

RFC 6238 solved the counter problem by replacing it with time. TOTP — Time-based One-Time Password — uses the current Unix timestamp divided by a time step (usually 30 seconds) as the counter value. That’s it. That’s the only difference from HOTP.

counter = floor(current_unix_time / 30)
code = HOTP(secret_key, counter)

Your authenticator app and the server both know the current time (within a reasonable tolerance). They both know the shared secret. They both do the same math. They both get the same 6-digit code. Every 30 seconds, the timestamp division produces a new counter value, and a new code appears.

That QR code you scan when setting up 2FA? It’s a URI containing the shared secret, the issuer name, and parameters like the time step and digit count. Something like: otpauth://totp/GitHub:you@email.com?secret=JBSWY3DPEHPK3PXP&issuer=GitHub. Your authenticator app stores that secret and runs the math every 30 seconds forever.

Why the Shared Secret Matters

Here’s the thing about TOTP that most folks don’t think about: that shared secret is stored on the server too. If the server gets breached and the 2FA secrets are exfiltrated, an attacker can generate valid TOTP codes for every account. This happened in the 2023 Retool breach — attackers used a phishing campaign combined with social engineering to extract TOTP secrets. The shared secret model means the server is a single point of failure for your second factor.

This is fundamentally different from how hardware keys work, which is why the distinction matters.

SMS 2FA — The Weakest Form

SMS-based 2FA sends a code to your phone number via text message. The code is typically generated server-side (not derived from a shared secret on your device) and transmitted through the SS7 signaling network — the same protocol infrastructure that’s been routing phone calls since the 1970s.

SS7 was designed in an era when only a handful of trusted telecom operators existed. It has no encryption, no authentication between network nodes, and was never designed to resist adversarial access. Researchers have demonstrated the ability to intercept SMS messages by exploiting SS7 vulnerabilities since at least 2014. Nation-state actors and well-resourced criminals have used SS7 interception to defeat SMS-based 2FA on banking platforms in Germany, the UK, and elsewhere.

But the more common attack is simpler: SIM swapping. An attacker calls your mobile carrier, convincingly impersonates you (using personal information scraped from data brokers, social media, or previous breaches), and asks to transfer your phone number to a new SIM card. Once the port completes — sometimes in minutes — they receive your SMS codes. They log into your email, reset your other passwords, and work outward.

NIST SP 800-63B formally designated SMS as a “restricted” authenticator back in 2017, meaning it’s allowed but discouraged. The recommendation is to use it only when better options aren’t available.

All that said — SMS 2FA is still dramatically better than no 2FA. It blocks automated attacks, credential stuffing bots, and lazy attackers who just have your password from a breach. Don’t let perfect be the enemy of good. If SMS is all a service offers, turn it on.

Authenticator Apps — TOTP Done Right

Authenticator apps — Google Authenticator, Authy, Microsoft Authenticator, Aegis (open-source on Android), Raivo or 2FAS on iOS — run the TOTP algorithm locally on your device. No network request, no SMS, no SS7.

The advantages over SMS:

The weaknesses:

Backing Up TOTP Secrets

When you set up TOTP on a new account, most services show you backup codes — usually 8-10 one-time-use codes. Write them down. Store them physically. Not in your email, not in a cloud note. On paper, in a safe, or in your password manager’s secure notes. These are your recovery path if your authenticator device is lost or destroyed.

Some authenticator apps (Authy, Microsoft Authenticator) offer cloud backup of TOTP secrets. This is convenient but means your secrets are only as secure as that cloud account — which circles right back to password security and 2FA on the backup account. It’s turtles all the way down.

Hardware Keys — FIDO2 and WebAuthn

Hardware security keys — YubiKeys, Google Titan Keys, SoloKeys, Nitrokeys — are a fundamentally different animal. They use public-key cryptography instead of shared secrets, and they bind credentials to specific website domains. This is the FIDO2 standard, with the browser-side component called WebAuthn.

Here’s how it works:

  1. Registration: You plug in your key (or tap it via NFC) on a website. The key generates a unique public/private key pair for that specific domain. The private key stays on the key and never leaves. The public key is sent to the server.
  2. Authentication: The server sends a random challenge. The key signs the challenge with the private key (after you physically touch it to confirm presence). The server verifies the signature with your public key. Done.

The critical difference: origin binding. The key cryptographically ties each credential to the website’s domain. If you registered a key with github.com, the key will only respond to authentication challenges from github.com. If a phishing proxy sends you to g1thub.com or github-login.evil.com, the key looks for a credential matching that domain, finds nothing, and refuses to sign. It doesn’t warn you — it simply can’t authenticate against the wrong domain. The phishing attack gets nothing.

Google deployed hardware keys to all 85,000+ employees in 2017 and subsequently reported zero successful phishing compromises. Not reduced — zero. CISA explicitly recommends phishing-resistant MFA based on FIDO2 for all high-value accounts.

Passkeys — The Consumer Evolution

Passkeys take the FIDO2 cryptographic model and make it usable for everyone. Instead of a dedicated hardware device, the credential lives in your platform’s secure hardware — Apple’s Secure Enclave, Google’s Titan security chip, Windows’ TPM. You authenticate with biometrics (Face ID, fingerprint) or your device PIN.

The key differences from hardware keys:

Why are Apple, Google, and Microsoft all pushing passkeys? Because passwords are an unsolvable problem at scale. No amount of password policy, user education, or breach notification will fix the fundamental issue that shared secrets can be stolen. Passkeys eliminate the shared secret entirely. The private key never leaves your device’s secure hardware. There’s nothing for the server to leak, nothing for a phishing page to capture, nothing to stuff or spray.

The tradeoff: synced passkeys depend on the security of your sync provider (Apple, Google, or a password manager). If someone compromises your iCloud account, they could potentially access your synced passkeys. This is why device-bound passkeys (hardware keys) remain the gold standard for the highest-risk accounts, and synced passkeys are the “good enough for nearly everyone” option.

How It Gets Exploited

SS7 Attacks on SMS

SS7 interception isn’t theoretical. In 2017, German bank customers lost money when attackers exploited SS7 to intercept SMS 2FA codes after first obtaining banking credentials through phishing. The attackers rerouted SMS messages through rogue network nodes. The EFF has documented these vulnerabilities extensively. The telecom industry has been slow to deploy SS7 replacements because the upgrade requires coordination across thousands of carriers worldwide.

SIM Swapping

The playbook: an attacker gathers your personal details (full name, phone number, last four of SSN, billing address) from data brokers or previous breaches. They call your carrier, pass the identity verification questions, and request a SIM swap. Some attacks involve bribing carrier employees directly — the DOJ has prosecuted multiple cases of carrier insiders facilitating SIM swaps for payment. Once the swap completes, every SMS code goes to the attacker. MITRE ATT&CK T1111 documents this under “Multi-Factor Authentication Interception.”

In the crypto space, SIM swapping has been devastating. A single 2019 SIM swap attack against a cryptocurrency investor resulted in $45 million in losses. Coinbase documented the pattern repeatedly — attackers SIM swap the phone number, reset the email password via SMS recovery, then access the exchange account.

Real-Time Phishing Proxies (EvilGinx)

EvilGinx is an open-source tool that acts as a man-in-the-middle between you and a legitimate website. You click a phishing link. EvilGinx presents you with the real login page (proxied), captures your password and TOTP code as you type them, forwards them to the real server, captures the authenticated session cookie, and hands it to the attacker. The whole process takes seconds and defeats any 2FA method that involves typing a code into a browser.

The only 2FA methods that survive a real-time proxy attack are those with origin binding — FIDO2 hardware keys and passkeys. The key checks the domain, sees it doesn’t match, and refuses to authenticate. The proxy becomes useless.

What You Can Do

The 2FA hierarchy, from worst to best:

  1. No 2FA. You’re rolling the dice with just a password. Don’t.
  2. SMS 2FA. Vulnerable to SIM swapping and SS7 interception. Still blocks automated attacks. Turn it on if it’s all that’s offered.
  3. Authenticator app (TOTP). No SIM swap risk, works offline, still phishable via real-time proxies. This is the minimum you should aim for.
  4. Hardware security key (FIDO2). Phishing-proof via origin binding. The gold standard. Buy two — one primary, one backup stored securely.
  5. Passkeys. Same phishing resistance as hardware keys, with sync convenience. Adopt these everywhere they’re supported.

Practical steps:

Sources & Further Reading