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

问题描述

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

我不在乎从UUID取回输入字符串。我需要用它来确定性地转换数据库中的键,作为迁移的一部分,以使并行执行操作的不同客户端收敛到相同的结果。

this post的可接受答案具有Java答案,我需要Swift版本。

解决方法

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

您要描述的是哈希值,而不是UUID。 UUID中的U代表 unique ;您每次都会得到一个不同的。例如,SHA-1散列对于相同的字符串相同,而对于不同的字符串则不同。

,

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

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

版本3或5 UUID用于从“名称”生成UUID 是从“名称空间”中提取出来的,并且在其中是唯一的。

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

如马特所言,如果您只需要哈希,则可以直接使用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