消息认证码(message authentication code)是一种确认完整性并进行认证的技术,取三个单词的首字母,简称为MAC。

– 保证数据未被篡改
– 对发送者进行身份认证

1. 发送者Alice与接收者Bob事先共享密钥。
2. 发送者Alice根据汇款请求消息计算MAC值(使用共享密钥)。
3. 发送者Alice将汇款请求消息和MAC值两者发送给接收者Bob。
4. 接收者Bob根据接收到的汇款请求消息计算MAC值(使用共享密钥)。
5. 接收者Bob将自己计算的MAC值与从Alice处收到的MAC值进行对比。
6. 如果两个MAC值一致,则接收者Bob就可以断定汇款请求的确来自Alice(认证成功);如果不一致,则可以断定消息不是来自Alice(认证失败)。

MAC使用场景
## 1. SWIFT
环球银行金融电信协会,是一个组织,为银行间的交易报价护航。银行间交互使用了SWIFT进行交互,这里面对消息的完成性和身份验证,就是使用了消息认证码。
– 最初使用消息认证码,由人工配送秘钥
– 后来使用公钥

## 2. https
– ssl/tls协议,里面的握手协议使用了消息认证码
– https = http + ssl/tls(security socket layer)

## 3. IPSec
– IP协议的增强版,使用了消息认证码

HMAC
==H代表哈希==

HMAC是一种使用单向散列函数来构造消息认证码的方法(RFC2104),其中HMAC的H就是Hash的意思。
HMAC中所使用的单向散列函数并不仅限于一种,任何高强度的单向散列函数都可以被用于HMAC,如果将来设计出新的单向散列函数,也同样可以使用。
使用SHA-I、MD5、RIPEMD-160所构造的HMAC,分别称为HMAC-SHA-1、HMAC-MD5和HMAC-RlPEMD。

//接收端和验证端都要执行
//New函数返回一个采用hash.Hash作为底层hash接口、key作为密钥的HMAC算法的hash接口。
func New(h func() hash.Hash, key []byte) hash.Hash

– 参数1:自己指定哈希算法, 是一个函数
– md5.New
– sha1.New
– sha256.New

– 参数2:秘钥
– 返回值:哈希函数对象

//仅在验证端执行
//比较两个MAC是否相同,而不会泄露对比时间信息。(以规避时间侧信道攻击:指通过计算比较时花费的时间的长短来获取密码的信息,用于密码破解)
func Equal(mac1, mac2 []byte) bool
– 参数1:自己计算的哈希值
– 参数2:接收到的哈希值
– 返回值:对比结果

package main

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

/*
//接收端和验证端都要执行
//New函数返回一个采用hash.Hash作为底层hash接口、key作为密钥的HMAC算法的hash接口。
func New(h func() hash.Hash, key []byte) hash.Hash

- 参数1:自己指定哈希算法, 是一个函数
- md5.New
- sha1.New
- sha256.New

- 参数2:秘钥
- 返回值:哈希函数对象


//仅在验证端执行
//比较两个MAC是否相同,而不会泄露对比时间信息。(以规避时间侧信道攻击:指通过计算比较时花费的时间的长短来获取密码的信息,用于密码破解)
func Equal(mac1, mac2 []byte) bool
- 参数1:自己计算的哈希值
- 参数2:接收到的哈希值
- 返回值:对比结果
*/

//生成hmac(消息认证码)
func generateHMAC(src []byte, key []byte) []byte {
	//1. 创建哈希器
	hasher := hmac.New(sha256.New, key)

	//2. 生成mac值
	//mac := hasher.Sum(src)
	hasher.Write(src)

	mac := hasher.Sum(nil)

	return mac
}

//认证mac
func verifyHMAC(src, key, mac1 []byte) bool {
	//1. 对端接收到的源数据

	//2. 对端接收到的mac1

	//3. 对端计算本地的mac2
	mac2 := generateHMAC(src, key)

	//4. 对比mac1与mac2
	return hmac.Equal(mac1, mac2)
}

func main() {
	src := []byte("hello world")
	key := []byte("1234567890")

	mac1 := generateHMAC(src, key)

	fmt.Printf("mac1 : %x\n", mac1)

	isEqual := verifyHMAC(src, key, mac1)

	fmt.Printf("isEqual : %v\n", isEqual)

	srcChanged := []byte("hello world!!!!!")

	isEqual = verifyHMAC(srcChanged, key, mac1)

	fmt.Printf("after changed, isEqual : %v\n", isEqual)
}