golang.zx2c4.com/wireguard/windows@v0.5.4-0.20230123132234-dcc0eb72a04b/tunnel/deterministicguid.go (about) 1 /* SPDX-License-Identifier: MIT 2 * 3 * Copyright (C) 2019-2022 WireGuard LLC. All Rights Reserved. 4 */ 5 6 package tunnel 7 8 import ( 9 "bytes" 10 "encoding/binary" 11 "sort" 12 "unsafe" 13 14 "golang.org/x/crypto/blake2s" 15 "golang.org/x/sys/windows" 16 "golang.org/x/text/unicode/norm" 17 18 "golang.zx2c4.com/wireguard/windows/conf" 19 ) 20 21 const ( 22 deterministicGUIDLabel = "Deterministic WireGuard Windows GUID v1 jason@zx2c4.com" 23 fixedGUIDLabel = "Fixed WireGuard Windows GUID v1 jason@zx2c4.com" 24 ) 25 26 // Escape hatch for external consumers, not us. 27 var UseFixedGUIDInsteadOfDeterministic = false 28 29 /* All peer public keys and allowed ips are sorted. Length/number fields are 30 * little endian 32-bit. Hash input is: 31 * 32 * label || len(interface name) || interface name || 33 * interface public key || number of peers || 34 * peer public key || number of peer allowed ips || 35 * len(allowed ip string) || allowed ip/cidr in canonical string notation || 36 * len(allowed ip string) || allowed ip/cidr in canonical string notation || 37 * len(allowed ip string) || allowed ip/cidr in canonical string notation || 38 * ... 39 * peer public key || number of peer allowed ips || 40 * len(allowed ip string) || allowed ip/cidr in canonical string notation || 41 * len(allowed ip string) || allowed ip/cidr in canonical string notation || 42 * len(allowed ip string) || allowed ip/cidr in canonical string notation || 43 * ... 44 * ... 45 */ 46 47 func deterministicGUID(c *conf.Config) *windows.GUID { 48 b2, _ := blake2s.New256(nil) 49 if !UseFixedGUIDInsteadOfDeterministic { 50 b2.Write([]byte(deterministicGUIDLabel)) 51 } else { 52 b2.Write([]byte(fixedGUIDLabel)) 53 } 54 b2Number := func(i int) { 55 if uint(i) > uint(^uint32(0)) { 56 panic("length out of bounds") 57 } 58 var bytes [4]byte 59 binary.LittleEndian.PutUint32(bytes[:], uint32(i)) 60 b2.Write(bytes[:]) 61 } 62 b2String := func(s string) { 63 bytes := []byte(s) 64 bytes = norm.NFC.Bytes(bytes) 65 b2Number(len(bytes)) 66 b2.Write(bytes) 67 } 68 b2Key := func(k *conf.Key) { 69 b2.Write(k[:]) 70 } 71 72 b2String(c.Name) 73 if !UseFixedGUIDInsteadOfDeterministic { 74 b2Key(c.Interface.PrivateKey.Public()) 75 b2Number(len(c.Peers)) 76 sortedPeers := c.Peers 77 sort.Slice(sortedPeers, func(i, j int) bool { 78 return bytes.Compare(sortedPeers[i].PublicKey[:], sortedPeers[j].PublicKey[:]) < 0 79 }) 80 for _, peer := range sortedPeers { 81 b2Key(&peer.PublicKey) 82 b2Number(len(peer.AllowedIPs)) 83 sortedAllowedIPs := peer.AllowedIPs 84 sort.Slice(sortedAllowedIPs, func(i, j int) bool { 85 if bi, bj := sortedAllowedIPs[i].Addr().BitLen(), sortedAllowedIPs[j].Addr().BitLen(); bi != bj { 86 return bi < bj 87 } 88 if sortedAllowedIPs[i].Bits() != sortedAllowedIPs[j].Bits() { 89 return sortedAllowedIPs[i].Bits() < sortedAllowedIPs[j].Bits() 90 } 91 return sortedAllowedIPs[i].Addr().Compare(sortedAllowedIPs[j].Addr()) < 0 92 }) 93 for _, allowedip := range sortedAllowedIPs { 94 b2String(allowedip.String()) 95 } 96 } 97 } 98 return (*windows.GUID)(unsafe.Pointer(&b2.Sum(nil)[0])) 99 }