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 接口。
_, err := h.Write(data)
if err != nil {
	log.Fatal(err)
}
  • 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 的例子,代码如下:

package main

import (
	"crypto/hmac"
	"crypto/sha256"
	"fmt"
)

func main() {
	key := []byte("secret key")
	data := []byte("message to authenticate")
	h := hmac.New(sha256.New, key)
	_, err := h.Write(data)
	if err != nil {
		fmt.Println("Error writing to HMAC:", err)
		return
	}
	result := h.Sum(nil)
	fmt.Printf("HMAC: %x\n", result)
}

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

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

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

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

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

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

小结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
HMAC(Hash-based Message Authentication Code)是一种基于哈希函数的消息认证码,用于验证数据的完整性和真实性。 HMAC 的原理可以简单描述为:将密钥和消息一起输入哈希函数(如SHA-256),生成一个固定长度的哈希值。这个哈希值就是 HMAC。只有拥有相同密钥的人才能重新生成相同的 HMAC,因此 HMAC 可以用于验证消息的真实性和完整性。 具体来说,HMAC 的计算过程如下: 1. 选择一个合适的哈希函数 H(如 SHA-256)和一个密钥 K。 2. 对消息 M 进行填充(padding)。 3. 将填充后的消息 M 和密钥 K 输入哈希函数 H 计算出 HMAC 值。 HMAC = H((K ⊕ opad) || H((K ⊕ ipad) || M)) 其,|| 表示拼接操作,opad 和 ipad 是两个固定的常量,具体定义如下: opad = 0x5c5c5c5c… ipad = 0x36363636… 如果密钥 K 的长度小于哈希函数的块长度,则将密钥 K 填充至块长度。 如果密钥 K 的长度大于哈希函数的块长度,则将密钥 K 进行哈希运算,得到新的密钥 K',再将 K' 填充至块长度。 4. 将生成的 HMAC 值与接收到的 HMAC 值进行比较,如果相同,则消息 M 的真实性和完整性得到验证。 HMAC 的优点在于它不仅可以验证消息的完整性,还可以防止对密钥的攻击。由于 HMAC 使用了哈希函数,因此它具有不可逆性和雪崩效应,即使稍微修改了消息或密钥,生成的 HMAC 值也会有很大的变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

路多辛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值