我不会担心循环和这些ord
东西,所以让我们把它扔掉,看看剩下的。
另外,我不明白“我需要帮助确定该算法的 unicode 部分的全部可能输出”,因为该算法没有 Unicode 部分,或者实际上代码中没有任何 Unicode 部分。但我可以帮助你弄清楚整个事情的总可能输出。我们将逐步简化它。
第一的:
li=[]
for a in range(900,7899):
li.append(a)
这完全等同于:
li = range(900, 7899)
同时:
li[random.randint(0,7000)]
因为li
恰好是 6999 个元素长,所以这与random.choice(li)
.
并且,将最后两个放在一起,这意味着它相当于:
random.choice(range(900,7899))
…相当于:
random.randrange(900,7899)
但是等等,那又如何random.shuffle(li, random.random)
呢?好吧(忽略第二个参数已经是默认值的事实random.random
),选择已经是随机的,但不是加密的,所以添加另一个 shuffle 不会改变这一点。如果有人试图从数学上预测你的 RNG,用相同的 RNG 添加一个更简单的 shuffle 不会使其更难预测(而基于结果添加更多的工作可能会使计时攻击更容易)。
事实上,即使你使用了一个子集li
而不是整个东西,也没有办法让你的代码更加不可预测。你将有一个更小的值范围来蛮力通过,没有任何好处。
所以,你的整个事情就变成了这样:
sent = os.urandom(random.randrange(900, 7899))
可能的输出是:长度在 900 到 7899 字节之间的任何字节字符串。
长度是随机的,并且大致均匀分布,但在密码学不可预测的意义上它不是随机的。幸运的是,这可能并不重要,因为大概攻击者可以看到他正在处理的字节数,而不必预测它。
内容是随机的,既均匀分布又在密码学上不可预测,至少在您的系统的范围内urandom
是这样。
这就是所有要说的。
但是,您使阅读、编写、维护和思考变得更加困难这一事实给您带来了重大劣势,而攻击者却没有任何补偿劣势。
因此,只需使用单线。
我认为在您的后续问题中,您是在询问 900-7898 字节的随机数据有多少个可能的值。
那么,900 字节有多少个值?256**900
. 901多少钱?256**901
. 所以,答案是:
sum(256**i for i in range(900, 7899))
……大约是2**63184
, 或10**19020
。
所以,63184 位的安全性听起来很令人印象深刻,对吧?可能不是。如果您的算法没有缺陷,那么 100 位就超出了您的需要。如果您的算法有缺陷(当然是有缺陷,因为它们都是),盲目地向它扔数千位将无济于事。
另外,请记住,加密的全部意义在于2**N
,对于一些较大的 N,您希望破解比合法解密慢。因此,使合法解密慢得多会使您的方案变得更糟。这就是为什么每个现实生活中的加密方案都使用几百位密钥、盐等(是的,公钥加密使用几千位作为其密钥,但那是因为它的密钥不是随机分布的。而且通常,您使用这些密钥所做的一切都是为了加密随机生成的几百位的会话/文档密钥。)
最后一件事:我知道你说过忽略ord
,但是......
首先,您可以将整个部分写为intsent=sum(bytearray(sent))
.
但是,更重要的是,如果你对这个缓冲区所做的只是总结它,你就会使用大量的熵来生成一个熵少得多的数字。(想一想这应该很明显。如果有两个单独的字节,则有 65536 种可能性;如果将它们加在一起,则只有 512 种可能性。)
此外,通过生成几千个单字节随机数并将它们相加,这基本上是正态或高斯分布的非常接近的近似值。(如果你是一名 D&D 玩家,想想 3D6 如何比 3 和 18 更频繁地给出 10 和 11……以及 3D6 比 2D6 更是如此……然后考虑 6000D6。)但是,通过使字节数范围从 900 到 7899,您将其拉平,使其趋向从 700*127.5 到 7899*127.5 的均匀分布。无论如何,如果您可以描述您想要获得的分布,您可能可以直接生成它,而不会浪费所有这些 urandom 熵和计算。
值得注意的是,很少有加密应用程序可以利用这么多的熵。甚至像生成 SSL 证书这样的东西也使用 128-1024 位,而不是 64K 位。
你说:
试图杀死密码。
如果您尝试对密码进行加密,以便将其存储在磁盘上或通过网络发送,那么这几乎总是错误的方法。您想使用某种零知识证明——存储密码的哈希值,或者使用质询-响应而不是发送数据等。如果您想构建“让我保持登录功能”,请通过实际保持用户登录(创建并存储会话身份验证令牌,而不是存储密码)。有关基础知识,请参阅 Wikipedia 文章密码。
有时,您确实需要加密和存储密码。例如,也许您正在为用户构建一个“密码锁”程序来存储一堆密码。或者是一个设计糟糕的服务器(或 70 年代设计的协议)的客户端。管他呢。如果您需要这样做,您需要使用相对较小的密钥进行一层加密(请记住,典型的密码本身只有大约 256 位长,实际信息不到 64 位,因此使用绝对没有任何好处一个密钥的长度是它们的数千倍)。使它更安全的唯一方法是使用更好的算法——但实际上,加密算法几乎永远不会成为最好的攻击面(除非你自己尝试设计一个);将精力投入到基础设施最薄弱的领域,
你问:
urandom 的输出是否也依赖于它正在使用的汇编程序?
嗯……没有它正在使用的汇编程序,我想不出你提到的任何其他任何有意义的东西。
所urandom
依赖的只是您的操作系统的熵池和 PRNG。正如文档所说,urandom
只需读取/dev/urandom
(Unix)或调用CryptGenRandom
(Windows)。
如果您想确切地知道它在您的系统上是如何工作的,或者在 MSDN 中man urandom
查找。CryptGenRandom
但是所有主要的操作系统都可以产生足够的熵并将其混合得足够好,您基本上不必担心这一点。在幕后,它们都有效地拥有一些熵池,以及一些用于“拉伸”该池的加密安全 PRNG,以及一些收集任何熵的内核设备(Linux、Windows)或用户空间守护程序(OS X)。从用户操作等不可预知的事情中获取,将其混合到池中。
那么,这取决于什么?假设您没有任何浪费大量熵的应用程序,并且您的机器没有受到损害,并且您的操作系统没有重大安全漏洞……它基本上不依赖于任何东西。或者,换句话说,它取决于这三个假设。
引用linux 手册页,/dev/urandom
对于“除了长寿命的 GPG/SSL/SSH 密钥之外的所有内容”已经足够了。(在许多系统上,如果有人试图运行一个程序,就像你的代码一样,读取数千字节的urandom
.可以处理。)
嗯 python 通过它自己的解释器,所以我不确定它是如何发挥作用的
它没有。显然,调用urandom(8)
在系统调用之前和之后做了一堆额外的事情来读取 8 个字节,/dev/urandom
而不是你在 C 问题中所做的……但实际的系统调用是相同的。所以urandom
设备甚至无法区分两者之间的区别。
但我只是问 urandom 是否会在不同的架构上产生不同的结果。
嗯,是的,很明显。例如,Linux 和 OS X 使用完全不同的 CSPRNG 和不同的熵累积方式。但重点是它应该是不同的,即使在同一台机器上,或者在同一台机器上的不同时间。只要它在每个平台上都能产生“足够好”的结果,那才是最重要的。
例如,处理器\组装器\解释器是否会导致特定于所述架构的指纹,这在随机可预测的范围内?
如上所述,解释器最终会进行与编译代码相同的系统调用。
至于汇编器……可能在任何地方都不涉及任何汇编器。Python 解释器、随机设备、熵收集服务或驱动程序等的相关部分很可能是用 C 编写的。即使它们是在汇编中手工编码的,汇编中编码的全部意义在于你几乎直接控制生成的机器代码,因此不同的汇编程序不会有任何区别。
处理器在某种意义上可能会留下“指纹”。例如,我敢打赌,如果您知道 RNG 算法并直接控制其状态,您可以编写代码来区分 x86 与 x86_64,或者甚至可能是一代 i7 与另一代,基于时间。但我不确定这对你有什么好处。该算法仍然会从相同的状态生成相同的结果。用于 RNG 的实际攻击是关于攻击熵累加器和/或熵估计器的算法。
无论如何,我愿意赌一大笔钱,urandom
比起你自己想出的任何东西,你都更安全。如果你需要更好的东西(而你不需要),实现——或者,更好的是,找到一个经过良好测试的实现——<a href="http://en.wikipedia.org/wiki/Fortuna_%28PRNG%29" rel="nofollow">Fortuna 或BBS,或购买硬件熵生成设备。