伪随机数示例

为了更好地理解计算机编程中伪随机数是如何生成的,可以试运行下面的 Python 代码。它会生成 5 个范围为 [10...20] 的伪随机数:

import hashlib, time

startSeed = str(time.time()) + '|'
min = 10
max = 20
for i in range(5):
    nextSeed = startSeed + str(i)
    hash = hashlib.sha256(nextSeed.encode('ascii')).digest()
    bigRand = int.from_bytes(hash, 'big')
    rand = min + bigRand % (max - min + 1)
    print(nextSeed, bigRand, '-->', rand)

运行上述代码示例:https://repl.it/@nakov/Pseudo-random-numbers-in-Python

上述代码会生成一个依赖时间、因而可预测的伪随机序列

1539884529.7564313|0 80821949188459167822103620715837790870744533466506114260335306835341654043374 --> 20
1539884529.7564313|1 74025479792630401388590516952955656999942018130178317853592496371994668720404 --> 12
1539884529.7564313|2 82017697577161203981429946799250236982499988253633196542465974577893633076425 --> 18
1539884529.7564313|3 107386997066995629290834465394867359239275712194747910247567090891223949362198 --> 13
1539884529.7564313|4 83874630241630198317549470506043001102325518306912594861433838548293113930135 --> 10

初始伪随机种子取自当前时间。序列中的第一个伪随机数来自初始种子加数字 0 后的 SHA-256 哈希,第二个伪随机数来自初始种子加数字 1 后的哈希,以此类推。要得到特定范围 [min...max] 内的输出,需要用 256 位哈希除以 (max - min + 1) 取余,再加上 min。数字 istartSeed 的值共同构成随机数生成器的内部状态,该状态会随每个新随机数而变化。

上述伪随机数生成器基于 SHA-256 函数的随机统计分布。理论上,每个可能数值被生成的概率都相同。

创建安全随机数生成器

上述随机数生成器并不安全,因为它没有使用不可预测的熵源进行初始化。下面来修复这个问题

我们将根据键盘事件初始化随机性。系统会要求用户输入 5 次,并将每次用户输入的精确时间与输入数据组合成初始随机性(种子)。收集到的文本熵可以通过 SHA-256 哈希压缩为 256 位。完成熵的收集并计算起始种子后,再使用与前一个示例相同的逻辑,生成 5 个范围为 [10...20] 的随机数。下面是一个 Python 实现示例:

import hashlib, time, binascii

entropy = ''
for i in range(5):
    s = input("Enter something [" + str(i+1) + " of 5]: ")
    entropy = entropy + s + '|' + str(time.time()) + '|'
print("Entropy:", entropy)
startSeed = str(binascii.hexlify(hashlib.sha256(entropy.encode('ascii')).digest()))[2:-1]
print("Start seed = SHA-256(entropy) =", startSeed)

min = 10
max = 20
for i in range(5):
    nextSeed = startSeed + '|' + str(i)
    hash = hashlib.sha256(nextSeed.encode('ascii')).digest()
    bigRand = int.from_bytes(hash, 'big')
    rand = min + bigRand % (max - min + 1)
    print(nextSeed, bigRand, '-->', rand)

运行上述代码示例:https://repl.it/@nakov/secure-random-generator-in-Python

上述代码的输出示例如下:

Enter something [1 of 5]: first
Enter something [2 of 5]: second
Enter something [3 of 5]: random text
Enter something [4 of 5]: dfasfdasfs
Enter something [5 of 5]: last
Entropy: first|1539885709.4494743|second|1539885713.687703|random text|1539885721.5754962|dfasfdasfs|1539885724.40904|last|1539885726.1286101|
Start seed = SHA-256(entropy) = f8a4eaceb16156b1a23f4b6d08e54665ffa4822949b22e01d6de4c5daae965e3
f8a4eaceb16156b1a23f4b6d08e54665ffa4822949b22e01d6de4c5daae965e3|0 84482770259566839097936866229004786554948913905882724148636325987196754263481 --> 19
f8a4eaceb16156b1a23f4b6d08e54665ffa4822949b22e01d6de4c5daae965e3|1 67001454659030164457342421011672033052466168976555224352709830050538321411120 --> 14
f8a4eaceb16156b1a23f4b6d08e54665ffa4822949b22e01d6de4c5daae965e3|2 103739181507291072572315034266940107849472122762876847172454548630886082729227 --> 12
f8a4eaceb16156b1a23f4b6d08e54665ffa4822949b22e01d6de4c5daae965e3|3 3011033199204097839903859902789759740091959530467456042709372597822032778153 --> 16
f8a4eaceb16156b1a23f4b6d08e54665ffa4822949b22e01d6de4c5daae965e3|4 100466094724924763659843669256673300207383922129676800217664465341535622195997 --> 16

请注意,收集到的熵很难预测。攻击者必须猜出用户输入的全部文本,还要猜出 5 次输入各自的精确时间。如果将上述过程从 5 次增加到 20 次,预测难度会进一步提高,因为收集到的熵更多。

一些密码学软件在生成密钥、密码和其他随机数据时会采用与上述代码示例类似的技术。现在你已经知道原因:以不可预测的方式收集熵。

results matching ""

    No results matching ""