Dragonblood : Analyzing the Dragonfly Handshake of WPA3 and EAP-pwd Mathy Vanhoef and Eyal Ronen Real World Crypto, New York, 10 January 2020.
Background: Wi-Fi Security › 1999: Wired Equivalent Privacy (WEP) Broken in 2001 [FMS01] › 2003: Wi-Fi Protected Access (WPA) › 2004: Wi-Fi Protected Access 2 (WPA2) Allows offline password brute-force KRACK and Kraken attack [VP][2017-8] 2
Background: Dragonfly in WPA3 and EAP-pwd = Password Authenticated Key Exchange (PAKE) Negotiate Provide mutual session key authentication Prevent offline dictionary attacks 3
Dragonfly Pick random 𝑠 𝐵 and 𝑛 𝐵 Pick random 𝑠 𝐶 and 𝑛 𝐶 𝑡 𝐵 = 𝑠 𝐵 + 𝑛 𝐵 mod 𝑟 𝑡 𝐶 = 𝑠 𝐶 + 𝑛 𝐶 mod 𝑟 𝐹 𝐵 = −𝑛 𝐵 ∙ 𝑄 𝐹 𝐶 = −𝑛 𝐶 ⋅ 𝑄 Convert password to group element P 4
Dragonfly Pick random 𝑠 𝐵 and 𝑛 𝐵 Pick random 𝑠 𝐶 and 𝑛 𝐶 𝑡 𝐵 = 𝑠 𝐵 + 𝑛 𝐵 mod 𝑟 𝑡 𝐶 = 𝑠 𝐶 + 𝑛 𝐶 mod 𝑟 𝐹 𝐵 = −𝑛 𝐵 ∙ 𝑄 𝐹 𝐶 = −𝑛 𝐶 ⋅ 𝑄 Commit( 𝑡 𝐵 , 𝐹 𝐵 ) Commit( 𝑡 𝐶 , 𝐹 𝐶 ) Verify 𝑡 𝐶 and 𝐹 𝐶 Verify 𝑡 𝐵 and 𝐹 𝐵 𝐿 = 𝑠 𝐵 ⋅ 𝑡 𝐶 ∙ 𝑄 + 𝐹 𝐶 𝐿 = 𝑠 𝐶 ⋅ 𝑡 𝐵 ∙ 𝑄 + 𝐹 𝐵 𝜆 = Hash 𝐿 𝜆 = Hash 𝐿 𝑢𝑠 = 𝑡 𝐵 , 𝐹 𝐵 , 𝑡 𝐶 , 𝐹 𝐶 𝑢𝑠 = 𝑡 𝐶 , 𝐹 𝐶 , 𝑡 𝐵 , 𝐹 𝐵 𝑑 𝐵 = HMAC(𝜆, 𝑢𝑠) 𝑑 𝐶 = HMAC(𝜆, 𝑢𝑠) 5
Dragonfly Pick random 𝑠 𝐵 and 𝑛 𝐵 Pick random 𝑠 𝐶 and 𝑛 𝐶 𝑡 𝐵 = 𝑠 𝐵 + 𝑛 𝐵 mod 𝑟 𝑡 𝐶 = 𝑠 𝐶 + 𝑛 𝐶 mod 𝑟 𝐹 𝐵 = −𝑛 𝐵 ∙ 𝑄 𝐹 𝐶 = −𝑛 𝐶 ⋅ 𝑄 Commit( 𝑡 𝐵 , 𝐹 𝐵 ) Negotiate shared key Commit( 𝑡 𝐶 , 𝐹 𝐶 ) Verify 𝑡 𝐶 and 𝐹 𝐶 Verify 𝑡 𝐵 and 𝐹 𝐵 𝐿 = 𝑠 𝐵 ⋅ 𝑡 𝐶 ∙ 𝑄 + 𝐹 𝐶 𝐿 = 𝑠 𝐶 ⋅ 𝑡 𝐵 ∙ 𝑄 + 𝐹 𝐵 𝜆 = Hash 𝐿 𝜆 = Hash 𝐿 𝑢𝑠 = 𝑡 𝐵 , 𝐹 𝐵 , 𝑡 𝐶 , 𝐹 𝐶 𝑢𝑠 = 𝑡 𝐶 , 𝐹 𝐶 , 𝑡 𝐵 , 𝐹 𝐵 𝑑 𝐵 = HMAC(𝜆, 𝑢𝑠) 𝑑 𝐶 = HMAC(𝜆, 𝑢𝑠) 6
Dragonfly Verify 𝑡 𝐶 and 𝐹 𝐶 Verify 𝑡 𝐵 and 𝐹 𝐵 𝐿 = 𝑠 𝐵 ⋅ 𝑡 𝐶 ∙ 𝑄 + 𝐹 𝐶 𝐿 = 𝑠 𝐶 ⋅ 𝑡 𝐵 ∙ 𝑄 + 𝐹 𝐵 𝜆 = Hash 𝐿 𝜆 = Hash 𝐿 𝑢𝑠 = 𝑡 𝐵 , 𝐹 𝐵 , 𝑡 𝐶 , 𝐹 𝐶 𝑢𝑠 = 𝑡 𝐶 , 𝐹 𝐶 , 𝑡 𝐵 , 𝐹 𝐵 𝑑 𝐵 = HMAC(𝜆, 𝑢𝑠) 𝑑 𝐶 = HMAC(𝜆, 𝑢𝑠) Confirm( 𝑑 𝐵 ) Confirm( 𝑑 𝐶 ) Confirm peer negotiated same key 7
Dragonfly Verify 𝑡 𝐶 and 𝐹 𝐶 Verify 𝑡 𝐵 and 𝐹 𝐵 𝐿 = 𝑠 𝐵 ⋅ 𝑡 𝐶 ∙ 𝑄 + 𝐹 𝐶 𝐿 = 𝑠 𝐶 ⋅ 𝑡 𝐵 ∙ 𝑄 + 𝐹 𝐵 𝜆 = Hash 𝐿 𝜆 = Hash 𝐿 𝑢𝑠 = 𝑡 𝐵 , 𝐹 𝐵 , 𝑡 𝐶 , 𝐹 𝐶 𝑢𝑠 = 𝑡 𝐶 , 𝐹 𝐶 , 𝑡 𝐵 , 𝐹 𝐵 How to derive P from a password? 𝑑 𝐵 = HMAC(𝜆, 𝑢𝑠) 𝑑 𝐶 = HMAC(𝜆, 𝑢𝑠) 1. MODP groups Confirm( 𝑑 𝐵 ) 2. Elliptic curves Confirm( 𝑑 𝐶 ) 8
Dragonfly Verify 𝑡 𝐶 and 𝐹 𝐶 Verify 𝑡 𝐵 and 𝐹 𝐵 𝐿 = 𝑠 𝐵 ⋅ 𝑡 𝐶 ∙ 𝑄 + 𝐹 𝐶 𝐿 = 𝑠 𝐶 ⋅ 𝑡 𝐵 ∙ 𝑄 + 𝐹 𝐵 𝜆 = Hash 𝐿 𝜆 = Hash 𝐿 𝑢𝑠 = 𝑡 𝐵 , 𝐹 𝐵 , 𝑡 𝐶 , 𝐹 𝐶 𝑢𝑠 = 𝑡 𝐶 , 𝐹 𝐶 , 𝑡 𝐵 , 𝐹 𝐵 How to derive P from a password? 𝑑 𝐵 = HMAC(𝜆, 𝑢𝑠) 𝑑 𝐶 = HMAC(𝜆, 𝑢𝑠) 1. MODP groups Confirm( 𝑑 𝐵 ) 2. Elliptic curves Confirm( 𝑑 𝐶 ) 9
Hash-to-curve: EAP-pwd for (counter = 1; counter < 40; counter++) x = hash(pw, addr1, addr2, counter) if x >= p: continue if square_root_exists(x) and not P: return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) 10
Hash-to-curve: EAP-pwd for (counter = 1; counter < 40; counter++) x = hash(pw, addr1, addr2, counter) if x >= p: continue if square_root_exists(x) and not P: return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) Half of x values aren’t on the curve 11
Hash-to-curve: EAP-pwd for (counter = 1; counter < 40; counter++) x = hash(pw, addr1, addr2, counter) if x >= p: continue if square_root_exists(x) and not P: return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) 12
Hash-to-curve: EAP-pwd for (counter = 1; counter < 40; counter++) x = hash(pw, addr1, addr2, counter) if x >= p: continue #iterations depends on password if square_root_exists(x) and not P: (and public MAC addresses) return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) 13
Hash-to-curve: EAP-pwd for (counter = 1; counter < 40; counter++) x = hash(pw, addr1, addr2, counter) if x >= p: continue #iterations depends on password if square_root_exists(x) and not P: (and public MAC addresses) return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) No timing leak countermeasures, despite warnings by IETF & CFRG! 14
Attacking Clients 15
Attacking Access Points 16
Leaked information: #iterations needed Client address addrA Measured 17
Leaked information: #iterations needed Client address addrA Measured Password 1 Password 2 Password 3 18
Leaked information: #iterations needed Client address addrA Measured Password 1 Password 2 Password 3 19
What information is leaked? for (counter = 1; counter < 40; counter++) x = hash(pw, addr1, addr2, counter) if x >= p: continue Spoof client address to obtain if square_root_exists(x) and not P: different execution & leak new data return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) 20
Leaked information: #iterations needed Client address addrA addrB Measured Password 1 Password 2 Password 3 21
Leaked information: #iterations needed Client address addrA addrB Measured Password 1 Password 2 Password 3 22
Leaked information: #iterations needed Client address addrA addrB addrC Measured Password 1 Password 2 Password 3 23
Leaked information: #iterations needed Client address addrA addrB addrC Measured Forms a signature of the password Password 1 Password 2 Need ~17 addresses to determine password in RockYou ( ~𝟐𝟏 𝟖 ) dump Password 3 24
Raspberry Pi 1 B+: differences are measurable 25
Raspberry Pi 1 B+: differences are measurable EAP-pwd client: ~30 measurements / address Using Crosby’s box test 26
Hash-to-curve: EAP-pwd for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: return (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) 27
Hash-to-curve: WPA3 for (counter = 1; counter < 40 ; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P : P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() WPA3: always do 40 return P loops & return first P 28
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) Blinded constant time pw = rand() square root test return P 29
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P Extra iterations based on random password 30
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue Truncate to size of prime p if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P 31
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) Brainpool: 𝑞 = 0xA9FB57DBA1EEA9BC… pw = rand() High chance that x >= p return P 32
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue = rejection sampling if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P 33
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P Code may be skipped 34
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P #Times skipped depends on password 35
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P #Times skipped depends on password & random password in extra itreations 36
Hash-to-curve: WPA3 for (counter = 1; counter < 40; counter++) x = hash(pw, counter, addr1, addr2) if x >= p: continue if square_root_exists(x) and not P: P = (x, 𝑦 3 + 𝑏𝑦 + 𝑐 ) pw = rand() return P Variance ~ when password element was found 37
Recommend
More recommend