从相同的字符串生成相同的UUID

Coc*_*uts 3 string uuid ios swift

我想从随机字符串生成一个UUID字符串,以便相同的输入字符串生成相同的UUID。

我不关心从 UUID 获取输入字符串。作为迁移的一部分,我需要它来确定性地转换数据库中的密钥,以便并行操作的不同客户端收敛到相同的结果。

这篇文章接受的答案有 Java 中的答案,我需要 Swift 版本。

Rob*_*ier 12

执行此操作的官方方法是使用版本 5 UUID(RFC 4122 第 4.3 节):

4.3 创建基于名称的 UUID 的算法

版本 3 或 5 UUID 旨在从“名称”生成 UUID,这些“名称”取自某些“名称空间”,并且在某些“名称空间”中是唯一的。

该过程是对字符串进行哈希处理,然后将其插入到 UUID 中。我将仔细遵循这里的规范,但我会标记您可以忽略的部分,它仍然可以正常工作。

正如 Matt 指出的,如果您只需要哈希值,则可以直接使用 SHA。但如果您的系统确实需要 UUID,则可以这样做。

  • 定义一个命名空间(这不是完全必要的,但它将确保您的 UUID 是全局唯一的):
let namespace = "com.example.mygreatsystem:"
Run Code Online (Sandbox Code Playgroud)
  • 将其与你的字符串结合起来
let inputString = "arandomstring"
let fullString = namespace + inputString
Run Code Online (Sandbox Code Playgroud)
  • 对值进行哈希处理。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
Run Code Online (Sandbox Code Playgroud)

或者

let hash = SHA256.hash(data: Data(fullString.utf8)) // SHA-2 is generally better
Run Code Online (Sandbox Code Playgroud)
  • 取数据的前 128 位。(从 SHA-1 或 SHA-2 哈希中提取任何位子集都是安全的。每个位都是“有效随机的”。)
var truncatedHash = Array(hash.prefix(16))
Run Code Online (Sandbox Code Playgroud)
  • 正确设置版本和变体位。这对于大多数用途来说并不重要。我从未遇到过真正解析 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
Run Code Online (Sandbox Code Playgroud)
  • 最后,计算您的 UUID:
let uuidString = NSUUID(uuidBytes: truncatedHash).uuidString
Run Code Online (Sandbox Code Playgroud)