likes
comments
collection
share

go 密码加密的方式

作者站长头像
站长
· 阅读数 15

数据库在存储密码时,不能明文存储,需要加密后存储

加密算法有很多种,比如:对称加密,非对称加密,哈希算法,密码派生等

在加密之前,我们需要生成一些随机数,这些随机数称为盐

什么是盐?为什么需要盐?

盐是一种加密算法中的一种参数,它是一个随机数,用于增加破解密码的难度

把密码想象成一盘菜,盐就是调料,不加调料就是原汁原味的菜,调料加多加少,菜口味就不一样了

也就是说,盐的多少,会影响到加密后的结果,如果不使用盐,那么相同的密码,加密后的结果是一样的,这样就很容易被破解

盐的生成方式有很多种,比如:随机数,时间戳等

这里用随机数来举例:

  1. 定义一个字符串,里面包含了所有可能的字符
  2. 根据传入的长度,生成一个切片,并用随机数填充
  3. 遍历这个切片,取出随机数,然后对字符串长度取余,得到一个索引,然后把这个索引对应的字符,放到切片中
  4. 返回这个切片(这个切片就是盐)
func generateSalt(length int) []byte {
  const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  salt := make([]byte, length)
  rand.Read(salt)
  for key, val := range salt {
    salt[key] = alphanum[val%byte(len(alphanum))]
  }
  return salt
}

生成盐之后,我们就可以对密码进行加密了

加密后的密码要使用 hex.EncodeToString 转换成字符串

salt := generateSalt(16)
encoded := pbkdf2.Key([]byte("uccs"), salt, 100, 32, sha256.New)
encodedPwd := hex.EncodeToString(encodedPwd)

因为这个加密算法是不可逆的,也就说你不能通过加密后的密码,反推出原始密码

那用户输入密码时,如何知道密码是否正确呢?

所以在存储加密后的密码时,还要存储盐和加密算法的参数

这里使用的是 pbkdf2 算法,它的参数有:原始密码,盐,迭代次数,密钥长度,哈希算法

所以最终存在数据的密码是:

pwd := fmt.Sprintf("%s$%s$%d$%d$%s", encodedPwd, salt, 100, 32, "pbkdf2-sha256")

这样在验证密码时,就可以通过这些参数,把用户输入的密码,加密后,再和数据库中存储的密码进行比较,如果相同,就说明密码正确