在Python中对字符串进行哈希(隐藏)处理

17

我需要的是对字符串进行哈希处理。因为它只是作为文本文件中的隐藏短语,所以不必过于安全(它只需不可被人眼辨认)。

这应该不仅仅是随机字符串,因为当用户键入该字符串时,我想将其哈希处理并将其与已哈希处理后的字符串(来自文本文件)进行比较。

对于这个目的,最好的方法是什么?它可以使用内置类完成吗?


1
你的真正问题是什么?有许多哈希算法,最好的方法取决于你如何使用哈希字符串。 - Leonardo.Z
4个回答

45

首先,我要说的是,你无法保证唯一的结果。如果你想对宇宙中所有字符串都实现唯一的结果,最好存储字符串本身(或者是压缩版本)。

稍后再详细解释这一点。让我们首先获取一些哈希值。

使用hashlib方式

你可以使用任何一个主要的加密哈希算法来对一个字符串进行哈希,只需要几个步骤:

>>> import hashlib
>>> sha = hashlib.sha1("I am a cat")
>>> sha.hexdigest()
'576f38148ae68c924070538b45a8ef0f73ed8710'

就编译器内置而言,您可以在SHA1、SHA224、SHA256、SHA384、SHA512和MD5之间进行选择。

这些哈希算法有什么区别?

哈希函数的工作原理是将长度可变的数据变成固定长度的数据。

在每个内置于hashlib中的SHA算法中,固定长度是名称中指定的位数(除了sha1是160位)。如果您想更好地确保两个字符串不会落入同一个桶(相同的哈希值),请选择具有更大摘要(即固定长度)的哈希函数。

按排序顺序,这些是您可以使用的摘要大小:

Algorithm  Digest Size (in bits)
md5        128
sha1       160
sha224     224
sha256     256
sha384     384
sha512     512

如果您的哈希函数足够好,摘要越大,发生冲突的可能性就越小。

等等,那么hash()呢?

内置的hash()函数返回整数,也可以用于您所描述的目的。但是存在问题。

>>> hash('moo')
6387157653034356308
  1. 如果您的程序将在不同的系统上运行,那么您不能确定hash会返回相同的结果。实际上,我正在运行64位Python的64位计算机。这些值将与32位Python的值大不相同。

  2. 对于Python 3.3+,正如@gnibbler所指出的,hash()在运行间是随机的。它可以在单次运行中工作,但几乎肯定无法跨您程序的多次运行工作(从您提到的文本文件中读取)。

为什么 hash() 被构建成这样呢? 因为内置哈希表/字典/查找表存在于内存中,而不是用于加密,而是用于运行时的廉价查找。

不要使用 hash(),请使用 hashlib


4
自 Python3.3 起,hash() 函数是随机化的,即在每次运行时都会变化。也就是说,你只能在程序单次运行中依赖于它返回相同的值。 - John La Rooy
太好了。谢谢@gnibbler,我不知道它在运行之间不稳定。 - Kyle Kelley

8
您可以简单地使用base64模块来实现您的目标:
>>> import base64
>>> a = 'helloworld'
>>> encoded_str = base64.encodestring(a)
>>> encoded_str
'aGVsbG93b3JsZA=='
>>> base64.decodestring(encoded_str)
'helloworld'
>>>

当然,您也可以使用hashlib模块,这更加安全,因为哈希字符串在以后无法(或者非常难以)被解码,但对于您的问题,base64已经足够了--"它不一定需要很安全"。

Python2.3默认是否带有base64模块?(是的,我知道这很奇怪) - Lucas
没错!可以在Python 2.3中运行上述代码 从这里了解更多 - tinylambda

4
请注意,Python的字符串哈希值并未被“定义”-它可以在不同版本和实现中发生变化。因此,存储Python字符串哈希值会产生困难。CPython的字符串哈希值也没有试图变得“晦涩难懂”。
一种标准方法是使用为此类事情而设计的哈希函数。像这样:
>>> import hashlib
>>> encoded = hashlib.sha1("abcdef") # "abcdef" is the password
>>> encoded.hexdigest()
'1f8ac10f23c5b5bc1167bda84b833e5c057a77d2'

那一长串十六进制数字就是“哈希”值。SHA-1是一种“强大”的哈希函数。如果你能找到两个字符串的哈希值相同,你可能会出名;-) 并且在所有平台和Python所有版本和实现中,给定相同的输入,它将返回相同的“十六进制摘要”。


1
特别是自从Python3.3以来,hash(somestring)在不同的运行中是不同的。 - John La Rooy

0

只需使用内置函数hash()即可,例如:

s = 'a string'
hash(s)
=> -8411828025894108412

这会为每个字符串生成唯一的数字吗?它可以被解码吗(只是好奇)? - Lucas
2
@Lucas,对于一个固定大小的哈希函数来说,不可能为所有可能的字符串返回不同的值。例如,如果一个哈希函数返回2比特,则只有4个可能的值。 - Tim Peters
2
@Lucas 不,哈希值无法“解码”。 如果两个对象相等,则它们的哈希值相等; 但是,“许多”对象可以(在字符串的情况下将)解析为相同的哈希值。 - roippi
1
这是一个不好的想法。请看我对其他答案的评论。 - John La Rooy
@Lucas。不,可能的字符串比哈希值多得多,所以有时候会发生碰撞。 - John La Rooy
1
Python 2中字符串哈希碰撞的示例可在以下链接中找到:https://stackoverflow.com/q/37127946/1959808 - 0 _

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