简介

Hash 是计算机中一种对资料的处理方法,通过某种特定的函数/算法(称为散列函数/算法)将要检索的项与用来检索的索引(称为散列,或者散列值)关联起来,生成一种便于搜索的数据结构(称为散列表)。也译为散列。旧译哈希(误以为是人名而采用了音译)。它也常用作一种资讯安全的实作方法,由一串资料中经过散列算法(Hashing
algorithms)计算出来的资料指纹(data fingerprint),经常用来识别档案与资料是否有被窜改,以保证档案与资料确实是由原创者所提供。

简单概要得说其实就是将任意长度的输入转换成固定长度的输出的一种方式。

一个很重要的点就是 hash 是不可逆的,也就是我们可以从明文得到 hash 值,但是很难(基本上不可能)从 hash 值获得明文。

使用场景

Hash 有大量的使用场景,从我们最常接触但是却不知道的密码验证,在服务器那边,一般我们的密码都不是明文存储的,常见的处理方式是存储我们密码的 hash
值,然后验证的时候就对比我们输入的密码的hash 值,如果一样,那么就是正确的了。

除了密码存储,我们还很常见的应用是文件校验,我们经常在网络上下载一个软件,都会提供一个 MD5 或者 SHA1
字符串,我们下载完成之后会和提供的值对比,看我们下载的文件有没有损毁,或者是被恶意篡改过的。

计算原理

hash 算法有很多,但是主要可以分为两类,分别是 MD系列和 SHA 系列,这里就以 MD5 为例介绍 hash 的算法。

  1. 初始 A、B、C、D为:

    1. //Initialize variables:
    2. var int A := 0x67452301
    3. var int B := 0xEFCDAB89
    4. var int C := 0x98BADCFE
    5. var int D := 0x10325476
  2. 将输入的序列分割成若干个和 A、B、C、D那么大的块,然后通过以下的逻辑循环计算

算完之后,最后的 A/B/C/D 就是 MD5 值了。

程序实现

在 pyhton 中有一个内置库 hashlib,内置了多种 hash 算法的实现,使用 hashlib 我们可以很方便得计算 hash 值。

  1. ## 一个简单的计算 md5 的版本
  2. import hashlib
  3. string = "i need hash"
  4. print hashlib.md5(string).hexdigest()

计算文件的 md5 值也很简单,例如:

  1. ## 一个简单的计算 md5 的版本
  2. import hashlib
  3. with open("needhashfile.name", "rb") as f:
  4. cont = f.read()
  5. print hashlib.md5(cont).hexdigest()

但是,这个版本有个很大的问题就是当文件很大的时候,内存会爆炸的,所以,我们改进一下,使用一个更好一些的版本:

  1. import os
  2. import hashlib
  3. def generate_file_md5(rootdir, filename, blocksize=2**20):
  4. m = hashlib.md5()
  5. with open( os.path.join(rootdir, filename) , "rb" ) as f:
  6. while True:
  7. buf = f.read(blocksize)
  8. if not buf:
  9. break
  10. m.update( buf )
  11. return m.hexdigest()

对于其他的 hash 算法一样使用这个程序,只需要替换一下hash 函数即可,例如 sha1 的:

  1. import os
  2. import hashlib
  3. def generate_file_md5(rootdir, filename, blocksize=2**20):
  4. m = hashlib.sha1()
  5. with open( os.path.join(rootdir, filename) , "rb" ) as f:
  6. while True:
  7. buf = f.read(blocksize)
  8. if not buf:
  9. break
  10. m.update( buf )
  11. return m.hexdigest()