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

问题描述 投票:0回答:3

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

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

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

ios swift string uuid
3个回答
11
投票

执行此操作的官方方法是使用版本 5 UUID(RFC 4122 第 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

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

2
投票

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

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


0
投票

UUIDKit @Nicolas Bachschmidt 在 Swift 中有完整的 UUID v5 实现。

它还支持 RFC 1808 中的所有命名空间,例如 NameSpace_URL:

import UUIDKit
UUID.v5(name: "http://example.com/index.html", namespace: .url)

因为它遵循规范,所以它使用 SHA-1 并且输出与其他平台实现相匹配,所以上面的行输出与此 python 代码相同的值:

import uuid
uuid.uuid5(uuid.NAMESPACE_URL, 'http://example.com/index.html')
© www.soinside.com 2019 - 2024. All rights reserved.