Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5 #158

Closed
RPRX opened this issue Jan 11, 2021 · 11 comments
Closed

VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5 #158

RPRX opened this issue Jan 11, 2021 · 11 comments
Labels

Comments

@RPRX
Copy link
Member

RPRX commented Jan 11, 2021

VLESS UUID 映射标准:将自定义字符串映射为一个 UUIDv5

这个想法很早就有了,这里感谢 @DuckSoft 提议参照 UUIDv5 标准作为映射方式。

特别注意:切勿把本机制理解为某种加密,而应假定得到映射出的 UUID 即相当于得到原始文本。

1. 范围

长度为 1-30 字节的任意字符串(因为 UUID 字符串长为 32-36 字节,又额外排除了 0 和 31)

UTF-8 编码,比如数字、英文字母、符号等 ASCII 字符占 1 个字节,汉字通常占 3 个字节,emoji 通常占 4 个字节。

  1. 若存在非 ASCII 字符,JSON 等配置文件本身的编码格式必须为 UTF-8。
  2. 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 填 examplefeb54431-301b-52bb-a6dd-e1e93e81bb9e 是等价的。

3. Q & A

Q: 为什么“范围”不包括更长的字符串?
A: 允许使用自定义字符串是方便记忆,过长的字符串也记不住,还不如直接用一个 UUID。

Q: UUIDv5 的 SHA-1 是否存在问题?
A: 不存在问题,因为我们只是需要把限定长度的字符串映射为不重复的 UUID 标识符,按照标准来即可。

补充

  1. 建议 GUI 客户端等提供一个映射工具,任何人都可以创造等价 UUID,满足更多用途。
  2. 对于分享、订阅,暂时规定需要先按此标准映射为 UUIDv5,不分享原始文本。
@RPRX RPRX pinned this issue Jan 11, 2021
@badO1a5A90
Copy link
Member

配置文件是:
服务端仍保持UUID,客户端可以使用 原字符串 / UUID 其中任一方式吗?

@RPRX
Copy link
Member Author

RPRX commented Jan 11, 2021

@badO1a5A90 两边都可以使用任一方式,同出/入站多 UUID 时还可以混用

@badO1a5A90
Copy link
Member

@badO1a5A90 两边都可以使用任一方式,同出/入站多 UUID 时还可以混用

都可以使用任一方式, 那么客户端使用 UUID 也能反映射到服务端的正常字符串?

@RPRX
Copy link
Member Author

RPRX commented Jan 11, 2021

@badO1a5A90 是的,因为这两个是完全等效的,只是配置文件不同,内存中都是同一个 UUID。

无需担心与现在常用的全随机 UUIDv4 冲突,因为标志位不一样,分别是 5 和 4。

@DuckSoft
Copy link
Member

五分钟撸了一个 Web App,但足够用了:https://xray-uuid.ducksoft.site/

@badO1a5A90
Copy link
Member

补充: 对于汉字,Golang使用UTF-8字符集存储,默认用三个字节

@RPRX
Copy link
Member Author

RPRX commented Jan 11, 2021

@badO1a5A90 已补充标准正文

@z826540272
Copy link

用普通话说就是 xray支持自定义密码了

@badO1a5A90
Copy link
Member

建议给 xray uuid 命令增加一个 xray uuid map 命令

如: xray uuid map -id "我爱🍉老师1314"
则输出 : 5783a3e7-e373-51cd-8642-c83782b807c5

@RPRX
Copy link
Member Author

RPRX commented Jan 12, 2021

@badO1a5A90 计划加 -map 参数,xray uuid -map "example"


后续:加了 -i 参数,xray uuid -i "example"

RPRX added a commit that referenced this issue Jan 12, 2021
@RPRX RPRX added the standard label Jan 13, 2021
@secXsQuared
Copy link

多说一句,python里面这么用:

import uuid

UUID_NAMESPACE = uuid.UUID('00000000-0000-0000-0000-000000000000')
uuid.uuid5(UUID_NAMESPACE, "example")

输出:
UUID('feb54431-301b-52bb-a6dd-e1e93e81bb9e')

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
Projects
None yet
Development

No branches or pull requests

5 participants