bcrypt
bcrypt是一个由美国计算机科学家尼尔斯·普罗沃斯(Niels Provos)以及大卫·马齐耶(David Mazières)根据Blowfish加密算法所设计的密码散列函数,于1999年在USENIX中展示。实现中bcrypt会使用一个加盐的流程以防御彩虹表攻击,同时bcrypt还是适应性函数,它可以借由增加迭代之次数来抵御日益增进的电脑运算能力透过暴力法破解。
由bcrypt加密的文件可在所有支持的操作系统和处理器上进行转移。它的口令必须是8至56个字符,并将在内部被转化为448位的密钥。然而,所提供的所有字符都具有十分重要的意义。密码越强大,数据就越安全。
除了对数据进行加密,默认情况下,bcrypt在删除数据之前将使用随机数据三次覆盖原始输入文件,以阻挠可能会获得计算机数据的人恢复数据的尝试。如果您不想使用此功能,可设置禁用此功能。
bcrypt哈希示意图
下图为bcrypt哈希的示例图,其由四部分组成:
- Prefix说明了使用的bcrypt的版本
- Cost是进行哈希的次数-数字越大生成bcrypt的速度越慢,成本越大。同样也意味着如果密码库被盗,攻击者想通过暴力破解的方法猜测出用户密码的成本变得越昂贵。
- Salt是添加到要进行哈希的字符串中的随机字符(21.25个字符),所以使用bcrypt时不需要我们在表里单独存储Salt。
- Hashed Text是明文字符串最终被bcrypt应用这些设置哈希后的哈希文本。
另外无论什么方法:每个密码加单独的盐进行哈希,使用bcrypt进行哈希等等,如果用户使用非常简单的密码例如password或123456,还是能被猜测出来的,所以在用户设置密码时应该禁止他们输入简单的密码。
go语言中使用bcrypt对密码进行加密
go语言库中,bcrypt只能做单向加密,而不能反向破解生成明文,但是可以对原密码和进行hash加密后的hash值进行比对判断是否相同,使用bcrypt进行加密,同一个密码每次生成的hash值都是不相同的。每次加密的时候首先会生成一个随机数就是盐,之后将这个随机数与密码进行hash。
// 加密密码
func HashAndSalt(pwd string) string {
hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.MinCost)
if err != nil {
log.Println(err)
}
return string(hash)
}
// 验证密码
func ComparePasswords(hashedPwd string, plainPwd string) bool {
byteHash := []byte(hashedPwd)
err := bcrypt.CompareHashAndPassword(byteHash, []byte(plainPwd))
if err != nil {
log.Println(err)
return false
}
return true
}
这里简单对两个方法封装了一下,方便后期调用。
在go语言中,bcrypt.GenerateFromPassword()
是对字符串进行加密hash的函数,其中第一个参数[]byte(pwd)
是对原字符串转换为字节切片,第二个参数bcrypt.MinCost
为对字符串进行哈希的次数,也就是上图中的Cost。bcrypt.CompareHashAndPassword()
是对hash过的字符串和原字符串进行判断,其中第一个参数byteHash
是hash加密过的hash值,第二个参数[]byte(plainPwd)
是原字符串,bcrypt.CompareHashAndPassword()
进行判断两个参数是否一个值。
示例:
func main() {
pwd1 := "wlc1003.."
pwd2 := "wlc1003.."
pwd3 := "wlc1003"
hash1 := utils.HashAndSalt(pwd1)
hash2 := utils.HashAndSalt(pwd2)
hash3 := utils.HashAndSalt(pwd3)
fmt.Println(hash1)
fmt.Println(hash2)
fmt.Println(hash3)
fmt.Println(utils.ComparePasswords(hash2, pwd1))
fmt.Println(utils.ComparePasswords(hash3, pwd2))
fmt.Println(utils.ComparePasswords(hash1, pwd2))
}
//输出
$2a$04$4MXIN0OQeiKf7HI.eKYw6eRM1mcjDrItX0wzgOSVgkczsvFj8ifuW
$2a$04$aJz4S67m.CTTP3gBiKoVZu3CTMujCImTqcUaPppcKzoUXtsIR.Z5.
$2a$04$OVXCGxnkIpvFSegtq20hHOhtvMwFIRp.iBog4E62CS9uaQ/PlDH5S
true
2023/07/16 21:53:24 crypto/bcrypt: hashedPassword is not the hash of the given password //表示不匹配
false
true