这段Go代码主要用于根据WireGuard配置文件生成一个确定性的GUID(全局唯一标识符)。GUID是在Windows系统中广泛使用的标识符格式,用于标识对象或实体。这段代码使用BLAKE2s哈希函数来生成GUID,并通过特定的规则和输入数据来确保其唯一性和确定性。
导入包
import (
"bytes"
"encoding/binary"
"sort"
"unsafe"
"golang.org/x/crypto/blake2s"
"golang.org/x/sys/windows"
"golang.org/x/text/unicode/norm"
"golang.zx2c4.com/wireguard/windows/conf"
)
分析:
bytes
提供了字节缓冲区和常用的字节操作功能。encoding/binary
提供了在不同字节序(大端、小端)之间转换数据的能力。sort
提供了切片排序功能。unsafe
允许进行不安全的内存操作,如直接转换指针类型。blake2s
是一种加密哈希函数,速度快且安全性高。windows
提供了与Windows操作系统的交互功能,包括GUID的定义。norm
提供了Unicode规范化功能,确保字符串在比较时是一致的。conf
是WireGuard的配置包,用于获取配置数据。
常量定义
const (
deterministicGUIDLabel = "Deterministic WireGuard Windows GUID v1 jason@zx2c4.com"
fixedGUIDLabel = "Fixed WireGuard Windows GUID v1 jason@zx2c4.com"
)
分析:
- 定义了两个字符串常量,用于在生成GUID时作为标签。一个用于确定性GUID (
deterministicGUIDLabel
),另一个用于固定GUID (fixedGUIDLabel
)。
变量定义
var UseFixedGUIDInsteadOfDeterministic = false
分析:
- 这是一个全局变量,默认值为
false
。它是一个“逃生舱口”变量,用于控制是否使用固定GUID而不是确定性GUID。
注释解释
/* All peer public keys and allowed ips are sorted. Length/number fields are
* little endian 32-bit. Hash input is:
*
* label || len(interface name) || interface name ||
* interface public key || number of peers ||
* peer public key || number of peer allowed ips ||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
* ...
* peer public key || number of peer allowed ips ||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
* len(allowed ip string) || allowed ip/cidr in canonical string notation ||
* ...
* ...
*/
分析:
- 这段注释解释了生成GUID时,哈希函数的输入是如何构造的。输入包含标签、接口名称、接口公钥、Peer的公钥、以及允许的IP地址,所有这些信息都经过规范化处理并按特定顺序排序,以确保GUID的确定性。
deterministicGUID
函数
func deterministicGUID(c *conf.Config) *windows.GUID {
b2, _ := blake2s.New256(nil)
if !UseFixedGUIDInsteadOfDeterministic {
b2.Write([]byte(deterministicGUIDLabel))
} else {
b2.Write([]byte(fixedGUIDLabel))
}
// 省略部分代码...
分析:
- 函数
deterministicGUID
用于根据给定的配置c
生成一个确定性的GUID。 b2
是一个BLAKE2s哈希函数的实例,256位输出。- 根据
UseFixedGUIDInsteadOfDeterministic
的值,决定是使用确定性GUID的标签还是固定GUID的标签。
内嵌函数 b2Number
b2Number := func(i int) {
if uint(i) > uint(^uint32(0)) {
panic("length out of bounds")
}
var bytes [4]byte
binary.LittleEndian.PutUint32(bytes[:], uint32(i))
b2.Write(bytes[:])
}
分析:
b2Number
将一个整数转换为小端字节序的4字节表示,并将其写入到哈希输入中。
内嵌函数 b2String
b2String := func(s string) {
bytes := []byte(s)
bytes = norm.NFC.Bytes(bytes)
b2Number(len(bytes))
b2.Write(bytes)
}
分析:
b2String
将一个字符串转换为规范化的字节数组,将其长度写入哈希函数,然后写入字节数组内容。
内嵌函数 b2Key
b2Key := func(k *conf.Key) {
b2.Write(k[:])
}
分析:
b2Key
将一个公钥直接写入哈希函数。
哈希输入构造
b2String(c.Name)
if !UseFixedGUIDInsteadOfDeterministic {
b2Key(c.Interface.PrivateKey.Public())
b2Number(len(c.Peers))
sortedPeers := c.Peers
sort.Slice(sortedPeers, func(i, j int) bool {
return bytes.Compare(sortedPeers[i].PublicKey[:], sortedPeers[j].PublicKey[:]) < 0
})
// 省略部分代码...
}
分析:
- 首先将接口名称写入哈希输入。
- 如果不使用固定GUID,则进一步将接口的公钥和Peer的数量写入哈希。
- 对Peers进行排序,确保GUID的确定性。
GUID生成
return (*windows.GUID)(unsafe.Pointer(&b2.Sum(nil)[0]))
分析:
- 最后,将哈希结果转换为GUID并返回。使用
unsafe.Pointer
进行类型转换,这是Go语言中直接操作内存的方式。
总结
这段代码的核心功能是根据WireGuard的配置文件生成一个确定性GUID,确保同样的配置文件在不同时间或不同机器上生成的GUID是相同的。通过使用BLAKE2s哈希函数和一系列严格排序和规范化的输入,确保GUID的唯一性和一致性。