前情提要
简介
消息验证码算法(也称为MAC算法)的作用是防止通信过程中消息被篡改和伪造,保证了消息的完整性和真实性。
假设有这样一个API,返回最近几天的天气状况,由于天气信息是公开的,不需要进行加密通信,但明文通信可能存在以下几个问题:
- 完整性破坏:某人截获了数据包并修改数据内容,使得API调用方获得了虚假数据
- 真实性破坏:API提供方尚未返回数据,但是被某个中间人伪造了一份数据返回
消息验证码的出现正是解决此类问题的
MAC算法使用非常简单,就是消息发送方根据<原消息, 密钥>计算出MAC值,和消息一起发送给接收方;接收方收到消息后,重复上述步骤计算出MAC值,和传递来的MAC值对比,如果不同,说明消息被篡改,则立即丢弃
常用算法
密码学中,MAC算法主要由两种形式:
- CBC-MAC (Cipher Block Chaining Message Authentication Code):从对称加密中的CBC迭代模式演变而来,通常用于保护短消息的完整性,例如消息的头部信息或消息的摘要信息。它也可以用于保护长消息的完整性,但需要将长消息分成多个短消息进行加密。
- HMAC (Hash-based Message Authentication Code):HMAC算法使用Hash算法作为加密基元,HMAC结合Hash算法有多种变种,比如HMAC-SHA-1、HMAC-SHA256、HMAC-SHA512,也是在HTTP MAC算法中应用最多的。通常用于保护长消息的完整性,也可以用于加密文件或大型数据流,因为哈希函数可以处理任意长度的数据。
基于Go的HMAC算法实现的使用示例
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"fmt"
)
// 计算消息验证码
func generateHMAC(message []byte, key []byte) string {
hash := hmac.New(sha256.New, key)
hash.Write(message)
// 将计算得到的 HMAC 值转换为 16 进制字符串
return hex.EncodeToString(hash.Sum(nil))
}
// 验证消息验证码是否正确
func verifyHMAC(message []byte, key []byte, expectedMAC string) bool {
// 计算消息的 HMAC 值
mac := generateHMAC(message, key)
// 比较计算得到的 HMAC 值和期望的 HMAC 值是否相同
return hmac.Equal([]byte(mac), []byte(expectedMAC))
}
实现原理
下面分别介绍下CBC-MAC和HMAC算法实现原理:
CBC-MAC
CBC-MAC算法是基于对称密钥的加密算法,它使用块密码算法(如AES)和CBC模式进行加密,并将最后一个加密块的输出作为消息验证码
计算MAC过程
- 将待加密的消息划分为若干个固定长度的块(一般为64位或128位)
- 选择一个随机的
密钥K,将其作为加密算法的输入,并使用该密钥对第一个消息块进行加密 - 对于后续的每一个消息块,都将其与前一个消息块的加密结果进行异或操作,然后再使用
密钥K对异或的结果进行加密 - 将最后一个加密结果作为消息的认证码(MAC),用于验证消息的完整性和真实性
细心的读者发现了CBC-MAC这和对称加密算法中的CBC模式非常相似,最终的MAC值即为最后一个分组的加密值,这也是它为什么被称为CBC-MAC的原因
那如果我们使用了对称加密,是不是就不需要MAC算法了呢,换句话说,对称加密算法是不是天然具备了MAC算法呢?答案是否定的,对称加密并不能代替MAC,主要原因在于攻击者可以篡改部分加密后信息,使得消息可以被解密,但是解密出来的结果不是原文
HMAC
HMAC是一种基于哈希函数的消息验证码算法。它的原理是将消息与密钥结合起来进行哈希计算,从而生成消息验证码,以确保消息的完整性和真实性
计算MAC过程
在HMAC算法中,使用一个密钥K和一个消息M作为输入,通过一个特定的哈希函数H来生成消息验证码,其计算过程如下:
- 密钥长度调整:如果密钥长度超过
哈希函数H的块长度,则将密钥K进行哈希,生成一个长度为H的输出 - 密钥填充:将
密钥K在前面填充0,使其长度等于哈希函数H的块长度 - 内部哈希值计算:将填充后的
密钥K与消息M进行异或运算,得到一个长度等于块长度的结果,然后将该结果作为初始哈希值计算得到一个内部哈希值 - 最终哈希值计算:将填充后的
密钥K与内部哈希值进行异或运算,得到一个长度等于块长度的结果,然后将该结果作为初始哈希值计算得到最终哈希值 - 消息验证码生成:将最终哈希值作为消息验证码输出
HMAC的过程就是多次HASH和密钥的运算,说的简单一点,就是一个带加密运算的HASH
那为什么我们不直接使用HASH函数作为MAC算法呢,主要就是在于防止中间人攻击。攻击人不能仅修改消息值,但是它可以通过修改消息值并重新计算HASH值来达到伪造的目的,引入密钥正是为了解决此类问题
总结
本文通过CBC-MAC和常用的HMAC算法介绍了消息验证码算法,相信大家对消息验证有了一定的了解。下篇我们开始介绍HTTPS的核心算法-非对称加密,以及围绕非对称加密的系列密码套件组合使用方式和场景~