我正在使用一个名称为21个字符的api来表示一个内部会话,该会话的生命周期为“两天”。我希望这个名字不要使用某种形式的意义? MD5生成40个字符,有什么我可以使用? Python和21个字符的随机密钥最大
现在我用'userid [:10]'+创建时间:ddhhmmss +随机3个字符。
感谢,
我正在使用一个名称为21个字符的api来表示一个内部会话,该会话的生命周期为“两天”。我希望这个名字不要使用某种形式的意义? MD5生成40个字符,有什么我可以使用? Python和21个字符的随机密钥最大
现在我用'userid [:10]'+创建时间:ddhhmmss +随机3个字符。
感谢,
如果我正确地阅读你的问题,你想要生成一些任意的标识符令牌,它必须是最多21个字符。它是否需要高度抵抗猜测?你给出的例子不是“crytographically强”,因为它可以通过搜索少于整个可能的密钥空间的1/2来猜测。
您不会说这些字符是否可以是全部256个ASCII字符,或者是否需要限制为可打印的ASCII(33-127,含)或更小的范围。
有一个为 UUID s(通用唯一标识符)设计的Python模块。您可能需要uuid4,它会生成一个随机的UUID,并使用操作系统支持(如果可用)(在Linux,Mac,FreeBSD和其他可能的系统上)。
>>> import uuid
>>> u = uuid.uuid4()
>>> u
UUID('d94303e7-1be4-49ef-92f2-472bc4b4286d')
>>> u.bytes
'\xd9C\x03\xe7\x1b\xe4I\xef\x92\xf2G+\xc4\xb4(m'
>>> len(u.bytes)
16
>>>
16个随机字节是非常难以猜测的,而且也没有必要使用完整的21个字节的API允许,如果你想要的是有一个难以猜测的不透明标识符。
如果你不能使用这样的原始字节,这可能是一个坏主意,因为它很难在日志和其他调试消息中使用,并且难以用眼比较,然后将字节转换为更易读的字符,如使用碱-64编码,其结果砍倒至21(或任何)字节:
>>> u.bytes.encode("base64")
'2UMD5xvkSe+S8kcrxLQobQ==\n'
>>> len(u.bytes.encode("base64"))
25
>>> u.bytes.encode("base64")[:21]
'2UMD5xvkSe+S8kcrxLQob'
>>>
这给你长度21的极高质量的随机串。
您可能不喜欢可能位于base-64字符串中的“+”或“/”,因为没有正确的转义可能会干扰URL。既然你已经想过使用“随机3个字符”,我不认为这是你的担心。如果是的话,你可以用别的东西替换这些字符(' - '和'。'可能有效),或者如果存在的话将其删除。如其他人指出的,你可以使用.encode(“十六进制”)并得到十六进制等效值,但这只是4位的随机性/字符*最多21个字符给你84位的随机性,而不是两倍。每一个位都会使您的密钥空间翻倍,使理论搜索空间变得更小,更小。减小2E24倍。
即使使用十六进制编码,您的密钥空间仍然是2E24的大小,所以我认为这更受理论上的关注。我不会担心人们对你的系统进行暴力攻击。
编辑 :如果有
P.S:该uuid.uuid4功能使用libuuid。从当前时间和本地以太网MAC地址中获取它的来自os.urandom的熵(如果可用)。如果libuuid不可用,那么uuid.uuid4函数直接从os.urandom获取字节(如果可用),否则使用随机模块。随机模块使用基于os.urandom的默认种子(如果可用),否则使用基于当前时间的值。探测发生在每个函数调用中,所以如果你没有os.urandom,那么开销会比你想象的要大一些。
回家的消息?如果你知道你有os.urandom那么你可以做
os.urandom(16).encode("base64")[:21]
,但如果你不想担心其可用性,然后使用UUID模块。
为什么不采取第21个字符的MD5或SHA1哈希?
真的应该是相当随机的 – coulix 2009-03-07 10:43:31
类似hashlib.md5(str(random.random()))。hexdigest()[:21] – 2009-03-07 11:56:42
random.random()默认从os.urandom获取它的种子,否则从了time.time。假设操作系统支持os.urandom,不妨操作os.urandom(11).encode(“hex”)[:21]。 – 2009-03-07 14:59:39
MD5的十六进制表示具有非常差的随机性:每个字符只能得到4位熵。
使用随机字符,是这样的:
import random
import string
"".join([random.choice(string.ascii_letters + string.digits + ".-")
for i in xrange(21)])
在选择把所有的可接受的字符。
虽然使用真正的哈希函数(如SHA1)也会为您带来不错的结果 如果使用正确 ,增加的复杂性和CPU消耗似乎不符合您的需求。你只需要一个随机字符串。
字符或字节?如果它使用任意字符串,则可以使用字节,而不用担心扩展为可读的字符(无论如何base64会比hex更好)。
如果您不使用它的十六进制扩展,则MD5会生成16个字符。 SHA1在相同条件下生成20个。
>>> import hashlib
>>> len(hashlib.md5('foobar').digest())
16
>>> len(hashlib.sha1('foobar').digest())
20
之后需要几个额外的字节。
base64模块可以进行URL安全编码。因此,如果需要的话,而不是
u.bytes.encode("base64")
你可以做
import base64
token = base64.urlsafe_b64encode(u.bytes)
和方便,转换回
u = uuid.UUID(bytes=base64.urlsafe_b64decode(token))
你必须思考SHA1。 MD5是32位十六进制数字。 – kmkaplan 2009-03-07 11:28:31