八、消息认证码

1 本章概要

使用消息认证码可以确认自己受到的消息是否就是发送者的本意,也就是说,使用消息认证码可以判断消息是否被篡改,以及是否有人伪装成发送者发送了该消息。
消息认证码是密码学家工具箱中 6 个重要的工具之一。这 6 个重要工具分别是:对称密码、公钥密码、单向散列函数、消息认证码、数字签名和伪随机数生成器。

2 消息认证码

2.1 汇款请求是正确的吗

我们需要关注汇款请求的“完整性”和“认证”这两个性质。即汇款的内容以及汇款请求是否是正确的人发送的请求。
消息的完整性(integrity),就是我们在第七章介绍过的“消息没有被篡改”这一性质,完整性也叫一致性。如果消息完整,也就意味着消息没有被篡改。
消息的认证(authentication)指的是“消息来自正确的发送者”这一性质,如果能够确认汇款请求确实来自 Alice,就相当于对消息进行了认证,也就意味着消息不是其他人伪装成发送者所发出的。
本章中介绍的消息认证码,我们就可以同时识别出篡改和伪装,也就是既可以确认消息的完整性,也可以进行认证。

2.2 什么是消息认证码

消息认证码(message authentication code)是一种确认完整性并进行认证的技术,简称为 MAC
消息认证码的输入包括任意长度的消息和一个发送者和接收者之间共享的秘钥,它可以输出固定长度的数据,这个数据称为 MAC 值。
根据任意长度的消息输出固定长度的数据,这一点和单向散列函数很类似。但是单向散列函数中计算散列值不需要秘钥,而消息认证码则需要使用发送者和接收者之间共享的秘钥。
要计算 MAC 必须持有共享秘钥,没有共享秘钥的人就无法计算 MAC 值,消息认证码正是利用这一性质来完成认证的。此外,和单向散列函数的散列值一样,哪怕消息中发生 1 比特的变化, MAC 值也会产生变化,消息认证码正是利用这一性质来确认完整性的。

后面我们会讲到,消息认证码有很多实现方法,大家可以暂且这样理解:消息认证码是一种与秘钥相关联的单向散列函数

2.3 消息认证码的使用步骤

以 Alice 银行和 Bob 银行的故事为例,来讲解一下消息认证码的使用步骤。

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

2.4 消息认证码的秘钥配送问题

发送者和接收者需要共享秘钥,这一点和我们在第三章中介绍的对称密码很相似。实际上,对称密码的秘钥配送问题在消息认证码中也同样会发生。要解决秘钥配送问题,我们需要像对称密码一样使用一些共享秘钥的方法,例如公钥密码、Diffie-Hellman 秘钥交换、秘钥分配中心,或者使用其它安全的方式发送秘钥等。

3 消息认证码的应用实例

3.1 SWIFT

SWIFT 的全称是 Society for Worldwide Interbank Financial Telecommunication(环球银行金融电信协会),其目的是为国际银行间的交易保驾护航。银行和银行之间是通过 SWIFT 来传递交易消息的。而为了确认消息的完整性以及对消息进行验证, SWIFT 中使用了消息认证码。
在使用公钥密码进行秘钥交换之前,消息认证码所使用的共享秘钥都是由人来进行配送的。

3.2 IPsec

IPsec 是对互联网基本通信协议——IP协议(Internet Protocol)增加安全性的一种方式。在 IPsec 中,对通信内容的认证和完整性校验都是采用消息认证码来完成的。

3.3 SSL/TLS

SSL/TLS 中对通信内容的认证和完整性校验也使用了消息认证码,将在第十四章详解。

4 消息认证码的实现方法

4.1 使用单向散列函数实现

使用 SHA-1、MD5 之类的单向散列函数可以实现消息认证码,其中一种实现方法称为 HMAC,具体将在下节介绍。

4.2 使用分组密码实现

使用 DES、AES 之类的分组密码可以实现消息认证码。
将分组密码的秘钥作为消息认证码的共享秘钥来使用。

4.3 其它实现方法

使用流密码和公钥密码等也可以实现消息认证码。

5 HMAC 的详细介绍

5.1 什么是 HMAC

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

5.2 HMAC 的步骤

1.秘钥填充

如果秘钥比单向散列函数的分组长度要短,就需要在末尾填充 0 ,直到其长度达到单向散列函数的分组长度为止。
如果秘钥比分组长度要长,则要用单向散列函数求出秘钥的散列值,然后将这个散列值用作 HMAC 的秘钥。 HMAC-SHA-1 的分组长度为 516 比特。

2.填充后的秘钥与 ipad 的 XOR

将填充后的秘钥与被称为 ipad 的比特序列进行 XOR 运算。ipad 是将 001100110 这一比特序列(即 16 进制的 36)不断循环反复直到达到分组长度所形成的比特序列,其中 ipad 的 i 是 inner 的意思。
XOR 运算所得到的值,就是一个和单向散列函数的分组长度相同,且和秘钥相关的比特序列。这里我们将这个比特序列称为 ipadkey。

3.与消息组合

随后,将 ipadkey 与消息进行组合,也就是将和秘钥相关的比特序列(ipadkey)附加在消息的开头。

4.计算散列值

将第三步的结果输入单向散列函数,并计算出散列值。

5.填充后的秘钥与 opad 的 XOR

