算法HMAC的使用步骤

举报
码乐 发表于 2025/01/10 14:23:41 2025/01/10
2.1k+ 0 0
【摘要】 1 简介本文详细分析HMAC通过密码和订单数据生成签名的步骤,并展示使用go实现一个例子展示HMAC如何计算和校验的 2 HMAC(Hash-based Message Authentication Code)概述HMAC 是基于哈希算法的一种消息认证码,它通过一个密钥和一个消息(数据)来生成一个签名(哈希值)。该签名是消息内容的“指纹”,可以确保消息的完整性和身份验证。只有知道密钥的双方...

1 简介

本文详细分析HMAC通过密码和订单数据生成签名的步骤,并展示使用go实现一个例子展示HMAC如何计算和校验的

2 HMAC(Hash-based Message Authentication Code)概述

HMAC 是基于哈希算法的一种消息认证码,它通过一个密钥和一个消息(数据)来生成一个签名(哈希值)。该签名是消息内容的“指纹”,可以确保消息的完整性和身份验证。只有知道密钥的双方才能计算和验证签名。

HMAC的基本计算步骤如下:

使用一个密钥和消息数据结合起来。
通过哈希算法(如 SHA-256)计算一个哈希值。
得到的哈希值就是HMAC签名。

接收方用相同的密钥对消息重新计算HMAC签名,并与发送方提供的签名进行对比,若匹配则验证通过。

3 HMAC 生成签名的步骤

准备数据:消息和密钥。

生成密钥的内外填充(Inner and Outer padding):HMAC算法会使用特定的填充方式,将密钥填充成一个固定长度的值,以适应哈希算法。

计算HMAC:首先计算内层哈希,然后计算外层哈希,最终得到HMAC签名。

HMAC 计算流程:

对消息 message 和密钥 key 进行组合。
使用 SHA-256 等哈希算法生成消息的哈希值。
计算内外两次哈希的结果,生成最终的签名。

4 实现 HMAC 签名计算和验证

下面是一个使用 Go 语言实现的例子,展示如何生成和验证 HMAC 签名。

代码实现

	package main

	import (
		"crypto/hmac"
		"crypto/sha256"
		"encoding/base64"
		"fmt"
		"log"
	)

	// 生成 HMAC 签名
	func generateHMACSignature(message, secret string) (string, error) {
		// 创建一个 HMAC 对象,使用 SHA-256 哈希算法和 secret 密钥
		mac := hmac.New(sha256.New, []byte(secret))

		// 写入消息内容
		_, err := mac.Write([]byte(message))
		if err != nil {
			return "", err
		}

		// 计算哈希并将其编码为 Base64 字符串
		signature := base64.StdEncoding.EncodeToString(mac.Sum(nil))
		return signature, nil
	}

	// 验证 HMAC 签名
	func verifyHMACSignature(message, signature, secret string) bool {
		// 使用相同的密钥生成签名
		expectedSignature, err := generateHMACSignature(message, secret)
		if err != nil {
			log.Println("Error generating signature:", err)
			return false
		}

		// 将生成的签名与传入的签名进行比较
		return hmac.Equal([]byte(expectedSignature), []byte(signature))
	}

	func main() {
		// 示例消息和密钥
		message := "OrderID=12345&Amount=199.99&CustomerID=67890"
		secret := "supersecretkey"

		// 生成 HMAC 签名
		signature, err := generateHMACSignature(message, secret)
		if err != nil {
			log.Fatalf("Error generating HMAC signature: %v", err)
		}

		// 打印生成的签名
		fmt.Println("Generated HMAC Signature:", signature)

		// 验证 HMAC 签名
		valid := verifyHMACSignature(message, signature, secret)
		if valid {
			fmt.Println("HMAC Signature is valid!")
		} else {
			fmt.Println("HMAC Signature is invalid!")
		}

		// 模拟一个错误的签名
		invalidSignature := "invalid_signature"
		invalid := verifyHMACSignature(message, invalidSignature, secret)
		if invalid {
			fmt.Println("Invalid signature was accepted, this should not happen!")
		} else {
			fmt.Println("Correctly rejected invalid signature.")
		}
	}

代码解析

  1. 生成HMAC签名(generateHMACSignature 函数)

输入:消息 (message) 和密钥 (secret)。
创建 HMAC 对象:使用 Go 内置的 hmac.New 函数与指定的哈希算法(这里使用 SHA-256)以及密钥来创建一个 HMAC 对象。
写入消息:使用 mac.Write 方法将消息写入 HMAC 对象。
计算 HMAC 签名:使用 mac.Sum(nil) 计算最终的 HMAC 签名并返回。
返回 Base64 编码:HMAC 签名是一个二进制数据,我们将其编码为 Base64 格式,以便于传输或存储。

  1. 验证HMAC签名(verifyHMACSignature 函数)
    输入:消息 (message)、签名 (signature) 和密钥 (secret)。
    重新生成签名:使用相同的消息和密钥重新计算 HMAC 签名。
    比较签名:将生成的签名与接收到的签名进行比较,若一致则验证通过,返回 true,否则返回 false。

  2. 示例输出

生成一个签名并打印出来:

	Generated HMAC Signature: cXkdVxGeK9S+PjV9phkT+7eb9Gg2RlR3zKX4BvIHqys=

验证签名是否有效:

	HMAC Signature is valid!

模拟传入错误签名并验证:

	Correctly rejected invalid signature.

HMAC如何保障不可抵赖性

密钥绑定签名:

HMAC签名使用了密钥(用户的密码或共享密钥)和消息(订单数据)进行计算。签名和数据是紧密绑定的,无法单独伪造签名而不改变数据,也无法篡改数据而不使签名失效。

用户身份验证:

因为签名的生成和验证依赖于一个私密的密钥,只有持有正确密钥的用户(或系统)才能计算正确的签名,因此系统能够确认是该用户(或系统)执行了操作,从而防止了用户否认的行为。
HMAC如何避免重放攻击

时间戳或唯一标识符:

为了避免重放攻击,HMAC通常会与时间戳或唯一标识符(如订单ID)一起使用。这使得每次请求都有一个唯一的签名,即使是相同的数据,由于时间戳的不同,每次生成的签名也不同。

验证时间有效性:

服务器可以根据时间戳判断请求是否在有效时间窗口内(例如5分钟)。如果时间戳过旧,则拒绝该请求,防止攻击者重放旧请求。

5 总结

HMAC通过结合消息内容和密钥生成一个唯一的签名,使得只有持有正确密钥的用户才能生成有效签名,从而保证了消息的完整性和不可抵赖性。

同时,通过结合时间戳和签名,HMAC可以防止重放攻击,因为每个签名都会与时间或唯一标识符绑定,避免重复使用相同的签名。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。