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. 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/ͷ֤ख๏ͷ೥݄೔࣌఺ͷ ࠷৽ͷ҆ఆ൛ͷιʔείʔυͷߦ਺ ܻҰͭҧ͏
  2. ͜͜ʹ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
  3. $ 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/
  4. 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౤͛ͨΓ 伴ϖΞͭͬͨ͘Γ͢ΔϢʔβۭؒπʔϧ
  5. WireGuardΛ࢖ͬͯΈΑ͏ $ wg genkey >private.key $ wg pubkey <private.key >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 ൿີ伴ͱެ։伴Λ࡞Δ ର޲ͷϗετͷެ։伴 ࣗ෼ͷൿີ伴 ର޲ͷϗετͷΞυϨεͱϙʔτ ௨৴Λ଴ͪड͚Δϙʔτ
  6. 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ΛுΔ྆ଆͷϗετͰߦ͏
  7. $ 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׬੒
  8. 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ͷઃఆ
  9. ࢲ͸͜Μͳํ๏Ͱ 伴ڞ༗͕Ͱ͖·͢ ͜ͷํ๏Ͱ伴ڞ༗͠·͠ΐ͏ 伴ͷૉͰ͢ 伴ͷૉͰ͢ ͋ͳ͕ͨຊ෺ͳΒ ͜ΕΛ෮߸Ͱ͖ΔഺͰ͢ ͋ͳ͕ͨຊ෺ͳΒ ͜ΕΛ෮߸Ͱ͖ΔഺͰ͢ ڞ௨伴Λ

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

    खʹೖΕͨ ͞ΒʹIKE Phase2Ͱ௨৴༻ͷڞ௨伴ͱ ௨৴ํ๏ͷબ୒͕ߦΘΕͯ Α͏΍͘ύέοτΛྲྀͤΔঢ়ଶʹͳΔ
  11. Noise Protocol Framework ఆ਺a ࣄલʹܾΊͨૉ਺c ఆ਺b ఆ਺ac ఆ਺bc cx cy

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

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

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

    ཚ਺x ཚ਺y abc bcx acy cxy bcx cxy abc acy ,%' ,%' ڵຯਂ͍ಇ͖Λ͢Δͷ͕bcx Noise Protocol Framework
  16. ఆ਺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
  17. 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ͷओ
  18. Alice͸ cx ͱ bcx͔Β࡞ͬͨ伴Ͱ҉߸Խͨࣗ͠਎ͷެ։伴ac ΛBobʹૹ৴ Bob͸ bcxΛٻΊͯAlice͔ΒૹΒΕ͖ͯͨެ։伴acΛ෮߸͠ Aliceͷ੩తެ։伴ͱ߹͏ࣄΛ֬ೝ͔ͯ͠Βabc acy cxyΛٻΊΔ

    cy ͱ 4ͭͷ஋͔Β࡞ͬͨ伴Ͱ҉߸Խۭͨ͠จࣈྻ ΛAliceʹૹ৴ 4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ Alice͸ abc acy cxyΛٻΊΔ 4ͭͷ஋ͰBob͔ΒૹΒΕ͖ۭͯͨจࣈྻΛ෮߸Ͱ͖ΔࣄΛ֬ೝ 4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ
  19. 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όΠτ)
  20. 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ѼʹૹΒΕͯ͘Δ
  21. 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Ͱ௨৴ʹ৐Δ஋͸ୈࡾऀʹݟ͑ͯ΋ྑ͍ҝ ͜ͷ஋͸҉߸Խ͞ΕͣʹૹΒΕΔ
  22. 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ʹૹΔ
  23. 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͔Βड͚औͬͨࣄ͕͋ΔλΠϜελϯϓҎԼͷ৔߹ ཁٻΛແࢹ͢Δ (ϋϯυγΣΠΫ࣌ͷϦϓϨΠ߈ܸͷճආ) λΠϜελϯϓ͸୯ௐ૿Ճ͍ͯ͠Ε͹ྑ͘ ਖ਼֬ͳ࣌ؒΛද͍ͯ͠Δඞཁ͸ͳ͍
  24. 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ʹରͯ͠ෛՙΛ͔͚Δछྨͷ߈ܸΛ ճආ͢ΔͨΊͷ΋ͷ ৄࡉ͸ޙड़
  25. 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Λ࡞Δखॱ
  26. 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Λಉظ͢Δखॱ
  27. Responder Hello 0x02 (1όΠτ) Reserved (3όΠτ) ड৴ऀID (4όΠτ) Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ ૹ৴ऀID

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

    (4όΠτ) Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋ BobͷҰ࣌తެ։伴 (cy) (32όΠτ) ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ (16όΠτ) mac1 (16όΠτ) mac2 (16όΠτ) ηογϣϯཱ֬ޙʹAlice͔ΒૹΒΕͯ͘Δύέοτ͸ ͜͜Ͱࢦఆͨ͠IDѼʹૹΒΕͯ͘Δ
  29. 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ʹର͢Δ ฦ౴͕ฦ͖ͬͯͨͷ͔ΛࣝผͰ͖Δ
  30. 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Ͱ௨৴ʹ৐Δ஋͸ୈࡾऀʹݟ͑ͯ΋ྑ͍ҝ ͜ͷ஋͸҉߸Խ͞ΕͣʹૹΒΕΔ
  31. 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 ΛٻΊΔ͜ͱ͕Ͱ͖Δ
  32. 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 ΛٻΊΔ͜ͱ͕Ͱ͖Δ
  33. Responder Hello 0x02 (1όΠτ) Reserved (3όΠτ) ड৴ऀID (4όΠτ) Bob͕ηογϣϯ͝ͱʹϢχʔΫͳ஋Λࢦఆ͢Δ ૹ৴ऀID

    (4όΠτ) Alice͕ࢦఆ͖ͯͨ͠ηογϣϯ͝ͱʹϢχʔΫͳ஋ BobͷҰ࣌తެ։伴 (cy) (32όΠτ) ۭจࣈྻΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ (16όΠτ) mac1 (16όΠτ) mac2 (16όΠτ) WireGuardʹରͯ͠ෛՙΛ͔͚Δछྨͷ߈ܸΛ ճආ͢ΔͨΊͷ΋ͷ ৄࡉ͸ޙड़
  34. 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Λ࡞Δखॱ ࣄલʹڞ༗ͨ͠ύεϫʔυ͕͋Δ৔߹ ͜͜ʹಥͬࠐΉ
  35. 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͔Βύέοτͷ҉߸Խʹ࢖͏伴Λ࡞Δ
  36. Transport Data 0x04 (1όΠτ) Reserved (3όΠτ) ड৴ऀID (4όΠτ) ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋ Χ΢ϯλ

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

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

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

    (8όΠτ) ಉҰηογϣϯͰύέοτΛ1ݸૹ৴͢Δͨͼʹ1ͮͭ૿͍͑ͯ͘஋ ύέοτΛChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ (҉߸Խલͷύέοτ௕+16όΠτ) Chacha20-Poly1305Ͱ҉߸Խ͞Εͨύέοτຊମ WireGuardͷMTU͸Transport Dataͷύέοτͷશ௕͕ ҉߸Խ͞ΕͨύέοτΛૹΔ௨৴࿏ͷMTUΛ௒͑ͳ͍஋ʹ͢Δ
  40. ύέοτ௕͕ฏจͷঢ়ଶͰ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ʹ͸ݩͷύέοτͷ௕͞͸ॻ͔Ε͍ͯͳ͍
  41. 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͸ΧϓηϧԽͨ͠ύέοτͷத͔Β ύέοτ௕ΛऔΓग़ͯ͠ύσΟϯάΛ෼཭͢Δ
  42. "MJDF #PC *OJUJBUPS )FMMP 3FTQPOEFS )FMMP 5SBOTQPSU %BUB 5SBOTQPSU %BUB

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

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

    ͍  WireGuardͷϝοηʔδ͸UDPͰૹΒΕΔҝ ϝοηʔδ͸ॱং͕มΘͬͨΓແ͘ͳͬͨΓ͢Δ          ͜ͷύέοτ͕ ٘ਜ਼ʹͳΔ
  45. RFC6479 IPsec Anti-Replay Algorithm without Bit Shifting ࡁ ࡁ ະ

    ະ ࡁ ະ ະ ະ ࡁ ະ ະ ະ ະ ະ ະ ະ                     ط஌ͷ࠷৽ ϦϯάόοϑΝΛ࢖ͬͯ ड͚औͬͨ͜ͱ͕͋ΔΧ΢ϯλͷ஋ͷ࠷େ஋पลͷ ஋ͷड͚औΓঢ়گΛ͓֮͑ͯ͘ গʑॱ൪͕ೖΕସΘͬͯಧ͍ͯ΋ ॏෳ͢Δύέοτ͚ͩΛ஄͘͜ͱ͕Ͱ͖Δ
  46. RFC6479 IPsec Anti-Replay Algorithm without Bit Shifting ར఺ ड͚औͬͨશͯͷύέοτͷΧ΢ϯλΛ͓֮͑ͯ͘͜ͱͳ͘ ॱ൪͕ೖΕସΘΔՄೳੑ͕͋Δύέοτͷྻ͔Β

    ॏෳ͢ΔύέοτΛݟ͚ͭग़͢͜ͱ͕Ͱ͖Δ ܽ఺ ύέοτͷॱ൪͕߽շʹೖΕସΘ͍ͬͯΔͱ ࣮ࡍʹ͸ॏෳ͕ͳ͔ͬͨͱͯ͠΋ ड͚औΓΛڋ൱͞ΕΔύέοτ͕ੜ͡Δ
  47. Alice͸ cx ͱ bcx͔Β࡞ͬͨ伴Ͱ҉߸Խͨࣗ͠਎ͷެ։伴 ΛBobʹૹ৴ Bob͸ bcxΛٻΊͯAlice͔ΒૹΒΕ͖ͯͨެ։伴Λ෮߸͠ Aliceͷ੩తެ։伴ͱ߹͏ࣄΛ֬ೝ͔ͯ͠Βabc acy cxyΛٻΊΔ

    cy ͱ 4ͭͷ஋͔Β࡞ͬͨ伴Ͱ҉߸Խۭͨ͠จࣈྻ ΛAliceʹૹ৴ 4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ Alice͸ abc acy cxyΛٻΊΔ 4ͭͷ஋ͰBob͔ΒૹΒΕ͖ۭͯͨจࣈྻΛ෮߸Ͱ͖ΔࣄΛ֬ೝ 4ͭͷ஋͔Β࡞ͬͨ伴͔Βૹ৴伴ͱड৴伴Λ࡞Δ
  48. 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͕΋ͨͳ͍
  49. 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Λ࡞Εͳ͍
  50. Cookie Reply 0x03 (1όΠτ) Reserved (3όΠτ) ड৴ऀID (4όΠτ) ύέοτΛड͚औΔଆ͕Ͳͷηογϣϯͷύέοτͳͷ͔Λࣝผ͢Δҝͷ஋ nonce

    (24όΠτ) cookieͷ҉߸Խʹ࢖ͬͨnonceͷ஋ cookieΛXChacha20-Poly1305Ͱ҉߸Խͨ͠΋ͷ (16όΠτ+16όΠτ) ߴෛՙͳ࣌ʹInitiatorHelloΛड͚औͬͨBob͸ AliceʹResponderHelloͷ୅ΘΓʹCookieReplyΛ౤͛Δ
  51. 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ͷϦϓϨΠ߈ܸͷճආ)
  52. 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ΑΓલͷ௨৴಺༰ͷ伴෇͖ϋογϡΛ͚ͭΔ
  53. 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 ιʔείʔυ
  54. 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 ιʔείʔυ
  55. 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 ιʔείʔυ
  56. 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 ιʔείʔυ
  57. 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 ιʔείʔυ
  58. 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Λड͚औΔ
  59. 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 ιʔείʔυ
  60. 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 ιʔείʔυ
  61. 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 ιʔείʔυ
  62. 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 ιʔείʔυ
  63. 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 ιʔείʔυ
  64. 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 ιʔείʔυ
  65. 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 ιʔείʔυ
  66. 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 ιʔείʔυ
  67. 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 ιʔείʔυ
  68. 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 ιʔείʔυ
  69. 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 ιʔείʔυ
  70. $ 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σόΠε͕଴ͪड͚த) ͳΜͯ؆୯ͳϓϩτίϧͳΜͰ͠ΐ͏
  71. 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
  72. 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Ͱ௨৴͍ͯ͠Δࣄ͸όϨόϨ