Python中的随机哈希

142

在Python中生成随机哈希(MD5)的最简单方法是什么?


1
随机是指任何东西吗?还是指一个对象?如果你只想要一个随机的MD5,那就随便选一些数字。 - samoz
我在上传之前重命名文件,希望文件名像这样:timestamp_randommd5.extension。干杯! - mistero
6
你可以将它们重命名为timestamp_randomnumber.ext。其实没有理由使用md5(randomnumber)比使用随机数本身更好。 - sth
Python 3 的最佳答案是最后一个 import uuid; uuid.uuid().hex https://dev59.com/h3NA5IYBdhLWcg3wZ8_U#20060712 - maxbellec
10个回答

176
一个 MD5 哈希值只是一个 128 位的值,所以如果你想要一个随机的:
import random

hash = random.getrandbits(128)

print("hash value: %032x" % hash)

我其实不太明白这个意义所在。也许你应该详细说明一下为什么你需要这个...

1
不要从随机数计算一个相对昂贵的哈希值,这种方法快了5倍。 - Nicolas Dumazet
13
+1 - 这肯定比我的回答更好,也可以用这种方式:hex(random.getrandbits(128))[2:-1],这将给你与 md5 hexdigest 方法相同的输出。 - Jiri
1
random.seed()调用多多少少是没有用的。 - tzot
3
我会使用 os.urandom,因为想要一个 MD5 哈希值可能意味着想要一个安全的哈希值。 - Unknown
9
使用os.urandom生成随机字节串并转换为十六进制字符串的方法是:''.join('%02x' % ord(x) for x in os.urandom(16)) - FogleBird
hex(random.getrandbits(128))[2:-1] 有时会给你一个31个字符长的字符串(期望每次都是32个字符)。 - stefanobaldo

153

93

secrets 模块 是从 Python 3.6+ 开始引入的。它通过一个单一的调用提供了密码安全的随机值。这些函数接受一个可选参数 nbytes,默认参数为 32(字节 * 8 位 = 256 位令牌)。MD5 具有 128 位哈希值,因此为“MD5 类型”令牌提供 16。

>>> import secrets

>>> secrets.token_hex(nbytes=16)
'17adbcf543e851aa9216acc9d7206b96'

>>> secrets.token_urlsafe(16)
'X7NYIolv893DXLunTzeTIQ'

>>> secrets.token_bytes(128 // 8)
b'\x0b\xdcA\xc0.\x0e\x87\x9b`\x93\\Ev\x1a|u'

50

这适用于 Python 2.x 和 3.x

import os
import binascii
print(binascii.hexlify(os.urandom(16)))
'4a4d443679ed46f7514ad6dbe3733c3d'

1
谢谢。这是生成随机哈希键的最佳方法。 - Jake
7
适用于2.x和3.x版本:binascii.hexlify(os.urandom(16)),意为生成一个长度为16的随机字节序列并将其转换为十六进制格式。 - Clay

25

另一种方法。您无需格式化整数即可获得它。

import random
import string

def random_string(length):
    pool = string.letters + string.digits
    return ''.join(random.choice(pool) for i in xrange(length))

让字符串长度更加灵活。

>>> random_string(64)
'XTgDkdxHK7seEbNDDUim9gUBFiheRLRgg7HyP18j6BZU5Sa7AXiCHP1NEIxuL2s0'

3
我可能会将string.letters更改为'abcdf'以反映十六进制数字。但是这是个好的解决方案! - ranchalp
有没有更Pythonic的方法来实现''.join(random.sample(string.ascii_letters + string.digits, 8)) - 404pio
string.ascii_letters for python 3 instead of string.letters - Alex

6

针对这个具体问题的另一种方法:

import random, string

def random_md5like_hash():
    available_chars= string.hexdigits[:16]
    return ''.join(
        random.choice(available_chars)
        for dummy in xrange(32))

我并不是说这是比其他答案更快或更可取的解决方案;只是它是另一种方法 :)


5
import uuid
from md5 import md5

print md5(str(uuid.uuid4())).hexdigest()

5
import os, hashlib
hashlib.md5(os.urandom(32)).hexdigest()

输出结果类似于: eca224d7443ec56efd984c08904cbe4b - not2qubit

4
最合适的方法是使用random模块。
import random
format(random.getrandbits(128), 'x')

使用secrets是过度的。它会牺牲性能,生成具有密码学强度的随机数。

所有建议使用UUID的响应在本质上都是错误的,因为UUID(甚至是UUID4)并不是完全随机的。至少它们包含一个永远不会改变的固定版本号。

import uuid
>>> uuid.uuid4()
UUID('8a107d39-bb30-4843-8607-ce9e480c8339')
>>> uuid.uuid4()
UUID('4ed324e8-08f9-4ea5-bc0c-8a9ad53e2df6')

所有MD5哈希值中,从左数第13位不是4的将无法通过此方式访问。


os.urandom(128//8) 计算时间比普通方式长 5 倍,或者长出 0.25 微秒。如果你关心在生成 400 万个哈希时节省 1 秒的时间,你应该使用像 PCG 这样更快的 RNG。如果你认为你的“哈希”是不可预测的,那么你应该使用 CSPRNG,因为在使用该函数约 160 次后,重新构建 RNG 状态(https://github.com/eboda/mersenne-twister-recover)是非常容易的。 - Nick T
我不理解你的MD5评论,请解释一下。 - not2qubit
使用UUID4生成的字符串,其第13个位置始终包含数字4,这是一个问题。 - Pasha Podolsky

1

from hashlib import md5
plaintext = input('Enter the plaintext data to be hashed: ') # Must be a string, doesn't need to have utf-8 encoding
ciphertext = md5(plaintext.encode('utf-8')).hexdigest()
print(ciphertext)

需要注意的是,MD5是一种非常弱的哈希函数,同时已经发现了碰撞(两个不同的明文值产生相同的哈希值)。只需为 plaintext 使用随机值即可。

要求用户输入并不能帮助解决原问题中“最简单”的方面... - AS Mackay
1
你检查过你的代码了吗?第三行缺少一个括号。 - ingyhere

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