Python生成32位十六进制随机数

6

我希望找到一种很好的方法来生成一个32位十六进制序列,该序列是随机的,并且从类似于10 * 78这样的大数中获得其随机性。

对于Python代码,我也找到了以下内容:

ran = random.randrange(10**80)
myhex = "%030x" % ran

这会生成一个64位的十六进制字符串,但是有时结果只有63或者61个字符,我不确定为什么?我需要它每次都能返回确切的64个字符。

我需要帮助调整上面的代码,使其始终只返回64个字符。我对"%030x"的工作原理不太了解。

我还尝试过生成更长的十六进制字符串,并使用以下方法将其缩短:

myhex = myhex[:64]

但我仍然看到返回的字符串长度小于64个字符。

最终,我只需要从类似于10*78的大数字中得出确切的64位十六进制字符串,并每次返回它。

我采用的解决方案

import random

ran = random.randrange(10**80)
myhex = "%064x" % ran

#limit string to 64 characters
myhex = myhex[:64]

print(myhex)

看起来下面@ScottMillers的回答是我需要找到答案的关键,所以我选择他的答案作为解决方案,但我想在这里发布我的最终代码。

谢谢大家


1
这是Scott Hunter,不是Scott Miller,但我被称为更糟的名字。 - Scott Hunter
8个回答

11

在现代Python发行版中,新的secrets库可以轻松生成加密强度的随机数,适用于管理诸如密码、账户认证、安全令牌以及相关保密数据等。特别地,应优先使用secrets而非random模块中默认的伪随机数生成器,后者适用于建模和模拟,而不是用于安全或加密。

对于Python 3.6及以上版本,请尝试以下方法:

import secrets
secrets.token_hex(32)
#'17450056b398cbeda1fa7e4fc25d4fb169ade2b1266892e2cecab56b12fb900b'

https://docs.python.org/3/library/secrets.html#module-secrets为Python的最新版本提供了安全模块,早期版本的Python可以使用回流版本(python2-secrets)。

   pip install python2-secrets

1
请注意,传递给 token_hex 的数字是请求的字节数,每个字节对应两个十六进制数字。因此,要像 OP 一样获得32个十六进制数字,您需要使用: secrets.token_hex(16) - Fernando Echeverria

9
UUID模块可以返回一个由32个十六进制数字组成的对象:
import uuid
uuid.uuid4().hex
# '7dccf8a43a6c4e018caadacdb2d0f6f0'

2
值得指出的是,尽管结果确实为128位,但RFC定义了6个最高有效位的值,因此只有122位是随机的。 - Michał Górny

8
""%030x"的意思是显示至少30个数字的相关值,并在必要时在前面填充0。由于您的数字几乎总是比这个大,所以这对您没有什么帮助。

听起来您需要"%064x"。"


谢谢。这对我的最终解决方案非常重要,所以我选择它作为我的答案。 - Norman Bird

2

"十六进制数"并不存在,只是同一个数字的不同表示方法(10在十进制中为0xA,在二进制中为0b1010,在十六进制中为A),但它们仍然代表同一个数字。

这会生成一个64位的十六进制字符串,但有时结果只有63或61个字符,我不知道为什么?我需要每次都返回64个字符。

所以:请你给我一个大于0且小于1000的随机数;那个数字将有多少位数?

对了。它可能有一位、两位或三位数字,其中三位数字是最可能的情况(在1000以下有900个三位数字,但只有90个两位数字和9个一位数字)。

显然,你只需要在前面填充0!

最终,我只需要从大数字(如10 * 78)派生出确切的64个十六进制字符串,每次返回。

你需要考虑随机数的含义。如果你可以接受每个数字都来自于0..F的均匀分布,那么为什么不简单地掷一个16面骰子64次,然后将结果连接起来呢?Python使这非常容易。

import random
hexdigits = "0123456789ABCDEF"
random_digits = "".join([ hexdigits[random.randint(0,0xF)] for _ in range(64) ])

编辑:

在下面的评论中,原帖作者表示他想使用那个随机字符串来生成比特币私钥。

绝对不要自己构建种子发生器,除非你真的是该领域的专家。因此,尽管我相信这1024位(实际上,这就是一个64位十六进制数)信息是随机的,但我不能声称这足以用于加密目的

不要自己实现加密,也不要干涉种子生成,除非你熟悉随机过程、数字、密码学和随机数生成器、计算机安全研究以及可能的攻击向量。 千万别这么做


谢谢您澄清我为什么有时会看到较短的数字。这是由于一个随机数导致的。我现在的问题是,rando.randint是否具有足够的熵来支持我大量数字的需求?比如高达10 ** 78。您认为它能够胜任吗? - Norman Bird
@NormanBird,除非您开始定义“随机”对您的意义,否则显然没有答案。但很可能:Python使用的随机数生成器非常好,因此您不太可能在1024位随机性中看到任何模式。 - Marcus Müller
不行。你需要使用加密安全的方法。显然,这不是你的专业领域。你真的不应该这样做。实现自己的随机种子生成器是灾难的源头。除非你确切知道自己在做什么,否则永远不要干涉生成密码秘密的过程。 - Marcus Müller
那个人是软件设计方面的专家。他只是在密码学和随机数生成方面不是专家。 - Marcus Müller
让我们在聊天中继续这个讨论:点击此处进入聊天室 - Norman Bird
显示剩余9条评论

1
你可以使用 os.urandom 代替 hexdump。Python 2.7:
import os
num_digits = 32
myhex = os.urandom(num_digits / 2).encode('hex')

Py3.4+:

import os, codecs
num_digits = 32
myhex = codecs.encode(os.urandom(num_digits / 2), 'hex').decode()

0

在前面填充零,我们可以使用zfill选项。

例如: device = '14AB'

device.zfill(8) '000014AB' device.zfill(64) '00000000000000000000000000000000000000000000000000000000000014AB'


0
为什么不为Python2编写一些易读的代码呢?
import random
value = "%032x" % random.randrange(16**32)

( 十六进制是基于16的 )


-1
我会尝试这样做:
mylist = [0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F]
number = ""

def randomhex():
    global mylist, number
    while len(number) < 32:
        number = number + random.choice(mylist)

如果你想要它作为数字,而不是字符串,只需使用 eval()。


你可以直接使用字符串(参见我的答案),它也是一种序列类型,使用random.choice函数。 - Marcus Müller
但是:绝不要没有充分理由就使用global。你的函数是一个很好的例子,应该使用return代替。我认为你应该认真提高你的Python知识! - Marcus Müller
因为这不是函数应该工作的方式:将输入转换为它们“返回”的输出。我认为追求编程是一件很棒的事情,所以继续努力吧! - Marcus Müller
1
学习Python函数。我认为python.org官方教程以一种使整个输入->返回过程比全局更直观的方式解释了它们。通常情况下,尽可能避免使用全局变量:因为您可能会更改程序的一端未预见到的另一端的某些内容,这是一种灾难性的方案。 - Marcus Müller
@MarcusMüller 感谢您的解释,我会尽力避免使用全局变量 :D - marcb20012
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接