gpt4 book ai didi

linux - 关于Python3.6 os.urandom/os.getrandom/secrets的问题

转载 作者:太空狗 更新时间:2023-10-29 12:11:37 26 4
gpt4 key购买 nike

请引用ossecrets的文档:

os.getrandom(大小,标志= 0)

Get up to size random bytes. The function can return less bytes than requested.

getrandom() relies on entropy gathered from device drivers and other sources of environmental noise.



那么这是否意味着它来自 /dev/random

On Linux, if the getrandom() syscall is available, it is used in blocking mode: block until the system urandom entropy pool is initialized (128 bits of entropy are collected by the kernel).



因此,要确保内部状态不好的内核CSPRNG是 而不是,我应该使用 os.getrandom()吗?由于该函数返回的字节数少于请求的字节数,因此应将应用程序级别的CSPRNG作为以下命令运行
def rng():
r = bytearray()
while len(r) < 32:
r += os.getrandom(1)
return bytes(r)

确保最大的安全性?我明确希望所有在初始化urandom熵池之前无法支持阻塞的系统都无法运行,并且无法运行支持该程序的系统。这是因为即使从启动时熵为零的实时CD运行,该软件也必须安全。

还是阻塞意味着如果我执行 os.getrandom(32),程序将在必要时一直等待直到收集到32个字节为止?

The flags argument is a bit mask that can contain zero or more of the following values ORed together: os.GRND_RANDOM and GRND_NONBLOCK.



有人可以请ELI5如何运作吗?

os.urandom(大小)

On Linux, if the getrandom() syscall is available, it is used in blocking mode: block until the system urandom entropy pool is initialized (128 bits of entropy are collected by the kernel).



因此,urandom悄无声息地退回到了不阻塞的CSPRNG上,后者不知道它在较旧的Linux内核版本中是内部种子状态吗?

Changed in version 3.6.0: On Linux, getrandom() is now used in blocking mode to increase the security.



这和os.getrandom()有关吗?是较低级别的通话吗?两者一样吗?

os.GRND_NONBLOCK

By default, when reading from /dev/random, getrandom() blocks if no random bytes are available, and when reading from /dev/urandom, it blocks if the entropy pool has not yet been initialized.



所以它是os.getrandom(size,flag = 0)中的0标志吗?

os.GRND_RANDOM

If this bit is set, then random bytes are drawn from the /dev/random pool instead of the /dev/urandom pool.



ORing os.getrandom()标志是什么意思? os.getrandom(flags = 1)如何说明我是否打算启用os.GRND_NONBLOCK或os.GRND_RANDOM。还是我需要像这样设置它:
os.GRND_RANDOM = 1
os.getrandom(32) # or use the rng() defined above

secret 模块

The secrets module is used for generating cryptographically strong random numbers suitable for managing data such as passwords, account authentication, security tokens, and related secrets.



唯一的生成随机字节的方法是
secrets.token_bytes(32)

The secrets module provides access to the most secure source of randomness that your operating system provides.



所以这应该意味着它是带有 os.getrandom后备的 os.urandom?因此,如果您希望“如果无法评估内部状态而优雅退出”,这不是一个好选择吗?

To be secure against brute-force attacks, tokens need to have sufficient randomness. Unfortunately, what is considered sufficient will necessarily increase as computers get more powerful and able to make more guesses in a shorter period. As of 2015, it is believed that 32 bytes (256 bits) of randomness is sufficient for the typical use-case expected for the secrets module.



但是,阻塞在内部状态的128位而不是256位处停止。出于某种原因,大多数对称密码具有256位版本。

因此,我应该确保在阻止模式下使用 /dev/random,以确保在生成密钥时内部状态已达到256位?

所以tl; dr

在Python3.6(3.17或更高版本)的实时发行版中,在程序执行开始时内核CSPRNG内部状态的熵为零的Python3.6中生成256位密钥的最安全方法是什么?

最佳答案

经过研究后,我可以回答我自己的问题。os.getrandom是Linux内核3.17及更高版本中提供的getrandom() syscall的包装。该标志是一个数字(0、1、2或3),它通过以下方式对应于位掩码:
使用ChaCha20 DRNG获得GETRANDOM
os.getrandom(32,标志= 0)

