首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在python中加密安全的伪随机混洗列表或数组

在python中加密安全的伪随机混洗列表或数组
EN

Stack Overflow用户
提问于 2021-03-08 19:29:06
回答 1查看 388关注 0票数 3

我需要一个混洗函数,使用CSPRNG (加密安全伪随机数生成器),可以手动播种相同的种子相同的输出。

内置的random.shuffle() in Python可以手动设定种子,但它是not suitable for cryptographic use,将在Python3.11版本中删除。

据我所知,Crypto.Random.random.shuffle() from PyCryptodome不接受种子。

目前,我已经满足于由内置的random.shuffle()函数使用的Mersenne Twister来处理数字列表,但这远远不是理想的。作为内置的numpy.random.shuffle is not suitable for cryptographic purposes,混洗numpy数组也很受欢迎。数组/列表可能包含超过100亿个元素,因此性能和随机性是关键。

创可贴代码如下。

代码语言:javascript
运行
复制
import numpy as np
from random import seed, shuffle
array = np.arange(10) # [0 1 2 3 4 5 6 7 8 9]
print(array)
seed(1)
shuffle(array)
print(array) # [6 8 9 7 5 3 0 4 1 2]
EN

回答 1

Stack Overflow用户

发布于 2021-03-14 09:06:50

CSPRNG通常在重新播种等方面存在问题,在操作期间从操作系统内的熵池中提取熵。因此,最好使用流密码,例如计数器模式下的AES。

那么同样重要的是,始终以相同的方式执行混洗操作。类似地,生成的比特流中的数字应该始终以相同的方式操作。如果对这些进行了优化或更改,结果将是不同的洗牌,从而破坏方案。

最后,您最好自己对此进行编程,这样就可以确保方法契约背后的代码不会更改。

这样做的要求是:

  • 具有密钥大小的种子的流密码;
  • 是“拒绝采样”的实现,以获得某个范围内的随机数;
  • Fisher-Yates shuffle,以创建完全随机的随机洗牌。

如果大小不符合流密码,则可以对种子进行散列并获取最左边的字节。

该想法的演示(未经过充分测试或精心设计):

代码语言:javascript
运行
复制
import numpy as np
from Crypto.Cipher import ChaCha20
from Crypto.Random import get_random_bytes

array = np.arange(100) # [0 1 2 3 4 5 6 7 8 9]

seed = bytes([0x00]) * 32 # use SHA-256 to hash different size seeds

nonce_rfc7539 = bytes([0x00]) * 12
cipher = ChaCha20.new(key=seed, nonce=nonce_rfc7539)
zerobuf = bytes([0x00]) * 5

def sample(max):
    # rejection sampling using rand(0..n * max) % max
    # the value 2 is in there to make sure the number of bits is at least
    # two higher than max, so that the chance of each candicate succeeding
    # is higher
    stream_size = (max.bit_length() + 2 + 7) // 8
    max_stream_value = 1 << (stream_size * 8)
    max_candidate = max_stream_value - max_stream_value % max
    while True:
        stream = cipher.encrypt(zerobuf[0:stream_size])
        candidate = int.from_bytes(stream, "big")
        if (candidate < max_candidate):
            break
    return candidate % max

def shuffle(list):
    # do the Fisher-Yates shuffle
    for i in range(len(list) - 1, 0, -1):
        j = sample(i + 1)
        list[i],list[j] = list[j],list[i]

# test only
print(array)
for i in range(0, 100):
    shuffle(array)
    print(array)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66528995

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档