时间相关的、可重复的伪随机数

Time-dependent, repeatable pseudo-random number

我需要生成一个依赖于当前时间和服务器机密的可重复伪随机数。例如,这种机制应该每分钟产生一个新的伪随机数。下一分钟的随机数应该不容易预测。

此外,我需要以无状态的方式解决这个问题(例如,不将生成的值存储在数据库中)。服务器节点可能会在同一分钟内多次被要求创建这样的数字,并且每次都需要生成相同的数字。此外,多个服务器节点(具有相同的服务器秘密)需要在给定的时间范围内生成相同的数字。所有这一切的目的与解决安全问题(例如令牌生成器)无关,因此并非绝对有必要使用加密安全的 PRNG。

线性同余 PRNG 在使用相同种子初始化时会产生可重复的数字序列,因此我可以结合时间和服务器机密为 PRNG 播种,并获得它产生的第一个随机数以满足我的标准。然而,这种类型的 PRNG 通常使用 next = (current * multiplier + offset) & mask 的简单公式,并且,给定一些已知时间和相应的随机数,似乎并不难找出服务器秘密(然后预测所有未来的数字提前)。

为了使这种逆向工程更加困难,我在获得我使用的“真实”随机数之前,从新播种的 PRNG 中提取并丢弃了固定数量(例如 1000)的值。我的想法是,next = (current * multiplier + offset) & mask 的 1000 个周期的逆向工程比仅一个周期的逆向工程要困难得多。

我想知道我的想法是否正确。根据播种后的第 1000 个值确定线性同余 PRNG 的种子是否真的比新播种生成器的第一个值更难?如果是这样,在停止增加难度之前,多少次迭代就足够了?

如果我完全不在这里,有什么更好的选择可以满足上述标准(可重复性、无国籍)?

在某种程度上,这就是 Time-based one-time 密码 (TOTPs) 的工作原理,因此您可以使用类似的解决方案。

要获取每N秒变化一次的时间值,可以使用下面的公式。

floor(timestamp / N)

然后,您可以将其转换为字符串或将其解释为字节。只需将它传递给 HMAC 之类的东西,以便将它变成 pseudo-random 值。

HMAC(SecretKey, floor(timestamp / N))

Python 中有一个简单的实现。这在其他语言中也应该非常相似。

import hmac
import time

# Duration that each value lasts, in seconds
duration = 60

# Generate randomly instead of using a phrase
secret_key = b"very epic secret key"

timestamp = int(time.time())
timestamp = int(timestamp / duration)
timestamp = timestamp.to_bytes(8, "big")

value = hmac.digest(secret_key, timestamp, "sha256")
print(value.hex())

您也可以将该值转为整数,或以其他方式使用。

value_int = int.from_bytes(value, "big")