从相同的字符串生成相同的 UUID
Generate the same UUID from the same String
我想从随机字符串生成一个 UUID 字符串,以便相同的输入字符串生成相同的 UUID。
我不关心从 UUID 取回输入字符串。作为迁移的一部分,我需要它来确定性地转换数据库中的键,以便并行操作的不同客户端收敛到相同的结果。
的已接受答案在 Java 中有答案,我需要 Swift 版本。
I would like to generate a UUID string from a random string, so that the same input string generates the same UUID.
您描述的是哈希值,而不是 UUID。 UUID中的U代表unique;你每次都会得到一个不同的。 SHA-1 散列(例如)对于相同的字符串是相同的,对于不同的字符串是不同的。
执行此操作的官方方法是使用版本 5 UUID (RFC 4122 Section 4.3):
4.3 Algorithm for Creating a Name-Based UUID
The version 3 or 5 UUID is meant for generating UUIDs from "names"
that are drawn from, and unique within, some "name space".
该过程是对您的字符串进行哈希处理,然后将其插入到 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
或
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),那么这将允许您区分哪些是通过散列创建的,哪些是随机的,如果出于任何原因这很重要的话。有关该格式的直观介绍,请参阅 UUIDTools。
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
- 最后,计算您的 UUID:
let uuidString = NSUUID(uuidBytes: truncatedHash).uuidString
我想从随机字符串生成一个 UUID 字符串,以便相同的输入字符串生成相同的 UUID。
我不关心从 UUID 取回输入字符串。作为迁移的一部分,我需要它来确定性地转换数据库中的键,以便并行操作的不同客户端收敛到相同的结果。
I would like to generate a UUID string from a random string, so that the same input string generates the same UUID.
您描述的是哈希值,而不是 UUID。 UUID中的U代表unique;你每次都会得到一个不同的。 SHA-1 散列(例如)对于相同的字符串是相同的,对于不同的字符串是不同的。
执行此操作的官方方法是使用版本 5 UUID (RFC 4122 Section 4.3):
4.3 Algorithm for Creating a Name-Based UUID
The version 3 or 5 UUID is meant for generating UUIDs from "names" that are drawn from, and unique within, some "name space".
该过程是对您的字符串进行哈希处理,然后将其插入到 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
或
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),那么这将允许您区分哪些是通过散列创建的,哪些是随机的,如果出于任何原因这很重要的话。有关该格式的直观介绍,请参阅 UUIDTools。
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
- 最后,计算您的 UUID:
let uuidString = NSUUID(uuidBytes: truncatedHash).uuidString