2009-03-07 29 views
7

我正在使用一个名称为21个字符的api来表示一个内部会话,该会话的生命周期为“两天”。我希望这个名字不要使用某种形式的意义? MD5生成40个字符,有什么我可以使用? Python和21个字符的随机密钥最大

现在我用'userid [:10]'+创建时间:ddhhmmss +随机3个字符。

感谢,

+0

你必须思考SHA1。 MD5是32位十六进制数字。 – kmkaplan 2009-03-07 11:28:31

回答

23

如果我正确地阅读你的问题,你想要生成一些任意的标识符令牌,它必须是最多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模块。

2

为什么不采取第21个字符的MD5或SHA1哈希?

+0

真的应该是相当随机的 – coulix 2009-03-07 10:43:31

+0

类似hashlib.md5(str(random.random()))。hexdigest()[:21] – 2009-03-07 11:56:42

+0

random.random()默认从os.urandom获取它的种子,否则从了time.time。假设操作系统支持os.urandom,不妨操作os.urandom(11).encode(“hex”)[:21]。 – 2009-03-07 14:59:39

4

MD5的十六进制表示具有非常差的随机性:每个字符只能得到4位熵。

使用随机字符,是这样的:

                        
                          import random 
import string 
"".join([random.choice(string.ascii_letters + string.digits + ".-") 
     for i in xrange(21)]) 

                        
                      

在选择把所有的可接受的字符。

虽然使用真正的哈希函数(如SHA1)也会为您带来不错的结果 如果使用正确 ,增加的复杂性和CPU消耗似乎不符合您的需求。你只需要一个随机字符串。

0

字符或字节?如果它使用任意字符串,则可以使用字节,而不用担心扩展为可读的字符(无论如何base64会比hex更好)。

如果您不使用它的十六进制扩展,则MD5会生成16个字符。 SHA1在相同条件下生成20个。

                        
                          >>> import hashlib 
>>> len(hashlib.md5('foobar').digest()) 
16 
>>> len(hashlib.sha1('foobar').digest()) 
20 

                        
                      

之后需要几个额外的字节。

2

base64模块可以进行URL安全编码。因此,如果需要的话,而不是

                        
                          u.bytes.encode("base64") 

                        
                      

你可以做

                        
                          import base64 

token = base64.urlsafe_b64encode(u.bytes) 

                        
                      

和方便,转换回

                        
                          u = uuid.UUID(bytes=base64.urlsafe_b64decode(token)) 

                        
                      
相关问题