VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5
RPRX opened this issue · 11 comments
VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5
这个想法很早就有了,这里感谢 @DuckSoft 提议参照 UUIDv5 标准作为映射方式。
特别注意:切勿把本机制理解为某种加密,而应假定得到映射出的 UUID 即相当于得到原始文本。
1. 范围
长度为 1-30 字节的任意字符串(因为 UUID 字符串长为 32-36 字节,又额外排除了 0 和 31)
UTF-8 编码,比如数字、英文字母、符号等 ASCII 字符占 1 个字节,汉字通常占 3 个字节,emoji 通常占 4 个字节。
- 若存在非 ASCII 字符,JSON 等配置文件本身的编码格式必须为 UTF-8。
- Xray-core 内置自动映射,包括 VMess。其它 VLESS 实现需要参照此标准进行映射。
2. 方式
选取 16 字节的空 UUID 作为 namespace,自定义字符串即为 name,遵循 UUIDv5 标准进行一系列变换,最终生成 UUIDv5。
我参考 go.uuid 库写了个简单的实现,并输出同一个 UUIDv5 的两种形式:
package main
import (
"crypto/sha1"
"encoding/hex"
"fmt"
)
func main() {
var Nil [16]byte
var str = "example"
h := sha1.New()
h.Write(Nil[:])
h.Write([]byte(str))
u := h.Sum(nil)[:16]
u[6] = (u[6] & 0x0f) | (5 << 4)
u[8] = (u[8]&(0xff>>2) | (0x02 << 6))
fmt.Println("UUIDv5:", u)
buf := make([]byte, 36)
hex.Encode(buf[0:8], u[0:4])
buf[8] = '-'
hex.Encode(buf[9:13], u[4:6])
buf[13] = '-'
hex.Encode(buf[14:18], u[6:8])
buf[18] = '-'
hex.Encode(buf[19:23], u[8:10])
buf[23] = '-'
hex.Encode(buf[24:], u[10:])
fmt.Println("UUIDv5:", string(buf))
}
字符串为 example
时,以上代码的输出为:
UUIDv5: [254 181 68 49 48 27 82 187 166 221 225 233 62 129 187 158]
UUIDv5: feb54431-301b-52bb-a6dd-e1e93e81bb9e
也就是说下一个版本的 Xray-core 中,VLESS/VMess id 填 example
和 feb54431-301b-52bb-a6dd-e1e93e81bb9e
是等价的。
3. Q & A
Q: 为什么“范围”不包括更长的字符串?
A: 允许使用自定义字符串是方便记忆,过长的字符串也记不住,还不如直接用一个 UUID。
Q: UUIDv5 的 SHA-1 是否存在问题?
A: 不存在问题,因为我们只是需要把限定长度的字符串映射为不重复的 UUID 标识符,按照标准来即可。
补充
- 建议 GUI 客户端等提供一个映射工具,任何人都可以创造等价 UUID,满足更多用途。
- 对于分享、订阅,暂时规定需要先按此标准映射为 UUIDv5,不分享原始文本。
配置文件是:
服务端仍保持UUID,客户端可以使用 原字符串 / UUID 其中任一方式吗?
@badO1a5A90 两边都可以使用任一方式,同出/入站多 UUID 时还可以混用
@badO1a5A90 两边都可以使用任一方式,同出/入站多 UUID 时还可以混用
都可以使用任一方式, 那么客户端使用 UUID 也能反映射到服务端的正常字符串?
@badO1a5A90 是的,因为这两个是完全等效的,只是配置文件不同,内存中都是同一个 UUID。
无需担心与现在常用的全随机 UUIDv4 冲突,因为标志位不一样,分别是 5 和 4。
五分钟撸了一个 Web App,但足够用了:https://xray-uuid.ducksoft.site/
补充: 对于汉字,Golang使用UTF-8字符集存储,默认用三个字节
@badO1a5A90 已补充标准正文
用普通话说就是 xray支持自定义密码了
建议给 xray uuid 命令增加一个 xray uuid map 命令
如: xray uuid map -id "我爱🍉老师1314"
则输出 : 5783a3e7-e373-51cd-8642-c83782b807c5
多说一句,python里面这么用:
import uuid
UUID_NAMESPACE = uuid.UUID('00000000-0000-0000-0000-000000000000')
uuid.uuid5(UUID_NAMESPACE, "example")
输出:
UUID('feb54431-301b-52bb-a6dd-e1e93e81bb9e')