• HMAC 详解:在 Golang 中实现消息认证码


    目录

    什么是 HMAC

    HMAC 的主要用途

    HMAC 的工作原理

    Golang 中的 crypto/hmac 包

    如何选择合适的哈希函数和密钥长度

    小结


    什么是 HMAC

    HMAC(Hash-based Message Authentication Code)是一种基于 Hash 函数和密钥的消息认证码,由 H.Krawezyk,M.Bellare,R.Canetti 于1996年提出的一种基于 Hash 函数和密钥进行消息认证的方法,并于1997年作为 RFC2104 被公布。HMAC 将密钥、消息和哈希函数一起使用,确保消息在传输过程中不被篡改,还可以验证消息的发送者身份。

    HMAC 的主要用途

    HMAC 主要用于以下几个方面:

    • 校验数据的完整性:HMAC可以用于校验数据在传输过程中是否被篡改,接收者通过计算接收到的消息的 HMAC,与接收到的 HMAC 进行比较,如果相同的话,可以认为数据是完整的。
    • 用于身份验证:HMAC 还可以用于验证消息的发送者。因为 HMAC 的计算需要一个密钥,只有知道这个密钥的人才能生成正确的 HMAC。所以,如果一个消息的 HMAC 是正确的,可以认为这个消息确实来自声称的发送者,典型的使用场景是 OpenAPI。
    • 防止重放攻击:在某些情况下,HMAC 还可用于防重放攻击。在消息中添加一个时间戳或序列号,并参与 HMAC 的计算,接收者可以拒绝那些具有旧时间戳或序列号的消息,从而防止攻击者重放旧消息。
    • 安全协议:HMAC 在很多安全协议中都有应用,例如 IPSec(用于保护 Internet Protocol 通信)和 TLS(用于保护 Web 通信)。这些协议使用 HMAC 来确保数据的完整性和验证发送者的身份。

    HMAC 的工作原理

    HMAC 的典型使用方式如下:

    1. 确定一个哈希函数(如 SHA256 或 MD5)和一个密钥。
    2. 通过将密钥和消息组合,并通过哈希函数运算,生成固定大小的数据(称为消息认证码)。
    3. 当消息接收者收到消息和 HMAC 时,使用同样的密钥和哈希函数对接收到的消息进行运算,然后将结果与接收到的 HMAC 进行比较,如果相同,消息就被认为是完整的且未被篡改,并且确实来自声称的发送者。

    Golang 中的 crypto/hmac 包

    Golang 中的 crypto/hmac 包提供了 HMAC 的实现方法。以下是 crypto/hmac 包的一些主要函数和用法:

    • New 函数,接收一个哈希函数和一个密钥,返回一个用来计算 HMAC 的 hash.Hash。
    h := hmac.New(sha256.New, key)
    • Write 方法,可以向 HMAC 添加数据,实现了 io.Writer 接口。
    1. _, err := h.Write(data)
    2. if err != nil {
    3. log.Fatal(err)
    4. }
    • Sum 方法,返回当前的哈希值作为字节切片。可以选择提供一个已存在的字节切片,哈希值会被追加到这个切片的末尾。
    result := h.Sum(nil)
    • Equal 函数,用于比较两个 HMAC 是否相等,这个函数可以防止 timing attack 类型的攻击(使用相同的时间来进行比较)。
    isValid := hmac.Equal(mac1, mac2)

    可以看出Equal函数并不是简单地使用`==`运算符来比较两个 HMAC 值,而是使用了一种叫做"constant time comparison"的技术来做比较。这种技术可以确保比较花费的时间不依赖比较的数据,从而防止 timing attack 类型的攻击。攻击者通过计算比较操作花费的时间,可以推断出一些关于数据的信息。例如,如果比较操作花费的时间和字节数有某种关系,攻击者就可以通过改变输入,观察比较操作花费时间的变化,从而推断出正确的 HMAC 值。

    以下是一个使用 crypto/hmac 包生成 HMAC 的例子,代码如下:

    1. package main
    2. import (
    3. "crypto/hmac"
    4. "crypto/sha256"
    5. "fmt"
    6. )
    7. func main() {
    8. key := []byte("secret key")
    9. data := []byte("message to authenticate")
    10. h := hmac.New(sha256.New, key)
    11. _, err := h.Write(data)
    12. if err != nil {
    13. fmt.Println("Error writing to HMAC:", err)
    14. return
    15. }
    16. result := h.Sum(nil)
    17. fmt.Printf("HMAC: %x\n", result)
    18. }

    这个例子是使用 SHA-256 作为底层的哈希函数,但也可以使用任何实现了 hash.Hash 接口的哈希函数。

    如何选择合适的哈希函数和密钥长度

    选择 HMAC 的哈希函数和密钥长度时,需要考虑以下几个因素:

    • 安全需求:安全需求是决定哈希函数和密钥长度选择的最重要因素。如果需要更高的安全性,应该选择更强大的哈希函数和更长的密钥。例如,SHA-256 或 SHA-3。
    • 性能需求:更强大的哈希函数和更长的密钥通常会更耗性能。如果系统对性能有严格的要求,可能需要在安全性和性能之间做出权衡。
    • 兼容性:如果系统需要与其他系统交互,可能需要选择一个与其他系统兼容的哈希函数和密钥长度。

    关于哈希函数,应该选择一个被广泛接受并且经过了严格安全检验的哈希函数。SHA-256 是被广泛接受的一种哈希算法,不仅提供了足够的安全性,并且在大多数现代硬件上都有很好的性能。

    关于密钥长度,一般来说,密钥的长度应该至少与哈希函数的输出长度相同。例如,如果使用了 SHA-256,那么密钥长度应该至少为256位。如果密钥太短,可能会降低 HMAC的安全性。如果密钥太长,浪费服务器资源不说,也不会进一步提高 HMAC 的安全性。所以,选择一个与哈希函数输出长度相同的密钥长度是一个好的选择。

    小结

    本文详细讲解了如何在 Golang 中实现 HMAC,首先介绍了 HMAC 的基本概念和用途。然后详细讲解了 HMAC 的工作原理,包括如何选择哈希函数和密钥。希望能帮助你理解和有效使用 HMAC 来提高程序的全性。

  • 相关阅读:
    Kafka生产者使用案例
    基于javaweb+mysql的甜品冰淇淋奶茶店网上订餐系统(前台、后台)
    【小笔记】当一个算法性能不满意,可能是这几方面的原因
    湖仓一体电商项目(十九):业务实现之编写写入DWS层业务代码
    请勿使用PostMessage来模拟键盘输入
    泛海微FH511单片机IC方案小家电LED照明MCU丝印FH511
    【算法|贪心算法系列No.2】leetcode2208. 将数组和减半的最少操作次数
    Redis6.0使用了多线程还能保证线程安全么?-Redis6.0 多线程精讲
    为什么没有办法画圆角?
    Java基础项目~用户管理系统
  • 原文地址:https://blog.csdn.net/luduoyuan/article/details/134341322