GRND_NONBLOCK =  0  (=Block until the ChaCha20 DRNG seed level reaches 256 bits)
GRND_RANDOM = 0 (=Use ChaCha20 DRNG)
= 00 (=flag 0)
当不需要与Python 3.5和3.17之前的内核向后兼容时,这是在所有平台(包括现场发行版)上与所有Python 3.6程序一起使用的一个很好的默认值。
PEP 524 claims不正确

On Linux, getrandom(0) blocks until the kernel initialized urandom with 128 bits of entropy.


根据 page 84 of the BSI report的说明,在引导期间,内核模块的 get_random_bytes()函数 的调用者使用128位限制,如果是,则该代码是为了正确等待 add_random_ready_callback()函数的触发而进行的。 (不等待就意味着 get_random_bytes()可能返回不安全的随机数。)根据第112页

When reaching the state of being fully seeded and thus having the ChaCha20 DRNG seeded with 256 bits of entropy -- the getrandom system call unblocks and generates random numbers.


因此,在ChaCha20 DRNG完全种子化之前,GETRANDOM()永远不会返回随机数。
os.getrandom(32,标志= 1)
GRND_NONBLOCK =  1  (=If the ChaCha20 DRNG is not fully seeded, raise BlockingIOError instead of blocking)
GRND_RANDOM = 0 (=Use ChaCha20 DRNG)
= 01 (=flag 1)
如果应用程序在等待ChaCha20 DRNG完全播种时需要执行其他任务,则该功能很有用。 ChaCha20 DRNG几乎总是在引导期间完全播种,因此 flags=0最有可能是更好的选择。需要围绕它的try-except逻辑。
GETRANDOM与blocking_pool
也可以通过 blocking_pool设备文件访问 /dev/random。设计池时要考虑到熵耗尽的想法。此想法仅在尝试创建一次性填充(争取信息理论安全性)时适用。为此目的, blocking_pool中的熵质量尚不清楚,并且性能确实很差。对于其他用途,正确播种的DRNG足够了。 blocking_pool可能更安全的唯一情况是使用4.17之前的内核,这些内核在编译时设置了 CONFIG_RANDOM_TRUST_CPU标志,并且CPU HWRNG碰巧有后门。由于在那种情况下,ChaCha20 DRNG最初是使用 RDSEED/ RDRAND指令进行播种的,因此不良的CPU HWRNG将是一个问题。但是,根据BSI报告的第134页:

[As of kernel version 4.17] The Linux-RNG now considers the ChaCha20 DRNG fully seeded after it received 128 bit of entropy from the noise sources. Previously it was sufficient that it received at least 256 interrupts.


