TLS 1.3, step by step — and every value checked against the RFC
A real handshake, executed in your browser: an X25519 key exchange, the RFC 8446 key schedule, and AES-128-GCM record protection. Nothing is illustrated — the ephemeral keys, the shared secret, every derived secret, every traffic key and IV, the Finished MACs and the encrypted records are all computed here on the page. The default run reproduces RFC 8448's published trace, so each value is compared with the number the IETF printed, and you can see whether they agree.
What an eavesdropper sees
Everything an attacker on the wire can observe in this handshake, separated from what stays secret. The plaintext parts are exactly the bytes anyone can read; the rest is AES-GCM output. Without the ephemeral private keys, the shared secret behind every key on this page is the X25519 discrete logarithm problem.
The 1-RTT trick, and what it costs
Why one round trip
The client sends a key share in its very first message, so the server can compute the shared secret immediately and start encrypting from its first flight onward. In TLS 1.2 the client waited for the server's parameters before choosing a key, costing an extra round trip — which is why 1.2 pages in your browser show "TLS handshake" latency that 1.3 does not.
Forward secrecy
Every connection uses fresh ephemeral keys, so the session keys are derived from a secret that is thrown away. An attacker who records this traffic and steals the server's long-term key later still cannot decrypt it — the ephemeral secret is gone. Static RSA key transport, where the client encrypts the session secret to the server's key, cannot offer this, and TLS 1.3 removed it.
What was deleted from TLS 1.2, and why
Renegotiation (and its attack), static RSA (no forward secrecy, Bleichenbacher), CBC modes with MAC-then-encrypt (padding oracles: BEAST, Lucky 13, POODLE), compression (CRIME), custom DH groups with weak parameters (Logjam), and a version-negotiation scheme that could be downgraded. TLS 1.3 keeps only AEAD ciphers, one key-schedule design, and moves the version into an extension.
The cost
0-RTT data — a client sending application data in its first flight, on a resumed connection — is replayable by an attacker who captures it, because nothing in the server has agreed to freshness yet. That is why 0-RTT is opt-in per connection, restricted to idempotent requests, and why the single-use-ticket machinery in RFC 8446 §8 exists at all.
Notation
| ClientHello / ServerHello | The two plaintext messages that establish parameters and exchange key shares. Each is a handshake message: 1 type byte, 3 length bytes, then the body. |
| {EncryptedExtensions} {Certificate} {CertificateVerify} {Finished} | Braces mean "encrypted under the handshake traffic keys". In TLS 1.3 everything after the ServerHello is encrypted, including the server's certificate. |
| HKDF-Extract(salt, IKM) | PRK = HMAC-Hash(salt, IKM). Turns any input into a fixed-size pseudorandom key. |
| HKDF-Expand-Label(secret, label, context, L) | HKDF-Expand with a structured info field: uint16 L ‖ uint8 len("tls13 "+label) ‖ "tls13 "+label ‖ uint8 len(context) ‖ context. The "tls13 " prefix is what keeps this key schedule from colliding with any other use of the same secret. |
| Derive-Secret(secret, label, messages) | Expand-Label(secret, label, SHA-256(messages), 32) — the transcript hash is the context, which binds each secret to the exact handshake so far. |
| Transcript | The concatenation of every handshake message so far (headers included). Its hash is what ties the keys to the actual conversation. |
| traffic key / IV | Derived per direction from the handshake or application traffic secret: Expand-Label(secret, "key", "", 16) and Expand-Label(secret, "iv", "", 12). |
| per-record nonce | IV XOR the record's 64-bit sequence number. Each key set has its own counter starting at 0; reusing a nonce with a given key would destroy GCM's confidentiality and integrity. |
| Finished | HMAC(finished_key, transcript so far) where finished_key = Expand-Label(traffic_secret, "finished", "", 32). It proves the sender derived the same keys from the same transcript. |
Glossary
Where the RFC 8448 values come from
RFC 8448 is the IETF's worked example of a complete TLS 1.3 handshake: it publishes the ephemeral private keys, every intermediate secret, each traffic key and IV, and the resulting encrypted records. This page's data file is generated from that RFC's own text by a script in the site's repository — nothing is retyped by hand — so the "RFC says" column below is the standard's number, not a copy of what this page computed.
Why the key schedule is shaped like this
Each stage is HKDF-Extract, so every phase's secrets are derived from a value that already mixes in the previous phase: early secret → (derived) → handshake secret → (derived) → master secret. The label at each Expand-Label call gives key separation: "c hs traffic" and "s hs traffic" from the same handshake secret are unrelated 32-byte values, as are "key" and "iv" from the same traffic secret. That is what lets a protocol derive many keys from one secret without one leaking the others, and it is the property TLS 1.2's PRF lacked in a provable sense.
Resumption, PSK and 0-RTT
After the handshake the server may send a NewSessionTicket. Its PSK is derived from the resumption secret and a per-ticket nonce, and the next connection can use it in place of a certificate — or together with (EC)DHE, which is what preserves forward secrecy. A resumed handshake is one round trip; 0-RTT data costs no round trip at all but is replayable, so it is safe only for requests that can be replayed.
CertificateVerify and authentication
The server signs the transcript with the key in its certificate, so the Finished MAC alone is not doing the authenticating — the signature is. That is why an attacker who can only split the Diffie-Hellman exchange (a man-in-the-middle, as on the Diffie–Hellman page) cannot impersonate a server here: they would have to produce a signature over a transcript containing their key share, which they cannot.
What this page does not do
It does not parse or validate the certificate chain, check names or dates, or implement the record layer's fragmentation, alerts, retransmission or anti-replay logic. The ClientHello and ServerHello here are the RFC's own bytes (or, in "fresh keys" mode, deliberately minimal ones), not a full offer of every cipher suite and extension a browser sends. The cryptography — key exchange, key schedule, MACs and record protection — is real and complete.