2009-03-07 63 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))