如何将Python的urandom转换为字符串?

44
如果我调用os.urandom(64),就会得到64个随机字节。参考将字节数组转换为Python字符串,我尝试了以下内容:
a = os.urandom(64)
a.decode()
a.decode("utf-8")

但是却得到了回溯错误,提示该字节不符合utf-8编码。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 0: invalid start byte

使用字节

b'\x8bz\xaf$\xb6\x93q\xef\x94\x99$\x8c\x1eO\xeb\xed\x03O\xc6L%\xe70\xf9\xd8
\xa4\xac\x01\xe1\xb5\x0bM#\x19\xea+\x81\xdc\xcb\xed7O\xec\xf5\\}\x029\x122
\x8b\xbd\xa9\xca\xb2\x88\r+\x88\xf0\xeaE\x9c'

是否有一种可靠的方法将这些字节解码为某些字符串表示形式?我正在生成伪随机令牌以跟踪多个数据库引擎中相关文档。


这种做法很奇怪...为什么不只是拥有一个更"中心化"的数据库,它会生成自己的ID,并引用其他的IDs呢?或者,可以使用uuid4或类似的方式,而不是使用urandom吗? - Jon Clements
这个能用来生成随机种子吗? - Charlie Parker
Django的生成随机字符串逻辑。https://github.com/django/django/blob/master/django/utils/crypto.py#L51 - bgth
6个回答

78

以下代码可在Python 2.7和3上使用:

from base64 import b64encode
from os import urandom

random_bytes = urandom(64)
token = b64encode(random_bytes).decode('utf-8')

rstring = os.urandom(16) rstring b'\xaf\xec)Uf\x1fb\x8dQ\xfa\xc0\x95\x9c\xd1T\x97' b64encode(rstring) b'r+wpVWYfYo1R+sCVnNFUlw==' b64encode(rstring).decode('utf-8') 'r+wpVWYfYo1R+sCVnNFUlw=='
- Muneeb Ejaz

14

您有随机字节;如果这些字节能被解码为字符串,我会非常惊讶。

如果您必须使用Unicode字符串,请从Latin-1解码:


a.decode('latin1')

因为它将字节一对一地映射到相应的 Unicode 码点。


似乎每次都能正常工作。我只需要一个 Django 字符字段可以接受的字符串。 - user1876508
是的,很遗憾Django只在即将发布的1.6版本中添加了一个二进制字段。 - Martijn Pieters

10

您可以使用base-64编码。在这种情况下:

a = os.urandom(64)
a.encode('base-64')

还要注意,我在这里使用的是encode而不是decode,因为decode试图将它从您指定的任何格式转换为Unicode。所以在您的示例中,您将随机字节视为形成有效的utf-8字符串,这在使用随机字节的情况下很少会发生。


10
我收到一条错误提示,指出“bytes”对象没有属性“encode”。这段代码是否与某个特定版本的Python有关?我正在使用3.3版本。 - user1876508
1
我不确定Python3.x。我正在使用Python2.7。 - Rob Watts
@user1876508 你尝试过使用 str(b'hello', encoding) 吗?如果你的编码方式是 'base-64',它可能会起作用。 - Rob Watts
str(os.urandom(64), 'base-64') 给我返回了LookupError: 未知的编码类型: base-64。 - user1876508
我遇到了错误,提示“bytes对象没有encode属性”。 - Muneeb Ejaz

3

您确定需要将64个字节表示为字符串吗?

也许您真正需要的是N位令牌? 如果是这样,请使用secrets。secrets模块提供了生成安全令牌的函数,适用于密码重置、难以猜测的URL等应用程序。

import secrets

>>> secrets.token_bytes(16)  
b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'

>>> secrets.token_hex(16)  
'f9bf78b9a18ce6d46a0cd2b0b86df9da'

>>> secrets.token_urlsafe(16)  
'Drmhze6EPcv0fN_81Bj-nA'

或许你需要一个长度为64个字符的随机字符串?导入字符串模块。

import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(64))

1
这个简单的方法:
a = str(os.urandom(64))
print(F"the: {a}")
print(type(a))

0

尝试使用编解码器和urandom(16)进行编码/解码时,我会收到一个UnicodeDecodeError: 'utf-8' codec can't decode byte 0xed in position 0: invalid continuation byte

这是我最终做的。

import os
import binascii

a = binascii.hexlify(os.urandom(32)).decode()
print(a)

'fd78f19c8bdcd7bc086d5a34b8d0ebccbd501fd2eea18e46699bb52efa48ac3c'

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