WPA3 and SAE (Dragonfly), step by step — and the offline attack it ends
Every value on this page is computed here, in your browser, with real P-256 arithmetic: the hunting-and-pecking loop that turns an SSID and a passphrase into a point on the curve, the commit exchange with its scalar multiplications, the shared secret both sides reach, and the confirm MACs that prove they derived the same key. Then the same arithmetic is used to show why an attacker who captures the whole exchange still cannot test a single password guess offline — and why that is the whole point of SAE. The point arithmetic the page rests on is cross-checked against WebCrypto's own ECDH.
What an eavesdropper captures
Everything on the wire in a SAE exchange is public: two scalars and two curve points. They are inert without the ephemeral secrets the peers delete when the handshake ends. This is the exact opposite of the WPA2 four-way handshake, whose ANonce/SNonce/MIC1–MIC4 give a captured-offline cracker everything it needs.
Why WPA2-PSK failed
One capture, attacked forever
WPA2-PSK authenticates with a four-way handshake. Its security rests
entirely on the passphrase's guessing cost: the pairwise master key is PBKDF2 over SSID ‖ passphrase,
and the handshake's message-integrity codes are a function of that key and the observed nonces. Anyone who
records a single handshake — or forces one by deauthenticating a client — can test candidate passphrases
offline, at whatever rate their hardware manages. The network is not involved; it cannot rate-limit what
it never sees. A passphrase is thus exactly as strong as its cost to guess, and human passphrases are cheap.
The dictionary attack, in one line
That attack is worked through, byte for byte, on the WPA2 & the four-way handshake page: PBKDF2 the guess, derive the PTK with the PRF, recompute MIC1, compare. Correct guess → the MIC matches, the attacker has the PSK, and with it the traffic. Wrong guess → move to the next word. This page does not repeat it; it exists to show what replaced it, and why the replacement has no equivalent.
SAE — Simultaneous Authentication of Equals, the Dragonfly key exchange of RFC 7664, adopted by WPA3 — makes each online guess cost one interaction with the access point. There is no offline step. Turn to the attack step below and the arithmetic will show you why.
WPA2-PSK vs WPA3-SAE
| property | WPA2-PSK (four-way handshake) | WPA3-SAE (Dragonfly / PAKE) |
|---|---|---|
| offline attack | Crackable offline from one captured handshake; guess rate = the attacker's GPU farm. This is the property that ended WPA2. | None available. A captured exchange yields no value that a password guess can be tested against without talking to the AP. Each guess costs one online interaction. |
| forward secrecy | No. Recover the passphrase later and every recorded session decrypts; the PMK/PTK are functions of the passphrase and observed nonces. | Yes. The session key is the x-coordinate of privSTA·privAP·PE; the ephemeral scalars are destroyed at the end of the handshake, so learning the passphrase afterwards is not enough. |
| downgrade resistance | Transition mode lets a rogue AP answer with the WPA2 handshake, which the client will accept — reintroducing the offline attack. PMF is optional. | SAE is entangled with the frame-protection handshake: a SAE-capable client must see a PMF (802.11w) connection, and WPA3-only mode forbids the fallback. This is the Dragonblood downgrade the standard closed. |
| per-guess cost to attacker | One PBKDF2 (≈10⁴–10⁵/s per GPU) against a capture they already hold. | One full exchange with the AP, plus the AP's own anti-clogging and retry limits. |
| what the passphrase buys | The whole network: a strong passphrase is the only thing standing between a capture and the PMK. | One online attempt per interaction; a weak passphrase is still weak, but it can only be attacked at network speed. |
Dragonblood (2019) — what SAE's first form got wrong
Side channels in the hunting-and-pecking loop
The password element is found by hashing and re-hashing until a value lands on the curve. The number of
iterations is not secret in principle, but a naive implementation's running time leaks it in practice, and
the loop's big-number operations (the quadratic-residue test, the modular square root, the branch that picks
y or p−y) leak through the cache and the branch predictor. An attacker who can measure
the AP's response time for many handshakes partitions the password space: passwords whose element is found on
iteration 1 behave differently from those needing 4. Vanhoef and Rønne's Dragonblood attacks turned those
leaks into a password-recovery oracle. RFC 7664 already anticipates part of this — it recommends a security
parameter k so that at least k iterations always run, and blinding the
quadratic-residue test — but timing the loop was only the start.
The downgrade to WPA2
WPA3 was deployed in transition mode: an AP advertises both WPA3-SAE and WPA2-PSK so old clients can still join. A rogue AP therefore has an easy choice — offer only WPA2, and a client that would have done SAE quietly performs the four-way handshake instead. The captured handshake is then crackable offline, exactly as before. This is why WPA3 makes PMF (802.11w) mandatory — Protected Management Frames stop the forged deauth and the forged (re)association that the downgrade and the handshake-capture attacks depend on — and why a WPA3-only network refuses the WPA2 fallback altogether.
What H2E fixed
Hash-to-element (H2E) replaces the loop with a single, constant-time hash-to-curve map
(the SSWU construction of RFC 9380, P256_XMD:SHA-256_SSWU_RO_): the password and the SSID go into
a hash, and the output is mapped straight onto the curve with no searching and no rejection branch. There is no
iteration count to leak because there are no iterations. H2E is negotiated in the SAE handshake and shipped as
the modern default. It closes the timing and cache side channels, not the downgrade — that needed PMF.
WPA3's other pieces, briefly
| PMF (802.11w) | Protected Management Frames. Mandatory in WPA3. Management frames — including the deauthentication and disassociation frames an attacker uses to force a handshake capture — are authenticated, so they can no longer be forged. This is the concrete fix for the downgrade and forced-capture attacks. |
| 192-bit enterprise mode | WPA3-Enterprise's optional suite uses GCMP-256 for data confidentiality and BIP-GMAC-256 for the management-frame integrity, with a stronger derived key hierarchy (SHA-384 / HMAC-SHA-384) — a suite aimed at government and regulated networks, not the consumer WPA3-SAE mode this page implements. |
| OWE | Opportunistic Wireless Encryption (RFC 8110). For open networks, it runs an unauthenticated Diffie–Hellman so each client gets its own encrypted link with the AP. It gives confidentiality against passive eavesdroppers, not authentication — the network is still "open", it just stops broadcasting your traffic in the clear. It replaces the old "open + no encryption" case, not SAE. |
Notation
| SSID, password | The network name and the shared passphrase. Both peers must agree on both. Together they fix the password element. |
| PE (PWE) | The password element: a point on P-256 derived deterministically from the SSID and password. It is the password, represented as a curve point. Nobody sends it. |
| H(x) | A one-way hash (SHA-256 on this page). |
| KDF-n(k, label) | A key-derivation function stretching key k to n bits under a label. This page uses HKDF-Expand-SHA256 (RFC 5869); see the glossary for where that differs from 802.11. |
| priv, mask | The two ephemeral random scalars each peer draws. 1 < priv, mask < q. The mask is destroyed as soon as the commit is built. |
| scalar = (priv + mask) mod q | What the peer sends as its commit-scalar. It hides priv only because mask is unknown. |
| Element = −(mask · PE) | The commit-element: the mask times the password element, negated. It is the mask's commitment to the password. |
| ss | The shared secret: the x-coordinate of privSTA · privAP · PE. Both sides reach it; neither sends it. |
| kck | mk | KDF(ss, "Dragonfly Key Derivation"). kck is the key-confirmation key; mk the master key handed to the 802.11 four-way handshake that follows. |
| confirm | H(kck ‖ own scalar ‖ peer scalar ‖ own element ‖ peer element ‖ sender-id). Each side recomputes the other's and compares — proof both derived the same ss, hence the same password. |
| q, n, p, a, b, G | The P-256 group order, the prime field, the curve coefficients and the generator. Cofactor is 1, as Dragonfly requires. |
| PAKE | Password-Authenticated Key Exchange: a key exchange that authenticates with a low-entropy password yet leaks nothing offline. SAE is one. |
Glossary — what is faithful here, and what is simplified
What the page implements, exactly
The page implements the original hunting-and-pecking PWE derivation (HnP) of RFC 7664 §3.2.1, not the
newer hash-to-element (H2E). You will see the loop run and fail and finally land on the curve, which is the
teaching point — but HnP is also the version whose timing leaked, and the reason H2E exists. Every iteration
shown is real arithmetic: a SHA-256 of SSID ‖ counter ‖ password, an HKDF stretch, and a
quadratic-residue test modulo the P-256 prime.
Where it is simplified — read this before quoting numbers
Identities. RFC 7664 hashes max(A,B) ‖ min(A,B) ‖ password ‖ counter, where A and B are the
two peers' identities — in Wi-Fi, their MAC addresses. This page uses the SSID in that position: a single
shared context both peers already agree on, which is what 802.11's H2E does with the SSID. The MAC addresses and
the canonical max/min ordering are simplified away so the page needs one network name instead of two radios.
The KDF. RFC 7664 and 802.11 specify their own KDFs (SP 800-108-style, and 802.11's
dot11–KDF for the key derivation). This page uses HKDF-Expand-SHA256 (RFC 5869) with the same
labels. The construction differs; the labels and the role each output plays do not. Two peers running the real
802.11 KDF would derive different bytes from the same inputs — this page is internally consistent, not
wire-compatible with a real AP.
Encodings. Scalars are encoded 32-byte big-endian here; 802.11 uses a little-endian scalar and a
specific element encoding. Points are shown uncompressed (0x04 ‖ x ‖ y, 65 bytes) with the compressed
form (0x02/0x03 ‖ x, 33 bytes) available; 802.11 fixes its own. The point arithmetic, the parity
trick and the exchange itself are the standard's.
The confirm hash. The transcripts are hashed with SHA-256 over the args above; 802.11 wraps them in its own KCK/confirm structure. The property being demonstrated — both sides recomputing each other's MAC from the derived kck — is unchanged.
Groups. WPA3-SAE permits P-256, P-384, P-521 and the finite-field MODP groups (ffc groups) of RFC 7664 §3.2.2. This page does P-256 only, which is both the common case and the one the site's verified curve arithmetic covers.
The rest of WPA3. The four-way handshake that actually derives the session keys from mk,
the 802.11 state machine, anti-clogging tokens, and the SAE confirm retry logic are out of scope here; this page
ends where the PMK is handed over.
Why the page says the arithmetic is verified
P-256 point arithmetic is not exposed by WebCrypto, so the site carries its own BigInt implementation in
assets/cryptolib.js. This page's arithmetic on top of it is cross-checked at the bottom of the page
against WebCrypto's own ECDH: a random WebCrypto P-256 key agrees on a shared point computed two
different ways. A scalar-multiplication bug would break that agreement, so the negative dictionary-attack result
below rests on arithmetic validated twice.