Upgrade to Pro — share decks privately, control downloads, hide ads and more …

作って理解するWireGuard

Fadis
July 19, 2018

 作って理解するWireGuard

比較的最近登場したL3VPNの手法WireGuardがどのような物であるかを解説します
これは2018年7月21日に行われた 第14回 カーネル/VM探検隊の発表資料です。

Fadis

July 19, 2018
Tweet

More Decks by Fadis

Other Decks in Programming

Transcript

  1. NAOMASA MATSUBAYASHI
    ࡞ͬͯཧղ͢Δ
    WireGuard

    View Slide

  2. ͜͜ʹ8JSF(VBSEެࣜαΠτͷը૾ΛషΔ
    WireGuard®͸࠷ઌ୺ͷ҉߸Λ࢖ͬͯ࡞ΒΕͨۃΊͯγϯϓϧͳ͕Βߴ଎Ͱۙ୅తͳVPNͰ͢ɻ
    https://www.wireguard.com/
    ৽͍͠-71/ͷख๏
    -JOVYͱ͔Ͱ࢖͑Δ

    View Slide

  3. WireGuard®͸࠷ઌ୺ͷ҉߸Λ࢖ͬͯ࡞ΒΕͨۃΊͯγϯϓϧͳ͕Βߴ଎Ͱۙ୅తͳVPNͰ͢ɻ
    ຊମ StrongSwan OpenSSL ߹ܭ
    WireGuard 26,130 ෆཁ ෆཁ 26,130
    OpenVPN 111,612 ෆཁ 366,769 478,381
    SoftEarther 422,714 ෆཁ 366,769 789,483
    xl2tpd+IPSec 12,151 566,150 366,769 945,070
    xfrm+IPSec 32,925 566,150 366,769 965,844
    71/ͷ֤ख๏ͷ೥݄೔࣌఺ͷ
    ࠷৽ͷ҆ఆ൛ͷιʔείʔυͷߦ਺
    ܻҰͭҧ͏

    View Slide

  4. WireGuard®͸࠷ઌ୺ͷ҉߸Λ࢖ͬͯ࡞ΒΕͨۃΊͯγϯϓϧͳ͕Βߴ଎Ͱۙ୅తͳVPNͰ͢ɻ
    Curve25519ͷପԁۂઢDHʹΑΔೝূͱ伴ڞ༗
    ύʔϑΣΫτϑΥϫʔυηΩϡϦςΟΛ༗͢
    ରশ҉߸͸Chacha20-Poly1305
    BLAKE2sΛ࢖ͬͨHKDFʹΑΔରশ҉߸ͷ伴ੜ੒
    φ΢͍
    φ΢͍ φ΢͍
    φ΢͍
    φ΢͍
    φ΢͍

    View Slide

  5. ͜͜ʹ8JSF(VBSEͷ࿦จͷ
    1FSGPSNBODFͷਤΛషΔ
    WireGuard®͸࠷ઌ୺ͷ҉߸Λ࢖ͬͯ࡞ΒΕͨۃΊͯγϯϓϧͳ͕Βߴ଎Ͱۙ୅తͳVPNͰ͢ɻ
    Donenfeld, J., WireGuard: next generation kernel network tunnel. In: 24th Annual
    Network and Distributed System Security Symposium, NDSS 2017, San Diego,
    California, USA (2017) ΑΓҾ༻
    طଘͷख๏ͱൺֱͯ͠
    ߴ͍εϧʔϓοτ
    ௿͍ϨΠςϯγ
    Whitepaper: https://www.wireguard.com/papers/wireguard.pdf

    View Slide

  6. WireGuardΛ࢖ͬͯΈΑ͏

    View Slide

  7. $ wget -q https://git.zx2c4.com/WireGuard/snapshot/
    WireGuard-0.0.20180625.tar.xz
    $ tar xf WireGuard-0.0.20180625.tar.xz
    $ cd WireGuard-0.0.20180625/src/
    $ make

    LD [M] /usr/src/hoge/WireGuard-0.0.20180625/src/wireguard.o
    Building modules, stage 2.
    MODPOST 1 modules
    CC /usr/src/hoge/WireGuard-0.0.20180625/src/wireguard.mod.o
    LD [M] /usr/src/hoge/WireGuard-0.0.20180625/src/wireguard.ko

    LD /usr/src/hoge/WireGuard-0.0.20180625/src/tools/wg
    # make install
    ΠϯετʔϧΨΠυhttps://www.wireguard.com/install/

    View Slide

  8. LD [M] /usr/src/hoge/WireGuard-0.0.20180625/src/wireguard.o
    Building modules, stage 2.
    MODPOST 1 modules
    CC /usr/src/hoge/WireGuard-0.0.20180625/src/wireguard.mod.o
    LD [M] /usr/src/hoge/WireGuard-0.0.20180625/src/wireguard.ko

    LD /usr/src/hoge/WireGuard-0.0.20180625/src/tools/wg
    # make install
    WireGuardʹϢʔβۭؒσʔϞϯ͸ͳ͍
    શͯΧʔωϧۭؒͰॲཧ͞ΕΔ
    ΧʔωϧϞδϡʔϧ
    ΧʔωϧϞδϡʔϧʹioctl౤͛ͨΓ
    伴ϖΞͭͬͨ͘Γ͢ΔϢʔβۭؒπʔϧ

    View Slide

  9. WireGuardΛ࢖ͬͯΈΑ͏
    $ wg genkey >private.key
    $ wg pubkey public.key
    $ cat private.key
    uMJnQnuscHiWTtIpMoDwVtOkoGgs4UQMRZaScCYPM1A=
    $ cat public.key
    kdOAXmxE4XwwoO+QbXLcTSRMp+TXfW8SOgW69DRURS0=
    $ vim wireguard.conf
    $ cat wireguard.conf
    [Interface]
    PrivateKey = uMJnQnuscHiWTtIpMoDwVtOkoGgs4UQMRZaScCYPM1A=
    ListenPort = 51820
    [Peer]
    PublicKey = 3K0qbsP8IzGZaHmwAyxQ8z/gRla9rSbL17RoLQi6hAk=
    Endpoint = example.com:51820
    AllowedIPs = 192.168.2.2/32
    ൿີ伴ͱެ։伴Λ࡞Δ
    ର޲ͷϗετͷެ։伴
    ࣗ෼ͷൿີ伴
    ର޲ͷϗετͷΞυϨεͱϙʔτ
    ௨৴Λ଴ͪड͚Δϙʔτ

    View Slide

  10. WireGuardΛ࢖ͬͯΈΑ͏
    $ modprobe wireguard
    $ ip link add dev wg0 type wireguard
    $ ip address add dev wg0 192.168.2.1 peer 192.168.2.2
    $ wg setconf wg0 wireguard.conf
    $ ip link set up dev wg0
    ৽͍͠8JSF(VBSEσόΠεXHΛ࡞Δ
    ΞυϨεͱ伴Λ༩͑Δ
    σόΠεΛى͜͢
    ͜ͷઃఆΛVPNΛுΔ྆ଆͷϗετͰߦ͏

    View Slide

  11. $ ping -c 5 192.168.2.2
    PING 192.168.2.2 (192.168.2.2) 56(84) bytes of data.
    64 bytes from 192.168.2.2: icmp_seq=1 ttl=64 time=18.3 ms
    64 bytes from 192.168.2.2: icmp_seq=2 ttl=64 time=8.64 ms
    64 bytes from 192.168.2.2: icmp_seq=3 ttl=64 time=8.84 ms
    64 bytes from 192.168.2.2: icmp_seq=4 ttl=64 time=8.80 ms
    64 bytes from 192.168.2.2: icmp_seq=5 ttl=64 time=8.82 ms
    --- 192.168.2.2 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4007ms
    rtt min/avg/max/mdev = 8.644/10.698/18.378/3.841 ms
    VPN׬੒

    View Slide

  12. port 11194
    proto udp6
    dev tap0
    ca privnet/ca.crt
    cert privnet/server.crt
    key privnet/server.key
    dh privnet/dh.pem
    server-bridge 192.168.0.250 255.255.255.0 192.168.0.10
    192.168.0.249
    push "redirect-gateway def1”
    client-to-client
    keepalive 10 120
    user nobody/
    group nobody
    persist-key
    persist-tun
    status openvpn-status.log
    verb 3
    link-mtu 1500
    mssfix
    fragment 1280
    cipher AES-256-GCM
    ncp-ciphers AES-256-GCM
    tls-version-min 1.2
    tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-
    RSA-WITH-AES-256-GCM-SHA384
    reneg-sec 60
    [Interface]
    PrivateKey = uMJnQnuscHiWTtIpMoDwVtOkoGgs4UQMRZaScCYPM1A=
    ListenPort = 51820
    [Peer]
    PublicKey = 3K0qbsP8IzGZaHmwAyxQ8z/gRla9rSbL17RoLQi6hAk=
    Endpoint = example.com:51820
    AllowedIPs = 192.168.2.2/32
    ͳΜͯ؆୯ͳΜͰ͠ΐ͏
    Α͋͘ΔOpenVPNͷઃఆ WireGuardͷઃఆ

    View Slide

  13. ͦͷVPN͸ຊ౰ʹ҆શ͔

    View Slide

  14. ୈࡾऀ͕௨৴Λݟ͍ͯͨͱͯ͠΋
    ಺༰͕όϨͯ͸ͳΒͳ͍
    ҉߸Խ

    View Slide

  15. ϝοηʔδΛૹΔ૬ख͕ҙਤͨ͠૬खͰ͋ΔࣄΛ
    ֬ೝͰ͖ͳ͚Ε͹ͳΒͳ͍
    ೝূ
    "MJDF
    #PCʹͳΓ͢·͢
    ߈ܸऀ
    #PC

    View Slide

  16. ड͚औͬͨϝοηʔδ͕ҙਤͨ͠૬ख͔Βͷ
    ΋ͷͰ͋ΔࣄΛ֬ೝͰ͖ͳ͚Ε͹ͳΒͳ͍
    վ᜵ݕ஌
    "MJDF
    "MJDFʹͳΓ͢·͢
    ߈ܸऀ
    #PC

    View Slide

  17. ҉߸Խʹ࢖͏伴͸௨৴૬खҎ֎ʹόϨͳ͍Α͏ʹ
    ڞ༗͞Εͳ͚Ε͹ͳΒͳ͍
    ౪ௌऀʹݟ͑ͳ͍伴ڞ༗

    View Slide

  18. ௕ظؒಉ͡伴͕࢖ΘΕΔͱ伴͕όϨΔՄೳੑ͕ߴ͘ͳΔ
    ҉߸Խʹ࢖͏伴͸ఆظతʹมߋ͞Εͳ͚Ε͹ͳΒͳ͍
    伴ͷϩʔςʔγϣϯ
    ΋͔ͯ͠͠:

    View Slide

  19. ϗετͷূ໌ॻͷൿີ伴͕ޙ͔Β࿙Εͯ΋
    ௨৴Λه࿥͍ͯͨ͠ୈࡾऀʹ಺༰͕όϨͯ͸ͳΒͳ͍
    ύʔϑΣΫτϑΥϫʔυηΩϡϦςΟ
    ?
    ޙ೔

    View Slide

  20. 伴Λ஌Βͳ͍ୈࡾऀ͔ΒͷେྔͷΞΫηεʹΑͬͯ
    ༰қʹਖ਼نͷϢʔβ͕઀ଓͰ͖ͳ͍ঢ়ଶʹؕͬͯ͸ͳΒͳ͍
    DoS߈ܸ଱ੑ

    View Slide

  21. ͜Ε͸҆શͳͷ͔ͳ
    Ͱ͔͗ͯ͢
    Α͘Θ͔ΒΜ
    γϯϓϧͳख๏
    Ҏ্ͷػೳ͸੬ऑੑ͕ແ͍ࣄΛݕূ͠΍͍͢Α͏ʹ
    Ͱ͖Δ͚ͩ؆ܿͳํ๏Ͱ࣮ݱ͞Ε͍ͯΔࣄ͕๬·͍͠

    View Slide

  22. ҉߸Խʹ࢖͏伴͸௨৴૬खҎ֎ʹόϨͳ͍Α͏ʹ
    ڞ༗͞Εͳ͚Ε͹ͳΒͳ͍
    ϝοηʔδΛૹΔ૬ख͕ҙਤͨ͠૬खͰ͋ΔࣄΛ
    ֬ೝͰ͖ͳ͚Ε͹ͳΒͳ͍
    伴ڞ༗ʹ࢖ΘΕͨൿີ伴͕ޙ͔Β࿙Εͯ΋
    ௨৴Λه࿥͍ͯͨ͠ୈࡾऀʹ಺༰͕όϨͯ͸ͳΒͳ͍
    ͚ͩ͜͜ͳΒ੩తͳ伴Λ࢖͏Diffie-HellmanͰୡ੒Ͱ͖Δ
    ͚ͩ͜͜ͳΒҰ࣌తͳ伴Λ࢖͏Diffie-HellmanͰୡ੒Ͱ͖Δ
    1ͭͷ伴ϖΞͰ͸3ͭͷ৚݅શͯΛຬͨ͢ࣄ͕Ͱ͖ͳ͍

    View Slide

  23. ࢲ͸͜Μͳํ๏Ͱ
    伴ڞ༗͕Ͱ͖·͢
    ͜ͷํ๏Ͱ伴ڞ༗͠·͠ΐ͏
    伴ͷૉͰ͢
    伴ͷૉͰ͢
    ͋ͳ͕ͨຊ෺ͳΒ
    ͜ΕΛ෮߸Ͱ͖ΔഺͰ͢
    ͋ͳ͕ͨຊ෺ͳΒ
    ͜ΕΛ෮߸Ͱ͖ΔഺͰ͢
    ڞ௨伴Λ
    खʹೖΕͨ
    ڞ௨伴Λ
    खʹೖΕͨ
    IPSec IKE Phase1ͷϋϯυγΣΠΫ
    Ұ࣌తͳ伴Λ࢖͏
    ڞ௨伴ͱ
    ੩తͳ伴Λ࢖͏
    ࢖༻͢Δ
    ҉߸ٕज़ΛܾΊΔ

    View Slide

  24. ͋ͳ͕ͨຊ෺ͳΒ
    ͜ΕΛ෮߸Ͱ͖ΔഺͰ͢
    ੩తͳ伴Λ࢖͏
    ͜ΜͳઃఆͰ௨৴Ͱ͖·͢
    ͜ͷઃఆͰ௨৴͠·͠ΐ͏
    Phase1ͷ
    ڞ௨伴Λ࢖͏
    ڞ௨伴Λ
    खʹೖΕͨ
    ڞ௨伴Λ
    खʹೖΕͨ
    ͞ΒʹIKE Phase2Ͱ௨৴༻ͷڞ௨伴ͱ
    ௨৴ํ๏ͷબ୒͕ߦΘΕͯ
    Α͏΍͘ύέοτΛྲྀͤΔঢ়ଶʹͳΔ

    View Slide

  25. ͋ͳ͕ͨຊ෺ͳΒ
    ͜ΕΛ෮߸Ͱ͖ΔഺͰ͢
    ੩తͳ伴Λ࢖͏
    ͜ΜͳઃఆͰ௨৴Ͱ͖·͢
    ͜ͷઃఆͰ௨৴͠·͠ΐ͏
    Phase1ͷ
    ڞ௨伴Λ࢖͏
    ڞ௨伴Λ
    खʹೖΕͨ
    ڞ௨伴Λ
    खʹೖΕͨ
    ϋϯυγΣΠΫ͕௕͍ͷͰ
    ୹࣌ؒͰRekey͢Δ৔߹͸͜ͷ෦෼͔Β΍Γ௚͢

    View Slide

  26. Ҏ্ͷػೳ͸੬ऑੑ͕ແ͍ࣄΛݕূ͠΍͍͢Α͏ʹ
    Ͱ͖Δ͚ͩ؆ܿͳํ๏Ͱ࣮ݱ͞Ε͍ͯΔࣄ͕๬·͍͠
    ௕ظؒಉ͡伴͕࢖ΘΕΔͱ伴͕όϨΔՄೳੑ͕ߴ͘ͳΔ
    ҉߸Խʹ࢖͏伴͸ఆظతʹมߋ͞Εͳ͚Ε͹ͳΒͳ͍
    ͜ͷ2ͭΛಉ࣌ʹຬͨͨ͢Ίʹ͸
    ϋϯυγΣΠΫΛ୹ͯ͘͠
    ॳճͱ伴ͷϩʔςʔγϣϯͰηογϣϯ伴ΛಘΔखॱΛ
    ׬શʹಉ͡ʹ͍ͨ͠

    View Slide

  27. ୡ੒͠ͳ͚Ε͹ͳΒͳ͍΋ͷ
    ௨৴ํ๏ɺ࢖༻͢Δ҉߸ٕज़ͷܾఆͱ
    ੩త伴Diffie-HellmanʹΑΔ௨৴૬खͷೝূͱ
    Ұ࣌伴Diffie-HellmanʹΑΔηογϣϯ伴ͷੜ੒Λ
    1ԟ෮ͷ௨৴Ͱߦ͏

    View Slide

  28. ௨৴ํ๏ɺ࢖༻͢Δ҉߸ٕज़ͷܾఆͱ
    ੩త伴Diffie-HellmanʹΑΔ௨৴૬खͷೝূͱ
    Ұ࣌伴Diffie-HellmanʹΑΔηογϣϯ伴ͷੜ੒Λ
    1ԟ෮ͷ௨৴Ͱߦ͏
    ୡ੒͠ͳ͚Ε͹ͳΒͳ͍΋ͷ
    ࢖༻Ͱ͖Δ௨৴ํ๏ͱ҉߸ٕज़͕
    1छྨ͔͠ͳ͚Ε͹͜ͷ෦෼͸ෆཁ
    ͜ͷ෦෼ΛҰؾʹͰ͖Ε͹࣮ݱͰ͖Δ

    View Slide

  29. 1-RTTϋϯυγΣΠΫ΁ͷಓ

    View Slide

  30. ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    abc abc
    ͸ac=f(a,c)ʹରͯ͠a=g(ac,c)ͱͳΔؔ਺g͕཭ࢄର਺໰୊ʹͳΔΑ͏ͳؔ਺
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌
    ී௨ͷ੩త伴Diffie-Hellman伴ڞ༗
    ,%' ,%'

    View Slide

  31. ͸xc=f(x,c)ʹରͯ͠x=g(xc,c)ͱͳΔؔ਺g͕཭ࢄର਺໰୊ʹͳΔΑ͏ͳؔ਺
    ࣄલ
    ௨৴࣌
    ී௨ͷҰ࣌伴Diffie-Hellman伴ڞ༗
    ཚ਺x ࣄલʹܾΊͨૉ਺c ཚ਺y
    cx cy
    cxy cxy
    ,%' ,%'

    View Slide

  32. ୯७ʹ2ͭͷDiffie-HellmanΛߦ͏͚ͩͩͱ
    Ұ࣌伴Λѱҙ͋Δୈࡾऀʹॻ͖׵͑ΒΕΔ
    Aliceͷ੩త伴
    AliceͷҰ࣌伴
    Aliceͷ੩త伴
    ୈࡾऀͷҰ࣌伴
    Alice Bob
    ѱҙ͋Δୈࡾऀ

    View Slide

  33. Noise Protocol Framework
    ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'

    View Slide

  34. ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'
    ΦϨϯδͷ෦෼͸
    WireGuardΛઃఆ͢Δࡍʹ৯΂ͤͨ͞
    ϐΞͷެ։伴ʹ૬౰͢Δ
    ͭ·ΓVPNΛઃఆ͢Δஈ֊Ͱߦ͓ͬͯ͘෦෼
    Noise Protocol Framework

    View Slide

  35. ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'
    ੨ͷ෦෼͸௨৴Λ։࢝͢Δࡍʹߦ͏
    cxͱcyͷަ׵1౓͚ͩͳͷͰ1ԟ෮ͷ௨৴Ͱߦ͑Δ
    Noise Protocol Framework

    View Slide

  36. ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'
    2ͭͷ伴ϖΞ͔Β4ͭͷ஋͕ڞ༗͞ΕΔ
    abc=੩త伴Diffie-Hellmanʹ૬౰
    cxy=Ұ࣌伴Diffie-Hellmanʹ૬౰
    Noise Protocol Framework

    View Slide

  37. ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'
    ڵຯਂ͍ಇ͖Λ͢Δͷ͕bcx
    Noise Protocol Framework

    View Slide

  38. ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'
    ఆ਺bΛ͍࣋ͬͯͳ͍ͱbcxΛ࡞Δ͜ͱ͕Ͱ͖ͳ͍
    cxΛૹͬͯbcxΛབྷΊͨ伴Λ࡞ΕΔ΍ͭ͸ؒҧ͍ͳ͘bͷ࣋ͪओ
    Noise Protocol Framework

    View Slide

  39. Noise Protocol Framework
    ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b
    ఆ਺ac ఆ਺bc
    cx cy
    ূ໌ॻͱͯ͠ެ։
    ࣄલ
    ௨৴࣌ ཚ਺x ཚ਺y
    abc
    bcx
    acy cxy
    bcx
    cxy
    abc acy
    ,%' ,%'
    aͷओͱbͷओ͚͕ͩڞ༗Ͱ͖Δ஋
    ͨͩ͠aͱb͸ޙ͔ΒόϨΔՄೳੑ͕͋Δ
    xͷओͱyͷओ͚͕ͩڞ༗Ͱ͖Δ஋
    ͦΕ͕ҙਤͨ͠௨৴૬ख͔͸Θ͔Βͳ͍
    xͷओͱbͷओ͚͕ͩڞ༗Ͱ͖Δ஋
    yͷओͱaͷओ͚͕ͩڞ༗Ͱ͖Δ஋
    4ͭͷ஋શͯΛڞ༗Ͱ͖ΔͳΒ͹
    aͷओ=xͷओ ͔ͭ bͷओ=yͷओ

    View Slide

  40. "MJDF #PC
    ࠓAlice͕Bobʹରͯ͠
    WireGuardͷηογϣϯ։࢝ͷཁٻΛ౤͛Α͏ͱ͍ͯ͠Δͱ͢Δ
    ಧ͚͍ͨύέοτ͕͋Δ
    ηογϣϯΛ։͍࢝ͨ͠ͳ

    View Slide

  41. Alice͸
    cx ͱ bcx͔Β࡞ͬͨ伴Ͱ҉߸Խͨࣗ͠਎ͷެ։伴ac ΛBobʹૹ৴
    Bob͸
    bcxΛٻΊͯAlice͔ΒૹΒΕ͖ͯͨެ։伴acΛ෮߸͠
    Aliceͷ੩తެ։伴ͱ߹͏ࣄΛ֬ೝ͔ͯ͠Βabc acy cxyΛٻΊΔ
    cy ͱ 4ͭͷ஋͔Β࡞ͬͨ伴Ͱ҉߸Խۭͨ͠จࣈྻ ΛAliceʹૹ৴
    4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ
    Alice͸
    abc acy cxyΛٻΊΔ
    4ͭͷ஋ͰBob͔ΒૹΒΕ͖ۭͯͨจࣈྻΛ෮߸Ͱ͖ΔࣄΛ֬ೝ
    4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ

    View Slide

  42. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)

    View Slide

  43. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    ͜ͷϋϯυγΣΠΫཁٻʹର͢Δฦ౴΍
    ηογϣϯཱ֬ޙʹBob͔ΒૹΒΕͯ͘Δύέοτ͸
    ͜͜Ͱࢦఆͨ͠IDѼʹૹΒΕͯ͘Δ

    View Slide

  44. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Alice͕௨৴Λ։࢝͢Δͱ͖ʹ
    ཚ਺Λൿີ伴ͱͯ͠࡞ͬͨެ։伴
    Diffie-HellmanͰ௨৴ʹ৐Δ஋͸ୈࡾऀʹݟ͑ͯ΋ྑ͍ҝ
    ͜ͷ஋͸҉߸Խ͞ΕͣʹૹΒΕΔ

    View Slide

  45. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Bobͷ੩తެ։伴ͱAliceͷҰ࣌తൿີ伴Λֻ͚ͯ࡞ͬͨ伴(bcx)Ͱ
    Aliceͷ੩తެ։伴Λ҉߸Խͯ͠BobʹૹΔ

    View Slide

  46. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Aliceͷ੩తൿີ伴ͱBobͷ੩తެ։伴Λֻ͚ͯ࡞ͬͨ伴Ͱ
    λΠϜελϯϓΛ҉߸Խͯ͠BobʹૹΔ
    Bob͸ૹΒΕ͖ͯͨཁٻͷλΠϜελϯϓ͕
    աڈʹAlice͔Βड͚औͬͨࣄ͕͋ΔλΠϜελϯϓҎԼͷ৔߹
    ཁٻΛແࢹ͢Δ
    (ϋϯυγΣΠΫ࣌ͷϦϓϨΠ߈ܸͷճආ)
    λΠϜελϯϓ͸୯ௐ૿Ճ͍ͯ͠Ε͹ྑ͘
    ਖ਼֬ͳ࣌ؒΛද͍ͯ͠Δඞཁ͸ͳ͍

    View Slide

  47. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    WireGuardʹରͯ͠ෛՙΛ͔͚Δछྨͷ߈ܸΛ
    ճආ͢ΔͨΊͷ΋ͷ
    ৄࡉ͸ޙड़

    View Slide

  48. C := HASH( “Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s" );
    H := HASH( C ∥ "WireGuard v1 zx2c4 [email protected]" );
    H := HASH( H ∥ Bobͷ੩తެ։伴 );
    AliceͷҰ࣌తൿີ伴ɺҰ࣌తެ։伴ͷϖΞΛ࡞੒;
    C := KDF( C, AliceͷҰ࣌తެ։伴 );
    H := HASH( H ∥ AliceͷҰ࣌తެ։伴 );
    ( C, AEADͷ伴 ) := KDF( C, DH( AliceͷҰ࣌తൿີ伴, Bobͷ੩తެ։伴 ));
    ҉߸Խ͞ΕͨAliceͷ੩తެ։伴 := AEAD_ENC( AEADͷ伴, 0, Aliceͷ੩తެ։伴, H );
    H := HASH( H ∥ ҉߸Խ͞ΕͨAliceͷ੩తެ։伴 );
    ( C, AEADͷ伴 ) := KDF( C, DH( Aliceͷ੩తൿີ伴, Bobͷ੩తެ։伴 ) );
    ҉߸Խ͞Εͨݱࡏ࣌ࠁ := AEAD_ENC( AEADͷ伴, 0, ݱࡏ࣌ࠁ, H );
    H := HASH( H ∥ ҉߸Խ͞Εͨݱࡏ࣌ࠁ );
    InitiatorHello(
    ++ηογϣϯID, AliceͷҰ࣌తެ։伴, ҉߸Խͨ͠Aliceͷ੩తެ։伴, ҉߸Խ͞Εͨݱࡏ࣌ࠁ
    );
    bcx
    abc
    Alice͕InitiatorHelloΛ࡞Δखॱ

    View Slide

  49. C := HASH( “Noise_IKpsk2_25519_ChaChaPoly_BLAKE2s" );
    H := HASH( C ∥ "WireGuard v1 zx2c4 [email protected]" );
    H := HASH( H ∥ Bobͷ੩తެ։伴 );
    C := KDF( C, ૹΒΕ͖ͯͨҰ࣌తެ։伴 );
    H := HASH( H ∥ ૹΒΕ͖ͯͨҰ࣌తެ։伴 );
    ( C, AEADͷ伴 ) := KDF( C, DH( Bobͷ੩తൿີ伴, ૹΒΕ͖ͯͨҰ࣌తެ։伴 ));
    Aliceͷ੩తެ։伴 := AEAD_DEC( AEADͷ伴, 0, ૹΒΕ͖ͯͨ҉߸Խ͞Εͨ੩తެ։伴, H );
    Aliceͷ੩తެ։伴͕Peerͷઃఆʹଘࡏ͢ΔࣄΛ֬ೝ;
    H := HASH( H ∥ ૹΒΕ͖ͯͨ҉߸Խ͞Εͨ੩తެ։伴 );
    ( C, AEADͷ伴 ) := KDF( C, DH( Bobͷ੩తൿີ伴, Aliceͷ੩తެ։伴 ) );
    ݱࡏ࣌ࠁ := AEAD_DEC( AEADͷ伴, 0, ҉߸Խ͞Εͨݱࡏ࣌ࠁ, H );
    ݱࡏ࣌ࠁ͕աڈʹAlice͔Βड͚औͬͨݱࡏ࣌ࠁͷ࠷େ஋ΑΓେ͖͍ࣄΛ֬ೝ;
    H := HASH( H ∥ ҉߸Խ͞Εͨݱࡏ࣌ࠁ );
    bcx
    abc
    InitiatorHelloΛड͚औͬͨBob͕CͱHΛಉظ͢Δखॱ

    View Slide

  50. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)

    View Slide

  51. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    ηογϣϯཱ֬ޙʹAlice͔ΒૹΒΕͯ͘Δύέοτ͸
    ͜͜Ͱࢦఆͨ͠IDѼʹૹΒΕͯ͘Δ

    View Slide

  52. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    ͜ͷϨεϙϯεΛड͚औͬͨAlice͸
    ͜ͷ஋ΛݟΔࣄͰͲͷInitiator Helloʹର͢Δ
    ฦ౴͕ฦ͖ͬͯͨͷ͔ΛࣝผͰ͖Δ

    View Slide

  53. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Bob͕Alice͔ΒInitiator HelloΛड͚औͬͨͱ͖ʹ
    ཚ਺Λൿີ伴ͱͯ͠࡞ͬͨެ։伴
    Diffie-HellmanͰ௨৴ʹ৐Δ஋͸ୈࡾऀʹݟ͑ͯ΋ྑ͍ҝ
    ͜ͷ஋͸҉߸Խ͞ΕͣʹૹΒΕΔ

    View Slide

  54. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Initiator helloΛड͚औͬͨ࣌఺ͰBob͸ҎԼͷ伴Λ஌͍ͬͯΔ
    Aliceͷ੩తެ։伴(ac) AliceͷҰ࣌తެ։伴(cx)
    Bobͷ੩తൿີ伴(b) BobͷҰ࣌తൿີ伴(y)
    ͜ΕΒ4ͭͷ஋Ͱ࡞ͬͨ伴ͰۭจࣈྻΛ҉߸Խͯ͠BobʹૹΔ
    ͜ΕΒͷ伴Λ࢖ͬͯ4ͭͷ஋
    abc acy bcx cxy
    ΛٻΊΔ͜ͱ͕Ͱ͖Δ

    View Slide

  55. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Responder helloΛड͚औͬͨ࣌఺ͰAlice͸ҎԼͷ伴Λ஌͍ͬͯΔ
    Bobͷ੩తެ։伴(bc) BobͷҰ࣌తެ։伴(cy)
    Aliceͷ੩తൿີ伴(a) AliceͷҰ࣌తൿີ伴(x)
    Chacha20-Poly1305͸ೝূ෇͖҉߸ͳͷͰฏจ͕ۭจࣈྻͰ΋
    伴͕Ұக͠ͳ͍ͱ෮߸͸ࣦഊ͢Δ
    ͜ΕΒͷ伴Λ࢖ͬͯ4ͭͷ஋
    abc acy bcx cxy
    ΛٻΊΔ͜ͱ͕Ͱ͖Δ

    View Slide

  56. Responder Hello
    0x02 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    ૹ৴ऀID (4όΠτ)
    Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋
    BobͷҰ࣌తެ։伴 (cy) (32όΠτ)
    ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    WireGuardʹରͯ͠ෛՙΛ͔͚Δछྨͷ߈ܸΛ
    ճආ͢ΔͨΊͷ΋ͷ
    ৄࡉ͸ޙड़

    View Slide

  57. BobͷҰ࣌తൿີ伴ɺҰ࣌తެ։伴ͷϖΞΛ࡞੒;
    C := KDF( C, BobͷҰ࣌తެ։伴 );
    H := HASH( H ∥ BobͷҰ࣌తެ։伴 );
    C := KDF( C, DH( BobͷҰ࣌తൿີ伴, AliceͷҰ࣌ެ։伴 ));
    C := KDF( C, DH( BobͷҰ࣌తൿີ伴, Aliceͷ੩తެ։伴 ));
    ( C, t, AEADͷ伴 ) := KDF( C, PSK );
    H := HASH( H ∥ t );
    ҉߸Խ͞Εۭͨจࣈྻ := AEAD_ENC( AEADͷ伴, 0, "", H );
    H := HASH( H ∥ ҉߸Խ͞Εۭͨจࣈྻ );
    ResponderHello(
    ++ηογϣϯID, BobͷҰ࣌తެ։伴, ҉߸Խۭͨ͠จࣈྻ
    );
    cxy
    acy
    Bob͕ResponderHelloΛ࡞Δखॱ
    ࣄલʹڞ༗ͨ͠ύεϫʔυ͕͋Δ৔߹
    ͜͜ʹಥͬࠐΉ

    View Slide

  58. C := KDF( C, BobͷҰ࣌తެ։伴 );
    H := HASH( H ∥ BobͷҰ࣌తެ։伴 );
    C := KDF( C, DH( AliceͷҰ࣌తൿີ伴, BobͷҰ࣌ެ։伴 ));
    C := KDF( C, DH( Aliceͷ੩తൿີ伴, BobͷҰ࣌ެ։伴 ));
    ( C, t, AEADͷ伴 ) := KDF( C, PSK );
    H := HASH( H ∥ t );
    ҉߸Խ͞Εۭͨจࣈྻ := AEAD_DEC( AEADͷ伴, 0, ૹΒΕ͖ͯͨ҉߸Խ͞Εۭͨจࣈྻ, H );
    H := HASH( H ∥ ҉߸Խ͞Εۭͨจࣈྻ );
    cxy
    acy
    ResponderHelloΛड͚औͬͨBob͕CͱHΛಉظ͢Δखॱ
    ͜ͷ࣌఺ͰAliceͱBobͷC͸ಉ͡஋ʹͳΔ
    ࣄલʹڞ༗ͨ͠ύεϫʔυ͕͋Δ৔߹
    ͜͜ʹಥͬࠐΉ
    ( Alice͕ύέοτͷૹ৴ʹ࢖͏伴, Bob͕ύέοτͷૹ৴ʹ࢖͏伴 ) = KDF( C, "" );
    ͋ͱ͸C͔Βύέοτͷ҉߸Խʹ࢖͏伴Λ࡞Δ

    View Slide

  59. ύέοτΛૹΖ͏

    View Slide

  60. Transport Data
    0x04 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋
    Χ΢ϯλ (8όΠτ)
    ಉҰηογϣϯͰύέοτΛ1ݸૹ৴͢Δͨͼʹ1ͮͭ૿͍͑ͯ͘஋
    ύέοτΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (҉߸Խલͷύέοτ௕+16όΠτ)

    View Slide

  61. Transport Data
    0x04 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋
    Χ΢ϯλ (8όΠτ)
    ಉҰηογϣϯͰύέοτΛ1ݸૹ৴͢Δͨͼʹ1ͮͭ૿͍͑ͯ͘஋
    ύέοτΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (҉߸Խલͷύέοτ௕+16όΠτ)
    ϋϯυγΣΠΫ࣌ʹ૬खʹૹͬͨηογϣϯΛࣝผ͢Δ஋
    ड৴ଆ͸͜ͷ஋Λݟͯ
    Ͳͷڞ༗伴Λ࢖ͬͯ෮߸͢Ε͹ྑ͍͔Λ஌Δ

    View Slide

  62. Transport Data
    0x04 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋
    Χ΢ϯλ (8όΠτ)
    ಉҰηογϣϯͰύέοτΛ1ݸૹ৴͢Δͨͼʹ1ͮͭ૿͍͑ͯ͘஋
    ύέοτΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (҉߸Խલͷύέοτ௕+16όΠτ)
    ύέοτΛ
    Chacha20-Poly1305Ͱ҉߸Խ͢Δࡍʹ࢖ͬͨΧ΢ϯλͷ஋

    View Slide

  63. Transport Data
    0x04 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋
    Χ΢ϯλ (8όΠτ)
    ಉҰηογϣϯͰύέοτΛ1ݸૹ৴͢Δͨͼʹ1ͮͭ૿͍͑ͯ͘஋
    ύέοτΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (҉߸Խલͷύέοτ௕+16όΠτ)
    Chacha20-Poly1305Ͱ҉߸Խ͞Εͨύέοτຊମ
    WireGuardͷMTU͸Transport Dataͷύέοτͷશ௕͕
    ҉߸Խ͞ΕͨύέοτΛૹΔ௨৴࿏ͷMTUΛ௒͑ͳ͍஋ʹ͢Δ

    View Slide

  64. ύέοτ௕͕ฏจͷঢ়ଶͰ16όΠτͷ੔਺ഒʹͳ͍ͬͯͳ͍৔߹
    ύσΟϯάΛ௥Ճͯ͠16όΠτͷ੔਺ഒʹ͢Δ
    ݩͷύέοτͷ௕͕͞Θ͔ΒΜ!
    4500 001f c6a1 0000 4001 2ce9 c0a8 0301 c0a8 0302 0000 9c37 61c2 0005 0001 02 00 0000 0000
    +
    ҉߸Խ
    237a a852 4cce a5a5 5dcc b2ee 0f82 1abc 4a02 5301 2551 56fc 7b7a e660 40a7 178b d460 5aff…
    ෮߸
    4500 001f c6a1 0000 4001 2ce9 c0a8 0301 c0a8 0302 0000 9c37 61c2 0005 0001 0200 0000 0000
    TransportDataʹ͸ݩͷύέοτͷ௕͞͸ॻ͔Ε͍ͯͳ͍

    View Slide

  65. 4500 001f c6a1 0000 4001 2ce9 c0a8 0301 c0a8 0302 0000 9c37 61c2 0005 0001 02 00 0000 0000
    +
    ҉߸Խ
    237a a852 4cce a5a5 5dcc b2ee 0f82 1abc 4a02 5301 2551 56fc 7b7a e660 40a7 178b d460 5aff…
    ෮߸
    4500 001f c6a1 0000 4001 2ce9 c0a8 0301 c0a8 0302 0000 9c37 61c2 0005 0001 0200 0000 0000
    4500 001f
    c6a1 0000
    4001 2ce9
    c0a8 0301
    c0a8 0302
    ෮߸ͨ͠ύέοτͷઌ಄ʹ͋Δͷ͸*1ϔομ
    *1ϔομͷόΠτ໨ʹ͋Δͷ͸
    ύέοτͷશ௕
    8JSF(VBSE͸ΧϓηϧԽͨ͠ύέοτͷத͔Β
    ύέοτ௕ΛऔΓग़ͯ͠ύσΟϯάΛ෼཭͢Δ

    View Slide

  66. 伴Λϩʔςʔτ͠Α͏

    View Slide

  67. "MJDF #PC
    *OJUJBUPS
    )FMMP 3FTQPOEFS
    )FMMP
    5SBOTQPSU
    %BUB
    5SBOTQPSU
    %BUB
    5SBOTQPSU
    %BUB
    *OJUJBUPS
    )FMMP 3FTQPOEFS
    )FMMP
    Alice͸120ඵຖʹInitiatorHelloΛ΍Γ௚͢

    View Slide

  68. "MJDF #PC
    *OJUJBUPS
    )FMMP 3FTQPOEFS
    )FMMP
    5SBOTQPSU
    %BUB
    5SBOTQPSU
    %BUB
    5SBOTQPSU
    %BUB
    5SBOTQPSU
    %BUB
    *OJUJBUPS
    )FMMP
    3FTQPOEFS
    )FMMP
    5SBOTQPSU
    %BUB 180ඵܦաͨ͠ηογϣϯ伴͸ഁغ͢Δ
    ৽͍͠InitiatorHelloͷޙ΋1ͭલͷ伴͕60ඵ΄Ͳੜ͖͍ͯΔͷͰ
    伴ڞ༗ͷ׬ྃΛ଴ͨͣʹσʔλΛૹΓଓ͚Δ͜ͱ͕Ͱ͖Δ

    View Slide

  69. ϦϓϨΠ߈ܸʹඋ͑Δ

    View Slide

  70. "MJDF #PC
    ͋
    ͋
    ѱҙ͋Δୈࡾऀ͕Alice͕ૹͬͨύέοτΛ
    ͦͷ··BobʹૹΔͱBob͸ͦΕΛ෮߸Ͱ͖ͯ͠·͏
    "MJDFʹͳΓ͢·͢
    ߈ܸऀ
    ͋͋


    View Slide

  71. "MJDF #PC
    ͋
    ͋
    ͜ΕΛ๷͙ʹ͸աڈʹड͚औͬͨࣄ͕͋ΔΧ΢ϯλͷ
    ࠷େ஋ΛԼճΔΧ΢ϯλͷϝοηʔδΛແࢹ͢Ε͹ྑ͍
    "MJDFʹͳΓ͢·͢
    ߈ܸऀ
    ͋


    1ͷύέοτ͸
    ΋͏ड͚औ͔ͬͨΒ
    ͬͪ͜͸ِ෺͔
    ͕

    View Slide

  72. "MJDF #PC
    ͋
    ͍
    ͏
    ͑
    ͓
    ͋
    ͏
    ͓
    ͍

    WireGuardͷϝοηʔδ͸UDPͰૹΒΕΔҝ
    ϝοηʔδ͸ॱং͕มΘͬͨΓແ͘ͳͬͨΓ͢Δ








    ͜ͷύέοτ͕
    ٘ਜ਼ʹͳΔ

    View Slide

  73. RFC6479
    IPsec Anti-Replay Algorithm without Bit Shifting
    IPSec΋ಉ͡໰୊Λ๊͍͑ͯΔҝ
    ͜͏ͨ͠߈ܸΛճආ͢Δҝͷ֦ு͕RFCʹͳ͍ͬͯΔ
    WireGuard΋ಉ͡ํ๏ͰϦϓϨΠ߈ܸΛճආ͢Δ

    View Slide

  74. RFC6479
    IPsec Anti-Replay Algorithm without Bit Shifting
    ࡁ ࡁ ະ ະ ࡁ ະ ະ ະ ࡁ ະ ະ ະ ະ ະ ະ ະ

    ط஌ͷ࠷৽
    ϦϯάόοϑΝΛ࢖ͬͯ
    ड͚औͬͨ͜ͱ͕͋ΔΧ΢ϯλͷ஋ͷ࠷େ஋पลͷ
    ஋ͷड͚औΓঢ়گΛ͓֮͑ͯ͘
    গʑॱ൪͕ೖΕସΘͬͯಧ͍ͯ΋
    ॏෳ͢Δύέοτ͚ͩΛ஄͘͜ͱ͕Ͱ͖Δ

    View Slide

  75. RFC6479
    IPsec Anti-Replay Algorithm without Bit Shifting
    ར఺
    ड͚औͬͨશͯͷύέοτͷΧ΢ϯλΛ͓֮͑ͯ͘͜ͱͳ͘
    ॱ൪͕ೖΕସΘΔՄೳੑ͕͋Δύέοτͷྻ͔Β
    ॏෳ͢ΔύέοτΛݟ͚ͭग़͢͜ͱ͕Ͱ͖Δ
    ܽ఺
    ύέοτͷॱ൪͕߽շʹೖΕସΘ͍ͬͯΔͱ
    ࣮ࡍʹ͸ॏෳ͕ͳ͔ͬͨͱͯ͠΋
    ड͚औΓΛڋ൱͞ΕΔύέοτ͕ੜ͡Δ

    View Slide

  76. DoS߈ܸΛ͔Θͤ

    View Slide

  77. Alice͸
    cx ͱ bcx͔Β࡞ͬͨ伴Ͱ҉߸Խͨࣗ͠਎ͷެ։伴 ΛBobʹૹ৴
    Bob͸
    bcxΛٻΊͯAlice͔ΒૹΒΕ͖ͯͨެ։伴Λ෮߸͠
    Aliceͷ੩తެ։伴ͱ߹͏ࣄΛ֬ೝ͔ͯ͠Βabc acy cxyΛٻΊΔ
    cy ͱ 4ͭͷ஋͔Β࡞ͬͨ伴Ͱ҉߸Խۭͨ͠จࣈྻ ΛAliceʹૹ৴
    4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ
    Alice͸
    abc acy cxyΛٻΊΔ
    4ͭͷ஋ͰBob͔ΒૹΒΕ͖ۭͯͨจࣈྻΛ෮߸Ͱ͖ΔࣄΛ֬ೝ
    4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ

    View Slide

  78. Alice͸
    cx ͱ bcx͔Β࡞ͬͨ伴Ͱ҉߸Խͨࣗ͠਎ͷެ։伴 ΛBobʹૹ৴
    Bob͸
    bcxΛٻΊͯAlice͔ΒૹΒΕ͖ͯͨެ։伴Λ෮߸͠
    Aliceͷ੩తެ։伴ͱ߹͏ࣄΛ֬ೝ͔ͯ͠Βabc acy cxyΛٻΊΔ
    cy ͱ 4ͭͷ஋͔Β࡞ͬͨ伴Ͱ҉߸Խۭͨ͠จࣈྻ ΛAliceʹૹ৴
    4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ
    Alice͸
    abc acy cxyΛٻΊΔ
    4ͭͷ஋ͰBob͔ΒૹΒΕ͖ۭͯͨจࣈྻΛ෮߸Ͱ͖ΔࣄΛ֬ೝ
    4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ
    ௨৴૬ख͕Կऀ͔Λ൑அ͢ΔҝʹbͱcxΛֻ͚Δඞཁ͕͋Δ
    Curve25519ͷੵ͸҉߸Ͱ࢖ΘΕΔପԁۂઢͷதͰ͸଎͍ํ͕ͩ
    ͦΕͰ΋InitiatorHelloΛେྔʹૹΒΕΔͱड৴ଆͷCPU͕΋ͨͳ͍

    View Slide

  79. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    Initiator HelloͱResponderHelloͷmac1ʹ
    mac1ΑΓલͷ಺༰ͷ伴෇͖ϋογϡΛ͚ͭΔ
    mac1 = MAC( HASH( "mac1----" ∥ ௨৴૬खͷ੩తެ։伴 ), mac1ΑΓલͷ௨৴಺༰ );
    ϋογϡͷ伴ʹ͸௨৴૬खͷ੩తެ։伴Λ࢖͏
    ੩తެ։伴͸VPNͷઃఆ࣌ʹୈࡾऀʹ࿙ΕΔՄೳੑ͕͋Δ͕
    ͦͷ͔࣌Βͣͬͱݟ͍ͯͨୈࡾऀҎ֎͸ਖ਼͍͠mac1Λ࡞Εͳ͍

    View Slide

  80. Cookie Reply
    0x03 (1όΠτ)
    Reserved (3όΠτ)
    ड৴ऀID (4όΠτ)
    ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋
    nonce (24όΠτ)
    cookieͷ҉߸Խʹ࢖ͬͨnonceͷ஋
    cookieΛXChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (16όΠτ+16όΠτ)
    ߴෛՙͳ࣌ʹInitiatorHelloΛड͚औͬͨBob͸
    AliceʹResponderHelloͷ୅ΘΓʹCookieReplyΛ౤͛Δ

    View Slide

  81. cookie = MAC( 2෼ຖʹมԽ͢Δཚ਺, InitiatorHelloͷૹ৴ݩIPΞυϨεͱϙʔτ );
    nonce = 24όΠτͷཚ਺;
    ҉߸Խ͞Εͨcookie = XAEAD_ENC(
    HASH( “cookie--" ∥ ௨৴૬खͷ੩తެ։伴 ),
    nonce, cookie, InitiatorHelloͷmac1
    );
    ૹ৴ݩIPΞυϨεͱϙʔτ͔ΒcookieΛ࡞Δ
    cookie͸MACΛ௨͢ҝड͚औͬͨଆͰվ᜵͸Ͱ͖ͳ͍
    cookieͷ҉߸Խʹ࢖ΘΕΔ੩తެ։伴ɺnonceɺmac1͸
    ͍ͣΕ΋௨৴Λ౪ௌ͍ͯ͠Δୈࡾऀʹݟ͑Δҝ
    ͜ͷ҉߸Խʹ͸cookieΛӅ͢ྗ͸ͳ͍͕
    ಉҰͷInitiatorHelloʹରͯ͠Cookie Reply͕ෳ਺ඈΜͰ͍Δঢ়گͷ
    ݕग़ΛՄೳʹ͢Δ໾ׂ͕͋Δ(Cookie ReplyͷϦϓϨΠ߈ܸͷճආ)

    View Slide

  82. Initiator Hello
    0x01 (1όΠτ)
    Reserved (3όΠτ)
    ૹ৴ऀID (4όΠτ)
    Alice͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ
    AliceͷҰ࣌తެ։伴 (cx) (32όΠτ)
    Aliceͷ੩తެ։伴ΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (32όΠτ+16όΠτ)
    TAI64NͰද͞Εͨݱࡏ࣌ࠁΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ
    (12όΠτ+16όΠτ)
    mac1 (16όΠτ)
    mac2 (16όΠτ)
    mac2 = MAC( 2෼Ҏ಺ʹड͚औͬͨcookie, mac2ΑΓલͷ௨৴಺༰ );
    InitiatorHello࣌ɺ2෼Ҏ಺ʹड͚औͬͨcookie͕͋Δ৔߹͸
    mac2ΑΓલͷ௨৴಺༰ͷ伴෇͖ϋογϡΛ͚ͭΔ

    View Slide

  83. ૹΒΕ͖ͯͨmac2ͱखݩͰܭࢉͨ͠mac2͕߹Θͳ͍
    Մೳੑ1:cookieͷݩʹͳΔཚ਺͕੾ΓସΘΔ͘Β͍͕࣌ؒܦաͨ͠
    Մೳੑ2:௨৴૬ख͸ਖ਼௚ͳୈࡾऀͰ͋Δ
    Մೳੑ1:௨৴૬ख͸ຊ෺Ͱ͋Δ
    Մೳੑ2:௨৴૬ख͸ιʔεΞυϨεΛ࠮শ͢ΔୈࡾऀͰ͋Δ
    ૹΒΕ͖ͯͨmac2ͱखݩͰܭࢉͨ͠mac2͕߹͏
    ΋͏Ұ౓cookie reply
    ͍ͣΕʹͯ͠΋ಛఆͷιʔεΞυϨεʹͳ͍ͬͯΔҝ
    IPϕʔεͷଳҬ੍ݶΛ͔͚ͯ
    InitiatorHelloͷ಺༰ͷνΣοΫʹਐΉ

    View Slide

  84. ࣮૷ͯ͠ΈΑ͏
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  85. ΦϦδφϧͷWireGuard͸ΧʔωϧۭؒͰ࣮૷͞Ε͍ͯΔ͕
    ҉߸ͷ࣮૷͕ἧ͍ͬͯΔϢʔβۭؒͷํ͕࣮૷͢Δͷ͸ָ
    Curve25519ͷ৐ࢉ
    BLAKE2s
    IETF Chacha20-Poly1305
    XChacha20-Poly1305
    ҉߸࿦తٖࣅཚ਺ੜ੒ث libsodiumΛ࢖༻
    libsodiumΛ࢖༻
    Crypto++Λ࢖༻
    libsodiumΛ࢖༻
    libsodiumΛ࢖༻
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  86. template< typename Out, typename CookieType >
    void initiator_hello_phase1( kx_state &stat, Out &out, const wg_key_type &self_static_private, const wg_key_type
    &self_static_public, const wg_key_type &remote_static_public, uint32_t self_spi, const CookieType &cookie ) {
    wg_key_type kdf_key;
    wg_key_type aead_key;
    wg_key_type mac_key;
    wg_tai64n_type self_timestamp;
    dh_generate( stat.self_ephemeral_private, stat.self_ephemeral_public );
    get_initial_chain_key( stat.chain_key );
    get_initial_hash_key( stat.hash_key, stat.chain_key );
    kdf( stat.chain_key ).update( stat.self_ephemeral_public ).get( stat.chain_key );
    hash().update( stat.hash_key, remote_static_public ).get( stat.hash_key );
    hash().update( stat.hash_key, stat.self_ephemeral_public ).get( stat.hash_key );
    dh( kdf_key, stat.self_ephemeral_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    out.resize( wg_kx1_len, 0u );
    auto encrypted_static = make_svv( out.data(), wg_kx1_encrypted_static_offset, wg_encrypted_static_len );
    aead_enc( encrypted_static, aead_key, 0ull, self_static_public, stat.hash_key );
    hash().update( stat.hash_key, encrypted_static ).get( stat.hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    timestamp( std::back_inserter( self_timestamp ) );
    auto encrypted_timestamp = make_svv( out.data(), wg_kx1_encrypted_tai64n_offset, wg_encrypted_tai64n_len );
    aead_enc( encrypted_timestamp, aead_key, 0ull, self_timestamp, stat.hash_key );
    hash().update( stat.hash_key, encrypted_timestamp ).get( stat.hash_key );
    out[ 0 ] = 0x01;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx1_self_spi_offset ), karma::little_dword, self_spi );
    InitiatorHelloΛ࡞Δ
    Ұ࣌伴ϖΞ(xͱcx)Λ࡞ͬͯ
    chain_key(C)ͱhash_key(H)ΛॳظԽ͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  87. template< typename Out, typename CookieType >
    void initiator_hello_phase1( kx_state &stat, Out &out, const wg_key_type &self_static_private, const wg_key_type
    &self_static_public, const wg_key_type &remote_static_public, uint32_t self_spi, const CookieType &cookie ) {
    wg_key_type kdf_key;
    wg_key_type aead_key;
    wg_key_type mac_key;
    wg_tai64n_type self_timestamp;
    dh_generate( stat.self_ephemeral_private, stat.self_ephemeral_public );
    get_initial_chain_key( stat.chain_key );
    get_initial_hash_key( stat.hash_key, stat.chain_key );
    kdf( stat.chain_key ).update( stat.self_ephemeral_public ).get( stat.chain_key );
    hash().update( stat.hash_key, remote_static_public ).get( stat.hash_key );
    hash().update( stat.hash_key, stat.self_ephemeral_public ).get( stat.hash_key );
    dh( kdf_key, stat.self_ephemeral_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    out.resize( wg_kx1_len, 0u );
    auto encrypted_static = make_svv( out.data(), wg_kx1_encrypted_static_offset, wg_encrypted_static_len );
    aead_enc( encrypted_static, aead_key, 0ull, self_static_public, stat.hash_key );
    hash().update( stat.hash_key, encrypted_static ).get( stat.hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    timestamp( std::back_inserter( self_timestamp ) );
    auto encrypted_timestamp = make_svv( out.data(), wg_kx1_encrypted_tai64n_offset, wg_encrypted_tai64n_len );
    aead_enc( encrypted_timestamp, aead_key, 0ull, self_timestamp, stat.hash_key );
    hash().update( stat.hash_key, encrypted_timestamp ).get( stat.hash_key );
    out[ 0 ] = 0x01;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx1_self_spi_offset ), karma::little_dword, self_spi );
    ࣗ෼ͷҰ࣌తൿີ伴(x)ͱ૬खͷ੩తެ։伴(bc)ͰbcxΛ࡞Γ
    bcxΛKDFʹ௨ͯ͠࡞ͬͨ伴Ͱ
    ࣗ෼ͷ੩తެ։伴(ac)Λ҉߸Խ͢Δ
    InitiatorHelloΛ࡞Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  88. hash().update( stat.hash_key, stat.self_ephemeral_public ).get( stat.hash_key );
    dh( kdf_key, stat.self_ephemeral_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    out.resize( wg_kx1_len, 0u );
    auto encrypted_static = make_svv( out.data(), wg_kx1_encrypted_static_offset, wg_encrypted_static_len );
    aead_enc( encrypted_static, aead_key, 0ull, self_static_public, stat.hash_key );
    hash().update( stat.hash_key, encrypted_static ).get( stat.hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    timestamp( std::back_inserter( self_timestamp ) );
    auto encrypted_timestamp = make_svv( out.data(), wg_kx1_encrypted_tai64n_offset, wg_encrypted_tai64n_len );
    aead_enc( encrypted_timestamp, aead_key, 0ull, self_timestamp, stat.hash_key );
    hash().update( stat.hash_key, encrypted_timestamp ).get( stat.hash_key );
    out[ 0 ] = 0x01;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx1_self_spi_offset ), karma::little_dword, self_spi );
    std::copy( stat.self_ephemeral_public.begin(), stat.self_ephemeral_public.end(), std::next( out.begin(),
    wg_kx1_ephemeral_offset ) );
    constexpr static char label_mac1[] = "mac1----";
    auto mac1_message = make_svv( out.data(), 0, wg_kx1_mac1_message_len );
    auto mac1 = make_svv( out.data(), wg_kx1_mac1_offset, wg_mac_len );
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( remote_static_public ).get( mac_key );
    mac( mac_key ).update( mac1_message ).get( mac1 );
    stat.mac1.resize( mac1.size() );
    std::copy( mac1.begin(), mac1.end(), stat.mac1.begin() );
    if( !cookie.empty() ) {
    auto mac2_message = make_svv( out.data(), 0, wg_kx1_mac2_message_len );
    auto mac2 = make_svv( out.data(), wg_kx1_mac2_offset, wg_mac_len );
    mac( cookie ).update( mac2_message ).get( mac2 );
    }
    clear_key( kdf_key );
    clear_key( aead_key );
    ࣗ෼ͷ੩తൿີ伴(a)ͱ૬खͷ੩తެ։伴(bc)ͰabcΛ࡞Γ
    abcΛKDFʹ௨ͯ͠࡞ͬͨ伴Ͱ
    λΠϜελϯϓΛ҉߸Խ͢Δ
    InitiatorHelloΛ࡞Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  89. out.resize( wg_kx1_len, 0u );
    auto encrypted_static = make_svv( out.data(), wg_kx1_encrypted_static_offset, wg_encrypted_static_len );
    aead_enc( encrypted_static, aead_key, 0ull, self_static_public, stat.hash_key );
    hash().update( stat.hash_key, encrypted_static ).get( stat.hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key, aead_key );
    timestamp( std::back_inserter( self_timestamp ) );
    auto encrypted_timestamp = make_svv( out.data(), wg_kx1_encrypted_tai64n_offset, wg_encrypted_tai64n_len );
    aead_enc( encrypted_timestamp, aead_key, 0ull, self_timestamp, stat.hash_key );
    hash().update( stat.hash_key, encrypted_timestamp ).get( stat.hash_key );
    out[ 0 ] = 0x01;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx1_self_spi_offset ), karma::little_dword, self_spi );
    std::copy( stat.self_ephemeral_public.begin(), stat.self_ephemeral_public.end(), std::next( out.begin(),
    wg_kx1_ephemeral_offset ) );
    constexpr static char label_mac1[] = "mac1----";
    auto mac1_message = make_svv( out.data(), 0, wg_kx1_mac1_message_len );
    auto mac1 = make_svv( out.data(), wg_kx1_mac1_offset, wg_mac_len );
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( remote_static_public ).get( mac_key );
    mac( mac_key ).update( mac1_message ).get( mac1 );
    stat.mac1.resize( mac1.size() );
    std::copy( mac1.begin(), mac1.end(), stat.mac1.begin() );
    if( !cookie.empty() ) {
    auto mac2_message = make_svv( out.data(), 0, wg_kx1_mac2_message_len );
    auto mac2 = make_svv( out.data(), wg_kx1_mac2_offset, wg_mac_len );
    mac( cookie ).update( mac2_message ).get( mac2 );
    }
    clear_key( kdf_key );
    clear_key( aead_key );
    clear_key( mac_key );
    }
    mac1Λܭࢉ
    InitiatorHelloΛ࡞Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  90. aead_enc( encrypted_timestamp, aead_key, 0ull, self_timestamp, stat.hash_key );
    hash().update( stat.hash_key, encrypted_timestamp ).get( stat.hash_key );
    out[ 0 ] = 0x01;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx1_self_spi_offset ), karma::little_dword, self_spi );
    std::copy( stat.self_ephemeral_public.begin(), stat.self_ephemeral_public.end(), std::next( out.begin(),
    wg_kx1_ephemeral_offset ) );
    constexpr static char label_mac1[] = "mac1----";
    auto mac1_message = make_svv( out.data(), 0, wg_kx1_mac1_message_len );
    auto mac1 = make_svv( out.data(), wg_kx1_mac1_offset, wg_mac_len );
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( remote_static_public ).get( mac_key );
    mac( mac_key ).update( mac1_message ).get( mac1 );
    stat.mac1.resize( mac1.size() );
    std::copy( mac1.begin(), mac1.end(), stat.mac1.begin() );
    if( !cookie.empty() ) {
    auto mac2_message = make_svv( out.data(), 0, wg_kx1_mac2_message_len );
    auto mac2 = make_svv( out.data(), wg_kx1_mac2_offset, wg_mac_len );
    mac( cookie ).update( mac2_message ).get( mac2 );
    }
    clear_key( kdf_key );
    clear_key( aead_key );
    clear_key( mac_key );
    }
    2෼Ҏ಺ʹड͚औͬͨcookie͕͋Ε͹
    mac2΋ܭࢉ
    InitiatorHelloΛ࡞Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  91. void responder_hello( key_state &key, Out &out, const wg_key_type &self_static_private, const wg_key_type
    &self_static_public, const wg_key_type &remote_static_public, uint32_t self_spi, const CookieType &cookie, const
    In &in ) {
    if( in.size() != wg_kx1_len ) throw invalid_packet();
    if( in[ 0 ] != 0x01 ) throw invalid_packet();
    auto encrypted_static = make_svv( in.data(), wg_kx1_encrypted_static_offset, wg_encrypted_static_len );
    auto encrypted_timestamp = make_svv( in.data(), wg_kx1_encrypted_tai64n_offset, wg_encrypted_tai64n_len );
    auto remote_ephemeral_public = make_svv( in.data(), wg_kx1_ephemeral_offset, wg_ephemeral_len );
    wg_key_type kdf_key, aead_key, chain_key, hash_key, incoming_remote_static_public;
    wg_key_type self_ephemeral_private,;
    wg_key_type q( wg_key_len, 0u );
    wg_key_type t, empty, mac_key, calculated_kx1_mac1;
    wg_tai64n_type remote_timestamp;
    wg_key_type calculated_kx1_mac1;
    namespace qi = boost::spirit::qi;
    uint32_t remote_spi;
    qi::parse( std::next( in.begin(), wg_kx1_self_spi_offset ), std::next( in.begin(), wg_kx1_self_spi_offset +
    wg_spi_len ), qi::little_dword, remote_spi );
    auto kx1_mac1_message = make_svv( in.data(), 0, wg_kx1_mac1_message_len );
    auto incoming_kx1_mac1 = make_svv( in.data(), wg_kx1_mac1_offset, wg_mac_len );
    constexpr static char label_mac1[] = "mac1----";
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( self_static_public ).get( mac_key );
    mac( mac_key ).update( kx1_mac1_message ).get( calculated_kx1_mac1 );
    if( !std::equal( calculated_kx1_mac1.begin(), calculated_kx1_mac1.end(), incoming_kx1_mac1.begin(),
    incoming_kx1_mac1.end() ) )
    throw invalid_packet();
    get_initial_chain_key( chain_key );
    get_initial_hash_key( hash_key, chain_key );
    mac1͕ਖ਼͍͠ࣄΛ֬ೝ
    InitiatorHelloΛड͚औΔ

    View Slide

  92. auto kx1_mac1_message = make_svv( in.data(), 0, wg_kx1_mac1_message_len );
    auto incoming_kx1_mac1 = make_svv( in.data(), wg_kx1_mac1_offset, wg_mac_len );
    constexpr static char label_mac1[] = "mac1----";
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( self_static_public ).get( mac_key );
    mac( mac_key ).update( kx1_mac1_message ).get( calculated_kx1_mac1 );
    if( !std::equal( calculated_kx1_mac1.begin(), calculated_kx1_mac1.end(), incoming_kx1_mac1.begin(),
    incoming_kx1_mac1.end() ) )
    throw invalid_packet();
    get_initial_chain_key( chain_key );
    get_initial_hash_key( hash_key, chain_key );
    kdf( chain_key ).update( remote_ephemeral_public ).get( chain_key );
    hash().update( hash_key, self_static_public ).get( hash_key );
    hash().update( hash_key, remote_ephemeral_public ).get( hash_key );
    dh( kdf_key, self_static_private, remote_ephemeral_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key, aead_key );
    out.resize( wg_kx2_len, 0u );
    if( !aead_dec( incoming_remote_static_public, aead_key, 0ull, encrypted_static, hash_key ) )
    throw invalid_packet();
    hash().update( hash_key, encrypted_static ).get( hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key, aead_key );
    if( !aead_dec( remote_timestamp, aead_key, 0ull, encrypted_timestamp, hash_key ) )
    throw invalid_packet();
    hash().update( hash_key, encrypted_timestamp ).get( hash_key );
    out.resize( wg_kx2_len, 0u );
    auto self_ephemeral_public = make_svv( out.data(), wg_kx2_ephemeral_offset, wg_ephemeral_len );
    auto encrypted_empty = make_svv( out.data(), wg_kx2_encrypted_empty_offset, wg_encrypted_empty_len );
    dh_generate( self_ephemeral_private, self_ephemeral_public );
    kdf( chain_key ).update( self_ephemeral_public ).get( chain_key );
    hash().update( hash_key, self_ephemeral_public ).get( hash_key );
    ૹΒΕ͖ͯͨ஋(cx)Λ࢖ͬͯ
    chain_key(C)ͱhash_key(H)ΛॳظԽ͢Δ
    InitiatorHelloΛड͚औΔ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  93. throw invalid_packet();
    get_initial_chain_key( chain_key );
    get_initial_hash_key( hash_key, chain_key );
    kdf( chain_key ).update( remote_ephemeral_public ).get( chain_key );
    hash().update( hash_key, self_static_public ).get( hash_key );
    hash().update( hash_key, remote_ephemeral_public ).get( hash_key );
    dh( kdf_key, self_static_private, remote_ephemeral_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key, aead_key );
    out.resize( wg_kx2_len, 0u );
    if( !aead_dec( incoming_remote_static_public, aead_key, 0ull, encrypted_static, hash_key ) )
    throw invalid_packet();
    hash().update( hash_key, encrypted_static ).get( hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key, aead_key );
    if( !aead_dec( remote_timestamp, aead_key, 0ull, encrypted_timestamp, hash_key ) )
    throw invalid_packet();
    hash().update( hash_key, encrypted_timestamp ).get( hash_key );
    out.resize( wg_kx2_len, 0u );
    auto self_ephemeral_public = make_svv( out.data(), wg_kx2_ephemeral_offset, wg_ephemeral_len );
    auto encrypted_empty = make_svv( out.data(), wg_kx2_encrypted_empty_offset, wg_encrypted_empty_len );
    dh_generate( self_ephemeral_private, self_ephemeral_public );
    kdf( chain_key ).update( self_ephemeral_public ).get( chain_key );
    hash().update( hash_key, self_ephemeral_public ).get( hash_key );
    dh( kdf_key, self_ephemeral_private, remote_ephemeral_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key );
    dh( kdf_key, self_ephemeral_private, remote_static_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key );
    kdf( chain_key ).update( q ).get( chain_key, t, aead_key );
    hash().update( hash_key, t ).get( hash_key );
    aead_enc( encrypted_empty, aead_key, 0ull, empty, hash_key );
    InitiatorHelloΛड͚औΔ
    ࣗ෼ͷ੩తൿີ伴(b)ͱड͚औͬͨҰ࣌తެ։伴(cx)ͰbcxΛ࡞Γ
    bcxΛKDFʹ௨ͯ͠࡞ͬͨ伴Ͱ
    ૬खͷ੩తެ։伴(ac)Λ෮߸ग़དྷΔࣄΛ֬ೝ͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  94. dh( kdf_key, self_static_private, remote_ephemeral_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key, aead_key );
    out.resize( wg_kx2_len, 0u );
    if( !aead_dec( incoming_remote_static_public, aead_key, 0ull, encrypted_static, hash_key ) )
    throw invalid_packet();
    hash().update( hash_key, encrypted_static ).get( hash_key );
    dh( kdf_key, self_static_private, remote_static_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key, aead_key );
    if( !aead_dec( remote_timestamp, aead_key, 0ull, encrypted_timestamp, hash_key ) )
    throw invalid_packet();
    hash().update( hash_key, encrypted_timestamp ).get( hash_key );
    out.resize( wg_kx2_len, 0u );
    auto self_ephemeral_public = make_svv( out.data(), wg_kx2_ephemeral_offset, wg_ephemeral_len );
    auto encrypted_empty = make_svv( out.data(), wg_kx2_encrypted_empty_offset, wg_encrypted_empty_len );
    dh_generate( self_ephemeral_private, self_ephemeral_public );
    kdf( chain_key ).update( self_ephemeral_public ).get( chain_key );
    hash().update( hash_key, self_ephemeral_public ).get( hash_key );
    dh( kdf_key, self_ephemeral_private, remote_ephemeral_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key );
    dh( kdf_key, self_ephemeral_private, remote_static_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key );
    kdf( chain_key ).update( q ).get( chain_key, t, aead_key );
    hash().update( hash_key, t ).get( hash_key );
    aead_enc( encrypted_empty, aead_key, 0ull, empty, hash_key );
    hash().update( hash_key, encrypted_empty ).get( hash_key );
    out[ 0 ] = 0x02;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx2_self_spi_offset ), karma::little_dword, self_spi );
    karma::generate( std::next( out.begin(), wg_kx2_remote_spi_offset ), karma::little_dword, remote_spi );
    auto kx2_mac1_message = make_svv( out.data(), 0, wg_kx2_mac1_message_len );
    InitiatorHelloΛड͚औΔ
    ࣗ෼ͷ੩తൿີ伴(b)ͱ૬खͷ੩తެ։伴(ac)ͰabcΛ࡞Γ
    abcΛKDFʹ௨ͯ͠࡞ͬͨ伴Ͱ
    λΠϜελϯϓΛ෮߸ग़དྷΔࣄΛ֬ೝ͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  95. throw invalid_packet();
    hash().update( hash_key, encrypted_timestamp ).get( hash_key );
    out.resize( wg_kx2_len, 0u );
    auto self_ephemeral_public = make_svv( out.data(), wg_kx2_ephemeral_offset, wg_ephemeral_len );
    auto encrypted_empty = make_svv( out.data(), wg_kx2_encrypted_empty_offset, wg_encrypted_empty_len );
    dh_generate( self_ephemeral_private, self_ephemeral_public );
    kdf( chain_key ).update( self_ephemeral_public ).get( chain_key );
    hash().update( hash_key, self_ephemeral_public ).get( hash_key );
    dh( kdf_key, self_ephemeral_private, remote_ephemeral_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key );
    dh( kdf_key, self_ephemeral_private, remote_static_public );
    kdf( chain_key ).update( kdf_key ).get( chain_key );
    kdf( chain_key ).update( q ).get( chain_key, t, aead_key );
    hash().update( hash_key, t ).get( hash_key );
    aead_enc( encrypted_empty, aead_key, 0ull, empty, hash_key );
    hash().update( hash_key, encrypted_empty ).get( hash_key );
    out[ 0 ] = 0x02;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx2_self_spi_offset ), karma::little_dword, self_spi );
    karma::generate( std::next( out.begin(), wg_kx2_remote_spi_offset ), karma::little_dword, remote_spi );
    auto kx2_mac1_message = make_svv( out.data(), 0, wg_kx2_mac1_message_len );
    auto kx2_mac1 = make_svv( out.data(), wg_kx2_mac1_offset, wg_mac_len );
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( remote_static_public ).get( mac_key );
    mac( mac_key ).update( kx2_mac1_message ).get( kx2_mac1 );
    if( !cookie.empty() ) {
    auto mac2_message = make_svv( out.data(), 0, wg_kx2_mac2_message_len );
    auto mac2 = make_svv( out.data(), wg_kx2_mac2_offset, wg_mac_len );
    mac( cookie ).update( mac2_message ).get( mac2 );
    }
    kdf( chain_key ).update( empty ).get( key.receive_key, key.send_key );
    ResponderHelloΛ࡞Δ
    Ұ࣌伴ϖΞ(yͱcy)Λ࡞ͬͯ
    4ͭͷ஋ͷ͏ͪ·ͩٻΊ͍ͯͳ͍acyͱcxyΛٻΊΔ
    4ͭͷ஋શͯΛKDFʹ௨ͯ͠ಘͨ伴Ͱ
    ۭจࣈྻΛ҉߸Խ͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  96. hash().update( hash_key, t ).get( hash_key );
    aead_enc( encrypted_empty, aead_key, 0ull, empty, hash_key );
    hash().update( hash_key, encrypted_empty ).get( hash_key );
    out[ 0 ] = 0x02;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( out.begin(), wg_kx2_self_spi_offset ), karma::little_dword, self_spi );
    karma::generate( std::next( out.begin(), wg_kx2_remote_spi_offset ), karma::little_dword, remote_spi );
    auto kx2_mac1_message = make_svv( out.data(), 0, wg_kx2_mac1_message_len );
    auto kx2_mac1 = make_svv( out.data(), wg_kx2_mac1_offset, wg_mac_len );
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( remote_static_public ).get( mac_key );
    mac( mac_key ).update( kx2_mac1_message ).get( kx2_mac1 );
    if( !cookie.empty() ) {
    auto mac2_message = make_svv( out.data(), 0, wg_kx2_mac2_message_len );
    auto mac2 = make_svv( out.data(), wg_kx2_mac2_offset, wg_mac_len );
    mac( cookie ).update( mac2_message ).get( mac2 );
    }
    kdf( chain_key ).update( empty ).get( key.receive_key, key.send_key );
    kdf_key.resize( wg_key_len );
    clear_key( kdf_key );
    clear_key( aead_key );
    clear_key( mac_key );
    clear_key( q );
    clear_key( t );
    clear_key( self_ephemeral_private );
    clear_key( chain_key );
    clear_key( hash_key );
    ResponderHelloΛ࡞Δ
    macΛ͚ͭͯ׬੒
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  97. template< typename In >
    void initiator_hello_phase2( key_state &key, const wg_key_type &self_static_private, const wg_key_type
    &self_static_public, const wg_key_type &/*remote_static_public*/, uint32_t /*self_spi*/, kx_state &stat, const In
    &in ) {
    if( in.size() != wg_kx2_len ) throw invalid_packet();
    if( in[ 0 ] != 0x02 ) throw invalid_packet();
    namespace qi = boost::spirit::qi;
    uint32_t remote_spi;
    qi::parse( std::next( in.begin(), wg_kx1_self_spi_offset ), std::next( in.begin(), wg_kx1_self_spi_offset +
    wg_spi_len ), qi::little_dword, remote_spi );
    auto encrypted_empty = make_svv( in.data(), wg_kx2_encrypted_empty_offset, wg_encrypted_empty_len );
    auto remote_ephemeral_public = make_svv( in.data(), wg_kx2_ephemeral_offset, wg_ephemeral_len );
    wg_key_type kdf_key, aead_key, t, empty, calculated_kx2_mac1, mac_key;
    wg_key_type q( wg_key_len, 0u );
    auto kx2_mac1_message = make_svv( in.data(), 0, wg_kx2_mac1_message_len );
    auto incoming_kx2_mac1 = make_svv( in.data(), wg_kx2_mac1_offset, wg_mac_len );
    constexpr static char label_mac1[] = "mac1----";
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( self_static_public ).get( mac_key );
    mac( mac_key ).update( kx2_mac1_message ).get( calculated_kx2_mac1 );
    if( !std::equal( calculated_kx2_mac1.begin(), calculated_kx2_mac1.end(), incoming_kx2_mac1.begin(),
    incoming_kx2_mac1.end() ) )
    throw invalid_packet();
    kdf( stat.chain_key ).update( remote_ephemeral_public ).get( stat.chain_key );
    hash().update( stat.hash_key, remote_ephemeral_public ).get( stat.hash_key );
    dh( kdf_key, stat.self_ephemeral_private, remote_ephemeral_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key );
    dh( kdf_key, self_static_private, remote_ephemeral_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key );
    ResponderHelloΛड͚औΔ
    mac1͕ਖ਼͍͠ࣄΛ֬ೝ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  98. constexpr static char label_mac1[] = "mac1----";
    hash().update( label_mac1, label_mac1 + strlen( label_mac1 ) ).update( self_static_public ).get( mac_key );
    mac( mac_key ).update( kx2_mac1_message ).get( calculated_kx2_mac1 );
    if( !std::equal( calculated_kx2_mac1.begin(), calculated_kx2_mac1.end(), incoming_kx2_mac1.begin(),
    incoming_kx2_mac1.end() ) )
    throw invalid_packet();
    kdf( stat.chain_key ).update( remote_ephemeral_public ).get( stat.chain_key );
    hash().update( stat.hash_key, remote_ephemeral_public ).get( stat.hash_key );
    dh( kdf_key, stat.self_ephemeral_private, remote_ephemeral_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key );
    dh( kdf_key, self_static_private, remote_ephemeral_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key );
    kdf( stat.chain_key ).update( q ).get( stat.chain_key, t, aead_key );
    hash().update( stat.hash_key, t ).get( stat.hash_key );
    if( !aead_dec( empty, aead_key, 0ull, encrypted_empty, stat.hash_key ) )
    throw invalid_packet();
    hash().update( stat.hash_key, encrypted_empty ).get( stat.hash_key );
    kdf( stat.chain_key ).update( empty ).get( key.send_key, key.receive_key );
    clear_key( kdf_key );
    clear_key( aead_key );
    clear_key( mac_key );
    clear_key( q );
    clear_key( t );
    clear_key( stat.self_ephemeral_private );
    clear_key( stat.self_ephemeral_public );
    clear_key( stat.chain_key );
    clear_key( stat.hash_key );
    }
    ResponderHelloΛड͚औΔ
    ࣗ෼ͷ੩తൿີ伴(a)ͱड͚औͬͨҰ࣌తൿີ伴(cy)ͰacyΛ࡞Δ
    ࣗ෼ͷҰ࣌తൿີ伴(x)ͱड͚औͬͨҰ࣌తൿີ伴(cy)ͰcxyΛ࡞Δ
    4ͭͷ஋શͯΛKDFʹ௨ͯ͠ಘͨ伴Ͱ
    ۭจࣈྻΛ෮߸ग़དྷΔࣄΛ֬ೝ͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  99. hash().update( stat.hash_key, remote_ephemeral_public ).get( stat.hash_key );
    dh( kdf_key, stat.self_ephemeral_private, remote_ephemeral_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key );
    dh( kdf_key, self_static_private, remote_ephemeral_public );
    kdf( stat.chain_key ).update( kdf_key ).get( stat.chain_key );
    kdf( stat.chain_key ).update( q ).get( stat.chain_key, t, aead_key );
    hash().update( stat.hash_key, t ).get( stat.hash_key );
    if( !aead_dec( empty, aead_key, 0ull, encrypted_empty, stat.hash_key ) )
    throw invalid_packet();
    hash().update( stat.hash_key, encrypted_empty ).get( stat.hash_key );
    kdf( stat.chain_key ).update( empty ).get( key.send_key, key.receive_key );
    clear_key( kdf_key );
    clear_key( aead_key );
    clear_key( mac_key );
    clear_key( q );
    clear_key( t );
    clear_key( stat.self_ephemeral_private );
    clear_key( stat.self_ephemeral_public );
    clear_key( stat.chain_key );
    clear_key( stat.hash_key );
    }
    ResponderHelloΛड͚औΔ
    InitiatorHelloͱResponderHelloͰڞ༗ͨ͠chain_key(C)Λ
    KDFʹ௨ͯ͠ηογϣϯ伴Λ࡞Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  100. template< typename Out, typename In >
    void encrypt_data( Out &packet, const key_state &key, In &&plain ) {
    const auto packet_size = plain.size() / 16 * 16 + ( plain.size() % 16 ? 16 : 0 );
    packet.clear();
    packet.resize( packet_size + wg_aead_hash_len + wg_counter_len + wg_spi_len + wg_header_len, 0u );
    packet[ 0 ] = 0x04;
    namespace karma = boost::spirit::karma;
    karma::generate( std::next( packet.begin(), wg_transport_remote_spi_offset ), karma::little_dword,
    key.remote_kxid );
    karma::generate( std::next( packet.begin(), wg_transport_counter_offset ), karma::little_qword, key.tx_count );
    plain.resize( packet_size, 0u );
    wg_key_type empty;
    auto encrypted = make_svv( packet.data(), wg_transport_packet_offset, packet_size + wg_aead_hash_len );
    aead_enc( encrypted, key.send_key, key.tx_count, plain, empty );
    }
    ύέοτΛૹΔ
    ύέοτΛηογϣϯΩʔͰ҉߸Խ͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  101. template< typename Out, typename In >
    bool decrypt_data( Out &plain, key_state &key, const In &packet ) {
    if( packet.size() < wg_transport_packet_offset + wg_aead_hash_len )
    return false;
    if( packet[ 0 ] != 0x04 )
    return false;
    namespace qi = boost::spirit::qi;
    uint64_t counter = 0;
    qi::parse( std::next( packet.begin(), wg_transport_counter_offset ), std::next( packet.begin(),
    wg_transport_counter_offset + wg_counter_len ), qi::little_qword, counter );
    wg_key_type empty;
    auto encrypted = make_svv( packet.data(), wg_transport_packet_offset, packet.size() -
    wg_transport_packet_offset );
    if( !aead_dec( plain, key.receive_key, counter, encrypted, empty ) )
    return false;
    if( plain.size() >= 4u ) {
    uint16_t length = 0;
    qi::parse( std::next( plain.begin(), 2 ), std::next( plain.begin(), 4 ), qi::big_word, length );
    if( plain.size() < length )
    return false;
    plain.resize( length );
    }
    return true;
    }
    ύέοτΛड͚औΔ
    ύέοτΛηογϣϯΩʔͰ෮߸͢Δ
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  102. class tunnel {
    public:
    tunnel( const std::string &devname ) : fd( 0 ) {
    ifreq ifr;
    if( ( fd = open("/dev/net/tun", O_RDWR) ) < 0 ) {
    std::string device_file_path( "/dev/" );
    device_name = devname.empty() ? std::string( "tun0" ) : devname;
    device_file_path += device_name;
    if( ( fd = open( device_file_path.c_str(), O_RDWR ) ) < 0 )
    throw unable_to_open_tunnel();
    }
    else {
    memset( &ifr, 0, sizeof( ifr ) );
    ifr.ifr_flags = IFF_TUN|IFF_NO_PI;
    if( !devname.empty() )
    strncpy( ifr.ifr_name, devname.c_str(), IFNAMSIZ );
    if( ioctl( fd, TUNSETIFF, (void *) &ifr ) < 0 ) {
    close( fd );
    throw unable_to_open_tunnel();
    }
    device_name = ifr.ifr_name;
    }
    }
    tunnel( const tunnel& ) = delete;
    tunnel( tunnel&& ) = delete;
    tunnel &operator=( const tunnel& ) = delete;
    tunnel &operator=( tunnel&& ) = delete;
    ~tunnel() {
    ͜ΕΛLinuxͷτϯωϧσόΠεʹܨ͙
    https://github.com/Fadis/userspace_wireguard
    ιʔείʔυ

    View Slide

  103. $ ip address add dev tun0 192.168.3.2 peer 192.168.3.1
    $ ip link set tun0 mtu 1420
    $ ip link set tun0 up
    $ ping -c 5 192.168.3.1
    PING 192.168.3.1 (192.168.3.1) 56(84) bytes of data.
    64 bytes from 192.168.3.1: icmp_seq=1 ttl=64 time=9.35 ms
    64 bytes from 192.168.3.1: icmp_seq=2 ttl=64 time=9.50 ms
    64 bytes from 192.168.3.1: icmp_seq=3 ttl=64 time=9.08 ms
    64 bytes from 192.168.3.1: icmp_seq=4 ttl=64 time=9.44 ms
    64 bytes from 192.168.3.1: icmp_seq=5 ttl=64 time=9.31 ms
    --- 192.168.3.1 ping statistics ---
    5 packets transmitted, 5 received, 0% packet loss, time 4006ms
    rtt min/avg/max/mdev = 9.080/9.340/9.508/0.180 ms
    (192.168.3.1ଆͰ͸ຊՈͷWireGuardσόΠε͕଴ͪड͚த)
    ͳΜͯ؆୯ͳϓϩτίϧͳΜͰ͠ΐ͏

    View Slide

  104. 00:43:13.196699 IP alice.example.com.51820 > bob.example.com.51820: UDP, length 148
    0x0000: 4588 00b0 23ad 0000 4011 xxxx xxxx xxxx
    0x0010: xxxx xxxx ca6c ca6c 009c 888f 0100 0000
    0x0020: 2a7b ac07 6d64 422c e2d0 7eb5 5e9d a0aa
    0x0030: 6231 c432 8724 d075 7985 8047 5b35 f43a
    0x0040: 1e99 4f2b f2f0 d747 c6f9 4e51 0464 3e7c
    0x0050: e943 c7a8 ec3b 9267 2f69 9751 eb79 2436
    0x0060: a838 13ae 159e 314c 9f44 2bd8 6797 139e
    0x0070: 7e4f a059 8eab c125 fca7 e071 6c4d 272e
    0x0080: bde2 9471 21ce 8778 5570 9a76 6cf5 c2e4
    0x0090: 4026 788d 74c4 6fd0 7bc9 26e2 c5c7 793c
    0x00a0: 0000 0000 0000 0000 0000 0000 0000 0000
    00:43:13.205687 IP bob.example.com.51820 > alice.example.com.51820: UDP, length 92
    0x0000: 4588 0078 fd9f 0000 3711 xxxx xxxx xxxx
    0x0010: xxxx xxxx ca6c ca6c 0064 77d7 0200 0000
    0x0020: 361f 3634 2a7b ac07 0664 5105 54ea af29
    0x0030: 01b5 5497 c882 e6f8 d1d9 ea95 10e9 035d
    0x0040: 70a7 72a3 1206 295f 9749 4399 4eca 7f8f
    0x0050: 3452 8ff1 ea91 bb54 29d5 5417 bdf3 6361
    0x0060: 6fbc 4197 a17c cf98 0000 0000 0000 0000
    0x0070: 0000 0000 0000 0000
    00:43:13.205983 IP alice.example.com.51820 > bob.example.com.51820: UDP, length 128
    0x0000: 4500 009c 23b6 0000 4011 xxxx xxxx xxxx
    0x0010: xxxx xxxx ca6c ca6c 0088 887b 0400 0000
    0x0020: 361f 3634 0000 0000 0000 0000 6265 0e85
    0x0030: 0f77 6b8c 13fb 1c1e 42a0 626d ff07 b5bb
    0x0040: 27bb ceb0 677b d98f bc6e 79b3 5318 87d6
    0x0050: af39 daf1 c63e f843 19bc 2dd1 02b7 6cde
    0x0060: c292 6cb2 254e 87f2 7b3a 788b c9ee 6a5b
    0x0070: 5e68 7eb9 5741 b9dc 9d84 fd42 54ab bb17
    0x0080: edf0 eae4 715b b097 def6 28e2 790e 73c1

    View Slide

  105. 00:43:13.196699 IP alice.example.com.51820 > bob.example.com.51820: UDP, length 148
    0x0000: 4588 00b0 23ad 0000 4011 xxxx xxxx xxxx
    0x0010: xxxx xxxx ca6c ca6c 009c 888f 0100 0000
    0x0020: 2a7b ac07 6d64 422c e2d0 7eb5 5e9d a0aa
    0x0030: 6231 c432 8724 d075 7985 8047 5b35 f43a
    0x0040: 1e99 4f2b f2f0 d747 c6f9 4e51 0464 3e7c
    0x0050: e943 c7a8 ec3b 9267 2f69 9751 eb79 2436
    0x0060: a838 13ae 159e 314c 9f44 2bd8 6797 139e
    0x0070: 7e4f a059 8eab c125 fca7 e071 6c4d 272e
    0x0080: bde2 9471 21ce 8778 5570 9a76 6cf5 c2e4
    0x0090: 4026 788d 74c4 6fd0 7bc9 26e2 c5c7 793c
    0x00a0: 0000 0000 0000 0000 0000 0000 0000 0000
    00:43:13.205687 IP bob.example.com.51820 > alice.example.com.51820: UDP, length 92
    0x0000: 4588 0078 fd9f 0000 3711 xxxx xxxx xxxx
    0x0010: xxxx xxxx ca6c ca6c 0064 77d7 0200 0000
    0x0020: 361f 3634 2a7b ac07 0664 5105 54ea af29
    0x0030: 01b5 5497 c882 e6f8 d1d9 ea95 10e9 035d
    0x0040: 70a7 72a3 1206 295f 9749 4399 4eca 7f8f
    0x0050: 3452 8ff1 ea91 bb54 29d5 5417 bdf3 6361
    0x0060: 6fbc 4197 a17c cf98 0000 0000 0000 0000
    0x0070: 0000 0000 0000 0000
    00:43:13.205983 IP alice.example.com.51820 > bob.example.com.51820: UDP, length 128
    0x0000: 4500 009c 23b6 0000 4011 xxxx xxxx xxxx
    0x0010: xxxx xxxx ca6c ca6c 0088 887b 0400 0000
    0x0020: 361f 3634 0000 0000 0000 0000 6265 0e85
    0x0030: 0f77 6b8c 13fb 1c1e 42a0 626d ff07 b5bb
    0x0040: 27bb ceb0 677b d98f bc6e 79b3 5318 87d6
    0x0050: af39 daf1 c63e f843 19bc 2dd1 02b7 6cde
    0x0060: c292 6cb2 254e 87f2 7b3a 788b c9ee 6a5b
    0x0070: 5e68 7eb9 5741 b9dc 9d84 fd42 54ab bb17
    0x0080: edf0 eae4 715b b097 def6 28e2 790e 73c1
    ΦϨϯδ৭ͷ෦෼͕*1ϔομ
    ࢵ৭ͷ෦෼͕6%1ϔομ
    *OJUJBUPS)FMMP
    3FTQPOEFS)FMMP
    5SBOTQPSU%BUB
    ௨৴಺༰͸όϨͳ͍͚Ͳ
    WireGuardͰ௨৴͍ͯ͠Δࣄ͸όϨόϨ

    View Slide

  106. ·ͱΊ
    WireGuard͸ͱͯ΋γϯϓϧͳ͕Β
    VPN͕උ͑Δ΂͖Ұ௨ΓͷػೳΛඋ͑ͨ
    ৽͍͠L3VPNͷख๏
    ͦͷ࢓༷͸
    ௨৴ͷ֊૚ߏ଄ͷ؍఺͔ΒݟΔͱ៉ྷͰ͸ͳ͍͕
    ߹ཧతͰ͋Δ

    View Slide