问题描述
我想从随机字符串生成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