如何使用 Python 生成由随机非零字节组成的字节串?
How to generate a byte string consisting of random nonzero bytes using Python?
作为实现 RSA 的 PKCS #1 v1.5 填充方案的一部分,我需要 生成一个长度为 n 的八位字节串,其中包含伪随机生成的非零八位字节 。
我正在寻找使用 Python.
执行此操作的最佳方法
这是我当前的实现方式:
def nonzero_random_bytes(n: int) -> bytes:
values = [x.to_bytes(1, "big") for x in range(1, 256)]
seq = [secrets.choice(values) for _ in range(n)]
return b"".join(seq)
我查看了使用 secrets.token_bytes(n)
生成字节字符串、过滤结果并生成非零值以回填字符串。我知道我也可以做类似 secrets.token_bytes(2 * n)
、过滤和 trim 结果的事情,但这并不是一个优雅的解决方案。
我还研究了 PyCryptodome and python-pkcs1 do this but I'm thinking there must be a better way (I poked around pyca/cryptography but couldn't find how they did it and it seems they use OpenSSL bindings - here's 我认为是如何实施的)。
免责声明: 我知道我不应该使用 PKCS1 v1.5,更不用说自己推出任何加密代码了。这纯粹是一个学术练习。 :)
您没有定义“最佳”对您意味着什么。我会接受这个,这基本上是一种不那么冗长的方式来做你已经做过的事情:
from secrets import randbelow
def nonzero_random_bytes(n: int) -> bytes:
return bytes(randbelow(255) + 1 for _ in range(n))
与 Tim 几乎一样,但认为“最佳”可能需要速度。 n = 250
的基准(“大概 100-400”范围的中间):
471.3 us nonzero_random_bytes_original
438.3 us nonzero_random_bytes_randbelow
4.7 us nonzero_random_bytes_2n
3.1 us nonzero_random_bytes_plus10
代码(Try it online!):
from timeit import timeit
import secrets
def nonzero_random_bytes_original(n: int) -> bytes:
values = [x.to_bytes(1, "big") for x in range(1, 256)]
seq = [secrets.choice(values) for _ in range(n)]
return b"".join(seq)
def nonzero_random_bytes_randbelow(n: int) -> bytes:
return bytes(1 + secrets.randbelow(255) for _ in range(n))
def nonzero_random_bytes_2n(n: int) -> bytes:
return secrets.token_bytes(2 * n).replace(b'[=11=]', b'')[:n]
def nonzero_random_bytes_plus10(n: int) -> bytes:
result = b''
while need := n - len(result):
result += secrets.token_bytes(need + 10).replace(b'[=11=]', b'')[:need]
return result
funcs = [
nonzero_random_bytes_original,
nonzero_random_bytes_randbelow,
nonzero_random_bytes_2n,
nonzero_random_bytes_plus10,
]
for _ in range(3):
for func in funcs:
t = timeit(lambda: func(250), number=1000)
print('%5.1f us ' % (t * 1e3), func.__name__)
print()
作为实现 RSA 的 PKCS #1 v1.5 填充方案的一部分,我需要 生成一个长度为 n 的八位字节串,其中包含伪随机生成的非零八位字节 。 我正在寻找使用 Python.
执行此操作的最佳方法这是我当前的实现方式:
def nonzero_random_bytes(n: int) -> bytes:
values = [x.to_bytes(1, "big") for x in range(1, 256)]
seq = [secrets.choice(values) for _ in range(n)]
return b"".join(seq)
我查看了使用 secrets.token_bytes(n)
生成字节字符串、过滤结果并生成非零值以回填字符串。我知道我也可以做类似 secrets.token_bytes(2 * n)
、过滤和 trim 结果的事情,但这并不是一个优雅的解决方案。
我还研究了 PyCryptodome and python-pkcs1 do this but I'm thinking there must be a better way (I poked around pyca/cryptography but couldn't find how they did it and it seems they use OpenSSL bindings - here's 我认为是如何实施的)。
免责声明: 我知道我不应该使用 PKCS1 v1.5,更不用说自己推出任何加密代码了。这纯粹是一个学术练习。 :)
您没有定义“最佳”对您意味着什么。我会接受这个,这基本上是一种不那么冗长的方式来做你已经做过的事情:
from secrets import randbelow
def nonzero_random_bytes(n: int) -> bytes:
return bytes(randbelow(255) + 1 for _ in range(n))
与 Tim 几乎一样,但认为“最佳”可能需要速度。 n = 250
的基准(“大概 100-400”范围的中间):
471.3 us nonzero_random_bytes_original
438.3 us nonzero_random_bytes_randbelow
4.7 us nonzero_random_bytes_2n
3.1 us nonzero_random_bytes_plus10
代码(Try it online!):
from timeit import timeit
import secrets
def nonzero_random_bytes_original(n: int) -> bytes:
values = [x.to_bytes(1, "big") for x in range(1, 256)]
seq = [secrets.choice(values) for _ in range(n)]
return b"".join(seq)
def nonzero_random_bytes_randbelow(n: int) -> bytes:
return bytes(1 + secrets.randbelow(255) for _ in range(n))
def nonzero_random_bytes_2n(n: int) -> bytes:
return secrets.token_bytes(2 * n).replace(b'[=11=]', b'')[:n]
def nonzero_random_bytes_plus10(n: int) -> bytes:
result = b''
while need := n - len(result):
result += secrets.token_bytes(need + 10).replace(b'[=11=]', b'')[:need]
return result
funcs = [
nonzero_random_bytes_original,
nonzero_random_bytes_randbelow,
nonzero_random_bytes_2n,
nonzero_random_bytes_plus10,
]
for _ in range(3):
for func in funcs:
t = timeit(lambda: func(250), number=1000)
print('%5.1f us ' % (t * 1e3), func.__name__)
print()