什么是消息认证码
消息认证码是密码学家工具箱中6个重要的工具之一。回忆一下,这6个重要的工具分别是:对称密码、公钥密码、单向散列函数、消息认证码、数字签名和伪随机数生成器。
消息认证码(Message Authentication Code)是一种确认完整性并进行认证的计算,取三个单词的首字母,简称MAC。
根据任意长度的消息输出固定长度的数据,这一点和单向散列函数很类似。但是单向散列函数中计算散列值时不需要密钥,相对地,消息认证码中则需要使用发送者与接收者之间共享的密钥。
要计算MAC必须持有共享密钥,没有共享密钥的人就无法计算MAC值,消息认证码正是利用这一性质来完成认证的。此外,和单向散列函数的散列值一样,哪怕消息中发生1比特的变化,MAC值也会产生变化,消息认证码正是利用这一性质来确认完整性的。
单向散列函数与消息认证码对比
消息认证码的使用步骤
由于消息认证码中必须使用到密钥,所以也会出现密钥配送问题。与对称加密一样,密钥配送可以使用公钥密码、DH密钥交换等。
消息认证码的实现方法
使用单向散列函数实现
使用 SHA-2 之类的单向散列函数可以实现消息认证码,例如 HMAC。HMAC 中的 H 是 Hash 的意思。可以参考 RFC2104
任何高强度的单向散列函数都可以被用于 HMAC 中,例如 SHA-1、SHA-224、SHA-256、SHA-384、SHA-512 所构造的 HMAC,分别称为 HMAC-SHA1、HMAC-SHA-224、HMAC-SHA-256、HMAC-SHA-384、HMAC-SHA-512。
HMAC的步骤
1. 密钥填充
如果密钥比单向散列函数的分组长度要短,就需要在末尾填充 0,使最终长度和单向散列函数分组长度一样。
如果密钥比分组长度要长,则要用单向散列函数求出密钥的散列值,然后把这个散列值作为 HMAC 的密钥。
2. 密钥变换 I
将填充后的密钥和 ipad 的比特序列进行 XOR 计算。ipad 是 00110110 (16进制的 36)不断循环直到长度和分组长度一样长的比特序列。ipad 的 i 是 inner 内部的意思。
XOR 得到的最终结果是一个和单向散列函数的分组长度相同,且和密钥相关的比特序列。这个序列称为 ipadkey。
3. 与消息组合
把 ipadkey 附加在消息的开头。
4. 计算散列值
把第 3 步的结果输入单向散列函数,计算出散列值。
5. 密钥变换 II
将填充后的密钥和 opad 的比特序列进行 XOR 计算。opad 是 01011100 (16进制的 5C)不断循环直到长度和分组长度一样长的比特序列。opad 的 o 是 outer 外部的意思。
XOR 得到的最终结果是一个和单向散列函数的分组长度相同,且和密钥相关的比特序列。这个序列称为 opadkey。
6. 与散列值组合
把 opadkey 附加在散列值的开头。
7. 计算散列值
把第 6 步的结果输入单向散列函数,计算出散列值。这个散列值即为最终 MAC 值。
最终的 MAC 值一定是一个和输入消息以及密钥都相关的长度固定的比特序列。
使用分组密码实现
使用 AES 之类的分组密码可以实现消息认证码。分组密码的密钥作为共享密钥,利用 CBC 模式将消息全部加密。由于消息认证码中不需要解密,所以可以只留下最后一个分组,其他分组全部丢弃。CBC 模式的最后一个分组会受到整个消息以及密钥的双重影响,所以它可以作为 MAC 值。AES-CMAC (RFC4493) 就是一种基于 AES 来实现的消息认证码。
其他方法实现
使用流密码和公钥密码。
认证加密
2000 年以后,人们基于认证的研究更加进一步,产生了认证加密 (AE:Authenticated Encryption,AEAD:Authenticated Encryption with Associated Data)。认证加密是一种将对称密码和消息认证相结合的技术,同时满足加密性,完整性和认证性三大功能。
认证加密有几种,这里举例:例如 Encrypt-then-MAC,先用对称密码将明文加密,然后计算密文的 MAC 值。Encrypt-and-MAC,将明文用对称密码加密,并对明文计算 MAC 值。MAC-then-Encrypt,先计算明文的 MAC 值,然后将明文和 MAC 值同时用对称密码加密。在 HTTPS 中,一般使用 MAC-then-Encrypt 这种模式进行处理。
GCM(Galois/Counter Mode)是一种认证加密方式。GCM 中使用 AES 等 128 位比特分组密码的 CTR 模式,并使用一个反复进行加法和乘法运算的散列函数来计算 MAC 值。CTR 模式加密与 MAC 值的计算使用的是相同密钥,所以密钥管理很方便。专门用于消息认证码的 GCM 成为 GMAC。GCM 和 CCM (CBC Counter Mode) 都是被推荐的认证加密方式。
GCM
GCM相当于CTR+GMAC,具体方式如下所示:
- 首先对密文进行分组,使用CTR分组模式进行加密操作
- 对每个进行加密后的密文分组进行MAC计算
ChaCha20-Poly1305 是谷歌发明的一种算法,使用 ChaCha20 流密码进行加密运算,使用 Poly1305 算法进行 MAC 运算。
对消息认证码的攻击
重放攻击
窃听者不直接破解消息认证码,而是把它保存起来,反复利用,这种攻击就叫做重放攻击(replay attack)。
防止重放攻击可以有 3 种方法:
-
序号
每条消息都增加一个递增的序号,并且在计算 MAC 值的时候把序号也包含在消息中。这样攻击者如果不破解消息认证码就无法计算出正确的 MAC 值。这个方法的弊端是每条消息都需要多记录最后一个消息的序号。 -
时间戳
发送消息的时候包含当前时间,如果收到的时间与当前的不符,即便 MAC 值正确也认为是错误消息直接丢弃。这样也可以防御重放攻击。这个方法的弊端是,发送方和接收方的时钟必须一致,考虑到消息的延迟,所以需要在时间上留下一定的缓冲余地。这个缓冲之间还是会造成重放攻击的可趁之机。 -
nonce
在通信之前,接收者先向发送者发送一个一次性的随机数 nonce。发送者在消息中包含这个 nonce 并计算 MAC 值。由于每次 nonce 都会变化,因此无法进行重放攻击。这个方法的缺点会导致通信的数据量增加。
密钥推测攻击
消息认证码同样可以暴力破解以及生日攻击。消息认证码必须要保证不能通过 MAC 值推测出通信双方所使用的密钥。这一点可以通过单向散列函数的单向性和抗碰撞性来保证无法推测出密钥。
消息认证码无法解决的问题
消息认证码虽然可以证明双方发送的消息是一致的,没有篡改,也不存在中间人伪装。但是它无法 “对第三方证明” 和 “防止抵赖”。无法 “对第三方证明” 原因是因为消息认证码中用到的密钥是共享密钥,通信双方都有这个密钥,所以对第三方无法证明消息到底出自双方中的哪一方。
解决 “第三方证明” 的问题需要用到数字签名。
无法 “防止抵赖” 原因是也是因为消息认证码的共享密钥双方都有,无法判断消息是发自于哪一方。所以消息认证码无法防止否认(nonrepudiation)。
解决 “防止抵赖” 的问题需要用到数字签名。
总结
- 单向散列函数保证消息的一致性,完整性,没有被篡改。
- 消息认证码保证消息的一致性,完整性,没有被篡改,并且不存在中间人伪装。
- 数字签名保证消息的一致性,完整性,没有被篡改,并且不存在中间人伪装,并且能防止抵赖。
参考资料
该系列的主要内容来自《图解密码技术第三版》