将填充后的秘钥与被称为 opad 的比特序列进行 XOR 运算。opad 是将 01011100 这一比特序列(即 16 禁止的 5C)不断循环反复直到达到分组长度所形成的比特序列,其中 opad 的 o 是 outer 的意思。
XOR 运算所得到的结果也是一个和单向散列函数的分组长度相同,且和秘钥相关的比特序列。我们将这个比特序列称为 opadkey。

6. 与散列值组合

将第四步的散列值拼在 opadkey 后面。

7.计算散列值

将第六步的结果输入单向散列函数,并计算出散列值,这个散列值就是最终的 MAC 值。
通过上述流程我们可以看出,最后得到的 MAC 值,一定是一个和输入的消息以及秘钥都相关的长度固定的比特序列。

6 对消息认证码的攻击

6.1 重放攻击

Mallory 想到可以通过将事先保存的正确 MAC 值不断重放来发动攻击,如果这种攻击成功的话,就可以让 100 万元滚雪球到 1 亿元。

  1. Mallory 到 Alice 银行向自己在 Bob 银行中的账户 汇款 100 万元。于是 Alice 银行为该汇款请求消息计算出正确的 MAC 值,然后将 MAC 和消息一起发送给 Bob 银行。
  2. Bob 银行用收到的消息自行计算 MAC 值,并与收到的 MAC 值进行对比,由于两个值相等,因此 Bob 银行向 Mallory 的账户汇款 100 万元。
  3. Mallory 窃听了 Alice 银行发给 Bob 银行的汇款请求消息以及 MAC 值,并保存在自己的计算机中。
  4. Mallory 将刚刚保存下来的汇款请求消息以及 MAC 值再次发给 Bob 银行。
  5. Bob 银行重复第二步,于是给 Mallory 的账户汇款 100 万元。
  6. Mallory 继续重复第四步。
  7. Bob 银行重复第五步。

有几种方法可以防御重放攻击。

1.序号

约定每次都对发送的消息赋予一个递增的序号,并且在计算 MAC 值时将序号也包含在消息中。这样,由于 Mallory 无法计算序号递增之后的 MAC 值,因此就可以防御重放攻击。这个方法有效,但是对每个通信对象都需要记录最后一个消息的序号。

2.时间戳

约定在发送消息时包含当前的时间,但是发送者和接收者的时钟必须一致,而且考虑到通信的延迟,必须在时间的判断上留下缓冲,于是多多少少还是会存在可以进行重放攻击的空间。

3.nonce

在通信之前,接收者先向发送者发送一个一次性的随机数,这个随机数一般称为 nonce。发送者在消息中包含这个 nonce 并计算 MAC 值。由于每次通信时 nonce 的值都会发生变化,因此无法进行重放攻击。虽然有效,但通信的数据量会有所增加。

6.2 密码推测攻击

和对单向散列函数的攻击一样,对消息认证码也可以进行暴力破解以及生日攻击(7.6.2节)。
对于消息认证码来说,应保证不能根据 MAC 值推测出通信双方所使用的秘钥。如果 Mallory 能够从 MAC 值反算出秘钥,就可以进行篡改、伪装等攻击。例如 HMAC 中就是利用单向散列函数的单向性和抗碰撞性来保证无法根据 MAC 值推测出秘钥的。
此外,在生成消息认证码所使用的秘钥,必须用高强度的伪随机数生成器。

7 消息认证码无法解决的问题

7.1 对第三方证明

假设 Bob 想要向第三方验证着 Victor 证明这条消息的却是 Alice 发送的,但是用消息认证码无法进行这样的证明,因为,Victor 要校验 MAC 值,就需要知道 Alice 和 Bob 之间共享的秘钥,假设 Bob 将秘钥告诉 Victor,但是 Victor 有理由相信,这条消息有可能是 Bob 伪装 Alice 发送的。使用第九章的数字签名就可以实现对第三方的证明。

7.2 防止否认

假设 Bob 收到了包含 MAC 值得消息,这个 MAC 值是用 Alice 和 Bob 共享的秘钥计算出来的,因此 Bob 能够判断这条消息的确来自 Alice。但是, Alice 可以说“这条消息是 Bob 自己编的吧”,说白了,就是 Alice 和 Bob 吵起来了。
即便 Bob 拿 MAC 值举证,Victor 也无法判断 Alice 和 Bob 谁才是正确的,也就是说,用消息认证码无法防止否认(nonrepudiation)。这种情况,数字签名同样可以实现防止否认。

8 本章小结

本章介绍的消息认证码,是对消息进行认证并确认其完整性的技术,通过使用发送者和接收者之间共享的秘钥,就可以识别出是否存在伪装和篡改行为。
其可以使用单向散列函数和对称密码等技术来实现,本章重点介绍了通过单向散列函数来实现的 HMAC。
消息认证码的缺点在于,由于发送者和接收者共享相同的秘钥,因此会产生无法对第三方证明以及无法否认等问题。
下一章的数字签名可以解决这些问题。

9 小测验

  1. 使用消息认证码能够确保消息的机密性。注:消息本身的机密性不是由消息认证码决定的。
  2. 使用消息认证码能够识别出篡改行为。
  3. 使用消息认证码需要发送者和接收者之间共享的秘钥。
  4. 使用消息认证码能够防止否认。