因此,直到还从 input_pool混合了熵之后,才将ChaCha20 DRNG视为完全播种,该熵将来自所有LRNG噪声源的随机事件合并在一起。
通过将 os.getrandom()23标志一起使用,熵来自 blocking_pool,后者从 input_pool接收熵,继而又从几个其他噪声源接收熵。 ChaCha20 DRNG也从 input_pool重新播种,因此CPU RNG对DRNG状态没有永久控制权。一旦发生这种情况,ChaCha20 DRNG和 blocking_pool一样安全。
os.getrandom(32,标志= 2)
GRND_NONBLOCK =  0  (=Return 32 bytes or less if entropy counter of blocking_pool is low. Block if no entropy is available.)
GRND_RANDOM = 1 (=Use blocking_pool)
= 10 (=flag 2)
这需要一个运行该函数的外部循环,并将返回的字节存储到缓冲区中,直到缓冲区大小为32个字节为止。这里的主要问题是由于 blocking_pool的阻塞行为,获取所需的字节可能需要很长时间,尤其是在其他程序也从同一syscall或 /dev/random请求随机数的情况下。另一个问题是,与使用 os.getrandom(32, flags=2)标志相比,使用 3的循环花费更多的空闲时间等待随机字节(请参见下文)。
os.getrandom(32,标志= 3)
GRND_NONBLOCK =  1  (=return 32 bytes or less if entropy counter of blocking_pool is low. If no entropy is available, raise BlockingIOError instead of blocking).
GRND_RANDOM = 1 (=use blocking_pool)
= 11 (=flag 3)
如果应用程序在等待 blocking_pool具有一定量的熵时需要执行其他任务,则该功能很有用。需要围绕它的try-except逻辑以及一个运行该函数并将返回的字节存储到缓冲区中直到缓冲区大小为32字节的外部循环。
其他
打开('/dev/urandom','rb')。read(32)
为了确保向后兼容,与使用ChaCha20 DRNG的GETRANDOM()不同,从 /dev/urandom设备文件读取不会阻塞。无法保证随机数的质量,这是不好的。这是最不推荐的选项。
os.urandom(32) os.urandom(n)提供尽力而为的安全性:
Python3.6
在Linux 3.17及更高版本上, os.urandom(32)os.getrandom(32, flags=0)等效。在较旧的内核上,它安静地回落到 open('/dev/urandom', 'rb').read(32)的等效值,这不好。
首选 os.getrandom(32, flags=0),因为它不能退回到不安全模式。
Python3.5及更早版本
总是等效于 open('/dev/urandom', 'rb').read(32),这不好。由于 os.getrandom()不可用,因此不应使用Python3.5。
secrets.token_bytes(32)(仅适用于Python 3.6) os.urandom()的包装器。密钥的默认长度为32字节(256位)。在Linux 3.17及更高版本上, secrets.token_bytes(32)os.getrandom(32, flags=0)等效。在较旧的内核上,它安静地回落到 open('/dev/urandom', 'rb').read(32)的等效值,这不好。
同样,应首选 os.getrandom(32, flags=0),因为它不能退回到不安全模式。
tl; dr
使用 os.getrandom(32, flags=0)
那么其他RNG源,random,SystemRandom()等呢?
import random
random.<anything>()
对于创建密码,加密密钥等, 绝对不安全。
import random
sys_rand = random.SystemRandom()
可以安全地用于和密码!
sys_rand.sample()
使用sys_rand.sample(list_of_password_chars, counts=password_length) 生成随 secret 码不是安全的,因为用documentation引用,sample()方法用于“随机采样而无需替换”。这意味着密码中的每个后续字符都保证不包含任何先前的字符。这将导致密码为而不是统一随机的
sys_rand.choices()sample()方法用于随机采样,而无需替换choices()方法用于替换
的随机采样 。但是,在choices上引用documentation

The algorithm used by choices() uses floating point arithmetic for internal consistency and speed. The algorithm used by choice() defaults to integer arithmetic with repeated selections to avoid small biases from round-off error.


因此,使用的浮点算术choices()方法向采样的密码引入了密码学上不可忽略的偏差。因此, random.choices()不得用于密码/密钥生成!
sys_random.choice()
根据先前引用的文档,sys_random.choice()方法使用整数算法而不是浮点算法,因此使用重复调用sys_random.choice()生成密码/密钥是安全的。
secrets.choice()secrets.choice()sys_random.choice()的包装,并且可以与random.SystemRandom().choice()互换使用:它们是同一回事。
recipe for best practice to generate a passphrase with secrets.choice()
import secrets
# On standard Linux systems, use a convenient dictionary file.
# Other platforms may need to provide their own word-list.
with open('/usr/share/dict/words') as f:
words = [word.strip() for word in f]
passphrase = ' '.join(secrets.choice(words) for i in range(4))
如何确保生成的密码短语符合某些安全级别,例如128位?
这是一个食谱
import math
import secrets

def generate_passphrase() -> str:

PASSWORD_MIN_BIT_STRENGTH = 128 # Set desired minimum bit strength here

with open('/usr/share/dict/words') as f:
wordlist = [word.strip() for word in f]

word_space = len(wordlist)
word_count = math.ceil(math.log(2 ** PASSWORD_MIN_BIT_STRENGTH, word_space))

passphrase = ' '.join(secrets.choice(wordlist) for _ in range(word_count))

# pwd_bit_strength = math.floor(math.log2(word_space ** word_count))
# print(f"Generated {pwd_bit_strength}-bit passphrase.")

return passphrase

关于linux - 关于Python3.6 os.urandom/os.getrandom/secrets的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42190663/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com