执行此操作的官方方法是使用版本 5 UUID (RFC 4122 第 4.3 节 https://www.rfc-editor.org/rfc/rfc4122#section-4.3):
4.3 创建基于名称的 UUID 的算法
版本 3 或 5 UUID 用于从“名称”生成 UUID
它们是从某些“名称空间”中提取出来的,并且在某些“名称空间”中是唯一的。
该过程是对字符串进行哈希处理,然后将其插入到 UUID 中。我将仔细遵循这里的规范,但我会标记您可以忽略的部分,它仍然可以正常工作。
正如 Matt 指出的,如果您只需要哈希值,则可以直接使用 SHA。但如果您的系统确实需要 UUID,则可以这样做。
- 定义一个命名空间(这不是完全必要的,但它将确保您的 UUID 是全局唯一的):
let namespace = "com.example.mygreatsystem:"
let inputString = "arandomstring"
let fullString = namespace + inputString
- 对值进行哈希处理。 UUID v5 规范特别要求使用 SHA-1,但请随意在此处使用 SHA-256 (SHA-2)。此处使用 SHA-1 并没有实际的安全问题,但只要有可能,最好迁移到 SHA-2。
import CryptoKit
let hash = Insecure.SHA1.hash(data: Data(fullString.utf8)) // SHA-1 by spec
or
let hash = SHA256.hash(data: Data(fullString.utf8)) // SHA-2 is generally better
- 取数据的前 128 位。 (从 SHA-1 或 SHA-2 哈希中提取任何位子集都是安全的。每个位都是“有效随机的”。)
var truncatedHash = Array(hash.prefix(16))
- 正确设置版本和变体位。这对于大多数用途来说并不重要。我从未遇到过真正解析 UUID 元数据的系统。但这是规范的一部分。如果您使用 v4 随机 UUID 来记录未来的记录(这是当今几乎每个系统的“正常”UUID),那么这将允许您区分哪些是通过散列创建的,哪些是随机的(如果这出于任何原因而重要)。看UUID工具 https://www.uuidtools.com/decode对该格式有一个很好的视觉介绍。
truncatedHash[6] &= 0x0F // Clear version field
truncatedHash[6] |= 0x50 // Set version to 5
truncatedHash[8] &= 0x3F // Clear variant field
truncatedHash[8] |= 0x80 // Set variant to DCE 1.1
let uuidString = NSUUID(uuidBytes: truncatedHash).uuidString