The Illustrated TLS 1.3 Connection


Server Handshake Keys Calc

The server now has the information to calculate the keys used to encrypt the rest of the handshake. It uses the following information in this calculation: First, the server finds the shared secret, which is the result of the key exchange that allows the client and server to agree on a number. The server multiplies the client's public key with the server's private key using the curve25519() algorithm. The 32-byte result is found to be:
df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624
I've provided a tool to perform this calculation:
$ cc -o curve25519-mult curve25519-mult.c
$ ./curve25519-mult server-ephemeral-private.key \ client-ephemeral-public.key | hexdump 0000000 df 4a 29 1b aa 1e b7 cf a6 93 4b 29 b4 74 ba ad
0000010 26 97 e2 9f 1f 92 0d cc 77 c8 a0 a0 88 44 76 24
We then calculate the SHA256 hash of all handshake messages to this point (ClientHello and ServerHello). The hash does not include the 5-byte "record" headers. This "hello_hash" is da75ce1139ac80dae4044da932350cf65c97ccc9e33f1e6f7d2d4b18b736ffd5.

We then feed the hash and the shared secret into a set of key derivation operations, designed to ensure the integrity of the handshake process and to protect against known and possible attacks:

early_secret = HKDF-Extract( salt=00, key=00...)
empty_hash = SHA256("")
derived_secret = HKDF-Expand-Label( key = early_secret, label = "derived", context = empty_hash, len = 32)
handshake_secret = HKDF-Extract( salt = derived_secret, key = shared_secret)
client_handshake_traffic_secret = HKDF-Expand-Label( key = handshake_secret, label = "c hs traffic", context = hello_hash, len = 32)
server_handshake_traffic_secret = HKDF-Expand-Label( key = handshake_secret, label = "s hs traffic", context = hello_hash, len = 32)
client_handshake_key = HKDF-Expand-Label( key = client_handshake_traffic_secret, label = "key", context = "", len = 16)
server_handshake_key = HKDF-Expand-Label( key = server_handshake_traffic_secret, label = "key", context = "", len = 16)
client_handshake_iv = HKDF-Expand-Label( key = client_handshake_traffic_secret, label = "iv", context = "", len = 12)
server_handshake_iv = HKDF-Expand-Label( key = server_handshake_traffic_secret, label = "iv", context = "", len = 12)
This has introduced two new cryptographic methods:

  • HKDF-Extract - given a salt and some bytes of key material create 256 bits (32 bytes) of new key material, with the input key material's entropy evenly distributed in the output.
  • HKDF-Expand-Label - given the inputs of key material, label, and context data, create a new key of the requested length.
I've created an HKDF tool to perform these operations on the command line.
$ hello_hash=da75ce1139ac80dae4044da932350cf65c97ccc9e33f1e6f7d2d4b18b736ffd5
$ shared_secret=df4a291baa1eb7cfa6934b29b474baad2697e29f1f920dcc77c8a0a088447624
$ zero_key=0000000000000000000000000000000000000000000000000000000000000000
$ early_secret=$(./hkdf extract 00 $zero_key)
$ empty_hash=$(openssl sha256 < /dev/null)
$ derived_secret=$(./hkdf expandlabel $early_secret "derived" $empty_hash 32)
$ handshake_secret=$(./hkdf extract $derived_secret $shared_secret)
$ csecret=$(./hkdf expandlabel $handshake_secret "c hs traffic" $hello_hash 32)
$ ssecret=$(./hkdf expandlabel $handshake_secret "s hs traffic" $hello_hash 32)
$ client_handshake_key=$(./hkdf expandlabel $csecret "key" "" 16)
$ server_handshake_key=$(./hkdf expandlabel $ssecret "key" "" 16)
$ client_handshake_iv=$(./hkdf expandlabel $csecret "iv" "" 12)
$ server_handshake_iv=$(./hkdf expandlabel $ssecret "iv" "" 12)
$ echo ckey: $client_handshake_key
$ echo skey: $server_handshake_key
$ echo civ: $client_handshake_iv
$ echo siv: $server_handshake_iv ckey: 7154f314e6be7dc008df2c832baa1d39
skey: 844780a7acad9f980fa25c114e43402a
civ: 71abc2cae4c699d47c600268
siv: 4c042ddc120a38d1417fc815
From this we get the following key data:
  • handshake secret: fb9fc80689b3a5d02c33243bf69a1b1b20705588a794304a6e7120155edf149a
  • client handshake traffic secret: ff0e5b965291c608c1e8cd267eefc0afcc5e98a2786373f0db47b04786d72aea.
  • server handshake traffic secret: a2067265e7f0652a923d5d72ab0467c46132eeb968b6a32d311c805868548814.
  • client handshake key: 7154f314e6be7dc008df2c832baa1d39
  • server handshake key: 844780a7acad9f980fa25c114e43402a
  • client handshake IV: 71abc2cae4c699d47c600268
  • server handshake IV: 4c042ddc120a38d1417fc815