密钥衍生函数

密钥衍生函数(Key derivation function,KDF)通过接收一个密文,和一个可选的 salt 参数,生成另外的密文,也就是 key。

KDF 目前经常用户密码的存储方案。KDF 与普通的哈希加盐的密码存储方案相比,区别在于 KDF 通常会有一个很多次的迭代过程,尽可能的增加计算的时间消耗,以抵挡暴力破解。目前常用的 KDF 包括 PBKDF2、bcrypt、scrypt。优先选用 scrypt 和 bcrypt,如果没有这两个,PBKDF2 也是可以的。

bcrypt

目前业界最常用的是 bcrypt。常用模式如下:

1
2
3
4
>>> import bcrypt
>>> password = b"super secret password"
>>> bcrypt.hashpw(password, bcrypt.gensalt(10))
'$2b$10$jN0BGbH1W/50V1mW/cLWeewfmp3d0zbnenrlDgii2M6nnFKfM5USC'

生成的 hash 串,开头的 $2b$ 是标准前缀,还有 $2a$$2y$ 等,起到类似于版本号的作用。目前的默认前缀是 $2b$。紧接着的 10 表示 2^10 次循环迭代。接着的 jN0BGbH1W/50V1mW/cLWee 128 bit,经过 base64 编码成 22 个字符,代表的是随机的 salt。随后的 wfmp3d0zbnenrlDgii2M6nnFKfM5USC 184 bit,base64 编码成 31 个字符,是密码的哈希。

之所以不使用常见的 MD5、SHA1、SHA256 之类的 hash 算法是因为常用的 hash 无法对抗暴力破解。在我的笔记本上,一个如上文的代码,当指数是 10 的时候,计算一次 bcrypt 大约花费 80 毫秒,指数是 12 的时候,花费 290 毫秒,指数是 14 的时候,花费 1.2 秒。与此相应的是,一次 md5 计算只花费了 30 微秒。