看了 Windows 的 GUID 生成算法,惊掉我下巴。

2021-05-14 17:07:23 +08:00
 3dwelcome

原来没看到官方源代码前,我网上先搜了一下,做足了功课。一般都说 CLSID 的结构定义如下:

typedef struct _GUID {
DWORD Data1; // 随机数
WORD Data2; // 和时间相关
WORD Data3; // 和时间相关
BYTE Data4[8]; // 和网卡 MAC 相关
} GUID;

这看起来很合理,里面除了随机数,即有时间戳保证时间不重复,又有网卡保证物理区域不重复。

微软有专门生成 GUID 的 API, 叫 CoCreateGuid 给程序员调用。我看了代码,底层调用了 UuidCreate()。精彩部分的来了,查了 github 上的微软泄漏 UuidCreate()源代码后,发现整个函数核心就一句:

RpcStatus = GenerateRandomNumber((unsigned char *)Uuid, 16);

是的你没看错,就是生成 16 个随机数给用户。什么时间和网卡,全部都不存在!

是否碰撞?那就听天由命吧。只要冲突概率最小,那就可以忽略。(比如 TCP 包校验也有记录冲突,但同样选择忽略,具体可看这个贴: https://www.v2ex.com/t/767293

7803 次点击
所在节点    分享发现
58 条回复
Jirajine
2021-05-14 17:09:44 +08:00
泄露的是上古版本,简陋也正常。可能现在已经改了?
3dwelcome
2021-05-14 17:19:11 +08:00
@Jirajine 没改,微软的 VS 安装后,会自带一个 Create GUID 生成工具。

我一直天真的以为,这工具是 time base,或者和 Windows 系统时钟有点关系,然而今天发现,就是一个随机数生成器。

那我还不如自己程序来生产随机数呢。完全不加时间相关的变量的 GUID,大规模用起来,心里没底。
0x2CA
2021-05-14 17:22:57 +08:00
GUID 生成单线程生成用事件戳相同的的时间戳计数+1 就好,这样可以保证自己这个机子生成的唯一性
xupefei
2021-05-14 17:32:22 +08:00
Version 4 UUID 就是全部随机数,你看到的带网卡地址的版本是二十年前的了
nannanziyu
2021-05-14 17:41:12 +08:00
xupefei
2021-05-14 17:42:11 +08:00
仔细看了看 lz 的贴,不知从何吐槽。
你又不知道 GenerateRandomNumber 是通过什么当种子的,怎么能说冲突概率大?
3dwelcome
2021-05-14 17:55:41 +08:00
@xupefei
时间戳算法是完全 0 冲突,另一个随机算法冲突概率极小,但小归小,冲突也是客观存在的吧。

只要是个严谨的码农,想都不用想,肯定选完全 0 冲突的算法。

生成慢点无所谓,关键就是在未来某年某月,千万别冲突就好。

@nannanziyu
不去深究,普通码农哪里会知道那么多。

就算安全性 MAC 去掉可以理解,但不能把时间戳也一起去掉吧?

我们以前同事写各种 COM 代码,都是直接那 Create GUID 工具来生成的。也是对微软无比信任,生成界面就算加个可选时间戳参数,或者加一段随机算法说明,那也是极好的。
nannanziyu
2021-05-14 17:59:56 +08:00
@3dwelcome
重新定义普通码农
你质疑一个 API 之前,至少要看下这个 API 自己的文档吧
https://docs.microsoft.com/en-us/windows/win32/api/rpcdce/nf-rpcdce-uuidcreate
UuidCreate 的文档页就说了这个事情
3dwelcome
2021-05-14 18:06:44 +08:00
@nannanziyu

你错了,普通码农只会调用 CoCreateGuid,这才是最常用的。没人会直接调用底层 RPC 的函数,也就是我提到了,你才会去查一下。

你去看看 CoCreateGuid 那个微软 API 文档,就没提到任何有关算法的事情。
kop1989
2021-05-14 18:13:53 +08:00
@3dwelcome #8 没太明白你想表达什么,调用的逻辑不就是 New GUID 》 CoCreateGuid 》 UuidCreate 么……
CoCreateGuid 的文档中也明确写着:

The CoCreateGuid function calls the RPC function UuidCreate, which creates a GUID, a globally unique 128-bit integer. Use CoCreateGuid when you need an absolutely unique number that you will use as a persistent identifier in a distributed environment.To a very high degree of certainty, this function returns a unique value – no other invocation, on the same or any other system (networked or not), should return the same value.
3dwelcome
2021-05-14 18:22:23 +08:00
@kop1989 我的控诉,是要微软给的 GUID 的唯一性得到算法上的保障!而不是返回几个随机数敷衍一下。

普通码农获取 GUID 的两个办法:
1. 用 VS 带的图形界面生成工具。
2. 用 CoCreateGuid 。

这两个方法,都不能在算法上得到保证。API 文档写了“Use CoCreateGuid when you need an absolutely unique number”, 所以我应该无脑信任微软,返回的 GUID 不重复吗?

你加一个 CoCreateGuidEx 函数都好啊,可惜什么都没有。
kop1989
2021-05-14 18:29:22 +08:00
@3dwelcome #10

普通码农难道不应该用 new Guid 么……GUID 类并没有承诺 GUID 一定是 100%不重复的。
Guid 类的说明是这么写的:
SoloCompany
2021-05-14 18:32:22 +08:00
rss 跳进来,发现有点不知所云,然后发现原来是 block 了楼主,解开看了下赶紧关掉,民科好可怕
agagega
2021-05-14 18:35:29 +08:00
这个就是 uuid v4
lovecy
2021-05-14 18:38:54 +08:00
没搞过 C++不知道微软 API 代码怎样
但是凡事一扯上绝对,那个代价基本就是无法承受的。所以人们都得在合理的范围内去靠近绝对,比如根据预估损失来决定安全程度。
所以其实就算发生了重复,也没楼主想象的那么糟 - -
lovecy
2021-05-14 18:41:05 +08:00
@lovecy 其实代码里对这种极小概率重复做一下处理,代价是很低的
zhujinliang
2021-05-14 18:41:45 +08:00
首先,电脑时钟精度、同时产生 GUID 个数、不同电脑时间不同步等,导致时间戳可能相同,甚至不同网卡的 MAC 也可能会相同,不存在你说的 0 冲突

随机数算法肯定是密码学的随机数算法,理论上可保证随机性,否则全世界的加密算法的安全性就打折扣了

有非纯随机部分构成的 GUID,不过是其中一部分用一些其他算法得出的数值代替了随机数,很难说这些算法随机性上优于密码学随机数生成器
wevsty
2021-05-14 18:48:31 +08:00
一个定长的字节块事实上没有任何方法能保证 100%不重复,只能去想办法降低不重复的概率而已。

事实上就算加上时间戳也不能保证 100%不重复,而且要制造一个时间戳成本远低于要随机出相同长度的字节数。
3dwelcome
2021-05-14 18:48:43 +08:00
@lovecy "其实代码里对这种极小概率重复做一下处理,代价是很低的"

微软自己内核用的是完全另外一套算法,用到的是高精度时钟,源代码我都找到了。

算法还读取注册表里防重复的值:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Rpc\UuidSequenceNumber

但问题是不公开,对普通程序员就区分对待,这点我就觉得很不爽。
AstroProfundis
2021-05-14 18:54:54 +08:00
谁给你说的时间戳算法是 0 冲突的让他请你吃饭

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/776972

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX