Go使用SM3哈希算法和随机盐实现用户密码加密

 更新时间:2025年12月03日 09:02:49   作者:今天也很困  
在现代 Web 系统中,用户密码安全存储是非常关键的一环,本文将介绍如何使用 SM3 哈希算法 + 随机盐 (salt) 来加密用户密码,并提供 Go 语言实现示例,需要的朋友可以参考下

前言

在现代 Web 系统中,用户密码安全存储是非常关键的一环。
传统做法用简单哈希,容易受到彩虹表攻击。

本文将介绍如何使用 SM3 哈希算法 + 随机盐 (salt) 来加密用户密码,并提供 Go 语言实现示例。

一、为什么要加盐 (Salt)

直接哈希密码存在以下问题:

彩虹表攻击

  • 攻击者可以通过预先计算的哈希表快速破解常用密码。

相同密码哈希值相同

  • 用户 A 和用户 B 使用相同密码,会生成相同哈希值,增加泄露风险。

解决方案
在密码哈希前增加随机盐 (Salt),每个用户的密码哈希值都不同,即使密码相同也不会重复。

二、SM3 哈希算法

SM3 是中国国家标准的哈希算法(国密算法),具有:

  • 输出长度 256 位
  • 安全性高,适用于密码存储
  • 广泛应用于金融和安全系统

在 Go 中可以使用 github.com/tjfoc/gmsm/sm3 来实现 SM3 哈希。

三、Go 实现用户密码加密

下面是一套完整的 SM3 密码加密方案:

1. 生成随机盐

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 生成安全随机数
  • 转为十六进制字符串存储

2. SM3 哈希函数

func sm3Hash(password, salt string) string {
    h := sm3.New()
    h.Write([]byte(password + salt))
    return hex.EncodeToString(h.Sum(nil))
}
  • 将密码和盐拼接后进行 SM3 哈希
  • 返回十六进制字符串

3. 生成哈希密码

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>
  • 包含算法标识、版本、盐和哈希值,便于版本升级和兼容不同算法

4. 验证密码

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
}
  • 从数据库中取出存储的哈希
  • 提取盐和版本信息
  • 对输入密码进行同样哈希并对比

5. 可扩展支持多种算法

代码中还可以支持 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 哈希和盐的方式,能有效抵御彩虹表攻击和密码重复泄露风险,是企业级系统密码安全存储的可靠方案。

到此这篇关于Go使用SM3哈希算法和随机盐实现用户密码加密的文章就介绍到这了,更多相关Go SM3哈希和随机盐实现密码加密内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go设置http请求超时的方法实现

    Go设置http请求超时的方法实现

    这篇文章主要介绍了Go设置http请求超时的方法实现,最近接手了一个老项目进行维护,发现其中有个关于 http 请求的方法设置的 timeout 没有生效,很奇怪,一开始查看代码并没有发现什么可疑点,后查看了源码,打断点调试才发现问题所在,这里简单记录复盘一下
    2024-08-08
  • golang 定时任务方面time.Sleep和time.Tick的优劣对比分析

    golang 定时任务方面time.Sleep和time.Tick的优劣对比分析

    这篇文章主要介绍了golang 定时任务方面time.Sleep和time.Tick的优劣对比分析,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • golang 如何通过反射创建新对象

    golang 如何通过反射创建新对象

    这篇文章主要介绍了golang 通过反射创建新对象的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • Go语言标准库sync.Once使用场景及性能优化详解

    Go语言标准库sync.Once使用场景及性能优化详解

    这篇文章主要为大家介绍了Go语言标准库sync.Once使用场景及性能优化详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Go语言学习之链表的使用详解

    Go语言学习之链表的使用详解

    链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。本文将详细为大家介绍Go语言中链表的使用,感兴趣的可以了解一下
    2022-04-04
  • Go中的应用配置管理详解

    Go中的应用配置管理详解

    这篇文章主要为大家介绍了Go中的应用配置管理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • Go Map并发冲突预防与解决

    Go Map并发冲突预防与解决

    这篇文章主要为大家介绍了Go Map并发冲突预防与解决,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • Golang使用WebSocket通信的实现

    Golang使用WebSocket通信的实现

    这篇文章主要介绍了Golang使用WebSocket通信的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • Go语言之fo循环与条件判断

    Go语言之fo循环与条件判断

    这篇文章主要介绍Go语言之fo循环与条件判断,for 循环是一个循环控制结构,可以执行指定次数的循环。下面文章我们结合条件判断,感兴趣的朋友可以参考一下
    2021-10-10
  • Go 备份数据库表的实现示例

    Go 备份数据库表的实现示例

    备份mysql数据库的方法有很多,常用的可以登录mysql活着使用mysqldump命令进行备份,本文提供golang的方式来备份mysql数据库,下面就来详细的介绍一下
    2026-06-06

最新评论