文章目录
- func generateSalt() (string, error) { b := make([]byte, 16) // 16字节随机盐 if _, err := rand.Read(b); err != nil { return “”, err } return hex.EncodeToString(b), nil } 使用 crypto/rand 生成安全随机数 转为十六进制字符串存储
- func sm3Hash(password, salt string) string { h := sm3.New() h.Write([]byte(password + salt)) return hex.EncodeToString(h.Sum(nil)) } 将密码和盐拼接后进行 SM3 哈希 返回十六进制字符串
- func HashPassword(password string) (string, error) { salt, err := generateSalt() if err != nil { return “”, err } hash := sm3Hash(password, salt) return fmt.Sprintf(“sm3$v1$%s$%s”, salt, hash), nil } 存储格式为:sm3$v1$<salt_hex>$<hash_hex> 包含算法标识、版本、盐和哈希值,便于版本升级和兼容不同算法
- func CheckPassword(dbPassword, inputPassword string) (bool, error) { parts := strings.Split(dbPassword, “$”) if len(parts) != 4 { return false, errors.New(“hash 格式不正确”) } _, version, salt, hash := parts[0], parts[1], parts[2], parts[3] if version != “v1” { return false, errors.New(“不支持的版本”) } calculatedHash := sm3Hash(inputPassword, salt) return calculatedHash == hash, nil } 从数据库中取出存储的哈希 提取盐和版本信息 对输入密码进行同样哈希并对比
- 代码中还可以支持 bcrypt 或其他哈希算法: func CheckPassword(dbPassword, inputPassword, hashAlgo string) (bool, error) { switch hashAlgo { case “bcrypt”: return bcrypt.CompareHashAndPassword([]byte(dbPassword), []byte(inputPassword)) == nil, nil case “sm3”: return CheckPassword(dbPassword, inputPassword) default: return false, errors.New(“未知 hash 算法”) } } 方便未来系统迁移或混合使用多种哈希方案
目录
- 前言
- 一、为什么要加盐 (Salt)
- 二、SM3 哈希算法
- 三、Go 实现用户密码加密
- 1. 生成随机盐
- 2. SM3 哈希函数
- 3. 生成哈希密码
- 4. 验证密码
- 5. 可扩展支持多种算法
- 四、完整示例
- 五、小结
在现代 Web 系统中,用户密码安全存储是非常关键的一环。
传统做法用简单哈希,容易受到彩虹表攻击。
本文将介绍如何使用 SM3 哈希算法 + 随机盐 (salt) 来加密用户密码,并提供 Go 语言实现示例。
直接哈希密码存在以下问题:
彩虹表攻击
- 攻击者可以通过预先计算的哈希表快速破解常用密码。
相同密码哈希值相同
- 用户 A 和用户 B 使用相同密码,会生成相同哈希值,增加泄露风险。
解决方案:
在密码哈希前增加随机盐 (Salt),每个用户的密码哈希值都不同,即使密码相同也不会重复。
SM3 是中国国家标准的哈希算法(国密算法),具有:
- 输出长度 256 位
- 安全性高,适用于密码存储
- 广泛应用于金融和安全系统
在 Go 中可以使用 github.com/tjfoc/gmsm/sm3 来实现 SM3 哈希。
下面是一套完整的 SM3 密码加密方案:
func generateSalt() (string, error) {
b := make([]byte, 16) // 16字节随机盐
if _, err := rand.Read(b); err != nil {
return "", err
}
return hex.EncodeToString(b), nil
}
- 使用
crypto/rand 生成安全随机数
- 转为十六进制字符串存储
crypto/rand 生成安全随机数
func sm3Hash(password, salt string) string {
h := sm3.New()
h.Write([]byte(password + salt))
return hex.EncodeToString(h.Sum(nil))
}
- 将密码和盐拼接后进行 SM3 哈希
- 返回十六进制字符串
func HashPassword(password string) (string, error) {
salt, err := generateSalt()
if err != nil {
return "", err
}
hash := sm3Hash(password, salt)
return fmt.Sprintf("sm3$v1$%s$%s", salt, hash), nil
}
- 存储格式为:
sm3$v1$<salt_hex>$<hash_hex>
- 包含算法标识、版本、盐和哈希值,便于版本升级和兼容不同算法
sm3$v1$<salt_hex>$<hash_hex>
func CheckPassword(dbPassword, inputPassword string) (bool, error) {
parts := strings.Split(dbPassword, "$")
if len(parts) != 4 {
return false, errors.New("hash 格式不正确")
}
_, version, salt, hash := parts[0], parts[1], parts[2], parts[3]
if version != "v1" {
return false, errors.New("不支持的版本")
}
calculatedHash := sm3Hash(inputPassword, salt)
return calculatedHash == hash, nil
}
- 从数据库中取出存储的哈希
- 提取盐和版本信息
- 对输入密码进行同样哈希并对比
代码中还可以支持 bcrypt 或其他哈希算法:
func CheckPassword(dbPassword, inputPassword, hashAlgo string) (bool, error) {
switch hashAlgo {
case "bcrypt":
return bcrypt.CompareHashAndPassword([]byte(dbPassword), []byte(inputPassword)) == nil, nil
case "sm3":
return CheckPassword(dbPassword, inputPassword)
default:
return false, errors.New("未知 hash 算法")
}
}
- 方便未来系统迁移或混合使用多种哈希方案
func main() {
password := "123456"
hash, _ := HashPassword(password)
fmt.Println("存储密码:", hash)
ok, _ := CheckPassword(hash, password)
fmt.Println("验证密码:", ok)
}
输出示例:
存储密码: sm3$v1$e2a3f4...$9f8d7c... 验证密码: true
- 使用 SM3 + 随机盐,可以安全存储用户密码
- 存储格式建议包含算法和版本号,便于升级
- 密码验证时只需从数据库取出盐和哈希值即可
- 结合 Go 的标准库和
gmsm/sm3,可以快速落地
使用 SM3 哈希和盐的方式,能有效抵御彩虹表攻击和密码重复泄露风险,是企业级系统密码安全存储的可靠方案。
gmsm/sm3,可以快速落地使用 SM3 哈希和盐的方式,能有效抵御彩虹表攻击和密码重复泄露风险,是企业级系统密码安全存储的可靠方案。
到此这篇关于Go使用SM3哈希算法和随机盐实现用户密码加密的文章就介绍到这了,更多相关Go SM3哈希和随机盐实现密码加密内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!
您可能感兴趣的文章:
- Golang使用bcrypt实现密码加密和校验的操作代码
- Go语言crypto包创建自己的密码加密工具实现示例
- Golang常用的几种密码加密方式分享
- Golang实现密码加密的示例详解
- golang使用bcrypt包对密码进行加密的方法实现