## 消息验证码是怎么工作的?
既然消息验证码可以同时满足我们的三个条件,那么消息验证码是怎么工作的?
首先,我们来看使用消息验证码的前提,就是信息的发送方和接收方要持有相同的密钥,这和我们前面讨论的对称密钥的条件是一样的。能够使用对称密钥的场景,都能够满足这个前提。
另外,信息的发送方和接收方要使用相同的消息验证函数。这个函数的输入数据就是对称密钥和待验证信息。信息的发送方使用消息验证函数,可以生成消息验证码。
接下来,信息发送方把待验证信息和消息验证码都发送给信息接收方。信息接收方使用相同的消息验证函数和对称密钥,以及接收到的待验证信息,生成消息验证码。
然后,信息接收方对比接收到的消息验证码和自己生成的消息验证码。如果两个消息验证码是一样的,就表明待验证信息不是伪造的信息。否则,待验证信息就是被篡改过的信息。
这听起来是一个不错的方案。不过,消息验证函数需要使用对称密钥,输入任意大小的数据,输出为一小段数据。什么样的消息验证函数能够承担起这样的任务呢?
通常的对称密钥算法,密文数据不会小于明文数据,这样的话,就不能满足验证数据小的要求。因此,通常的对称密钥算法,我们并不能当做消息验证函数使用。
那么,我们到底该怎么选择消息验证函数?
## 该怎么选择消息验证函数?
我刚才提到,消息验证函数的输出应该是一小段数据,这一点有没有让你想起,我们前面提到的单向散列函数?我们再来回顾一下单向散列函数的三个特点:
- 正向计算容易,逆向运算困难;
- 运算结果均匀分布,构造碰撞困难;
- 给定数据的散列值是确定的,长度固定。
如果你再回头看看,我们上面讨论的消息验证的三个条件,单向散列函数就能够完美地满足这三个条件。那么,对称密钥怎么和单向散列函数结合起来,构造出消息验证函数呢?**最常见的方案就是基于单向散列函数的消息验证码。**
基于单向散列函数的消息验证码(Hash-based Message Authentication Code, HMAC)这个名字是不是听起来太长了,所以我们通常使用它的简称HMAC。
在HMAC的算法里,单向散列函数的输入数据是由对称密钥和待验证消息构造出来的。到目前为止,这种构造方法还没有明显的安全问题,我们不再讨论构造细节。如果你感兴趣,可以查阅1997年发表的RFC 2104。
一个密码学算法经历了二十多年还没有明显的安全漏洞,这真的是很难得!
不过,你需要注意的是,HMAC算法并不使用我们前面讨论过的链接模式。所以,对称密钥链接模式的各种安全问题并不会影响HMAC算法的安全性。
## 为什么需要对称密钥?
到这里,你是不是早就有了一个疑问,消息验证函数为什么还需要对称密钥呢?我们前面提到,单向散列函数也可以验证数据的完整性。为什么它不直接使用单向散列函数呢?
还记得吗?我们前面在讨论单向散列函数解决数据完整性问题的时候,还有一个遗留的问题,就是怎么获得原始数据的散列值。对称密钥就是用来解决这个问题的。
我们先来看看,如果没有对称密钥的加入,消息验证码还能不能工作。
信息发送方把待验证信息和消息验证码都发送给信息接收方。假设存在一个中间攻击者,能够解开待验证信息和消息验证码。由于单向散列函数是公开的算法,中间攻击者就可以篡改待验证信息,重新生成消息验证码。
然后,中间攻击者把篡改的信息和篡改的验证码发给信息接收方。篡改的信息和篡改的验证码能够通过信息接收方的信息验证。也就是说,这样的话,信息接收方就没有办法识别出这个信息是不是原始的、没有篡改的信息。这样,信息验证就失效了。
可是,如果对称密钥参与了消息验证码的运算,由于中间攻击者并不知道对称密钥的数据,攻击者就很难伪造出一个能够通过验证的消息验证码。换一个说法,**对称密钥的参与,是为了确保散列值来源于原始数据,而不是篡改的数据。**
有了对称密钥这个私有数据的参与,消息验证码的算法是不是就没有安全漏洞了呢?
## 怎么计算HMAC算法的强度?
HMAC算法与对称密钥和单向散列函数息息相关,所以,对称密钥的安全强度和单向散列函数的安全强度,都会影响HMAC算法的安全强度。该怎么计算HMAC算法的安全强度呢?
严格的来说,HMAC算法的安全强度,是由对称密钥的安全强度和两倍的散列值长度之间较小的那个数值决定的。比如,如果我们选择256位的对称密钥,以及散列值长度是160位的SHA-1。
两倍的散列值长度就是320位。那么,在256位和320位两个数值之间,256位是较小的数值。那么,这个HMAC运算的安全强度就是256位。
一般来说,两倍的散列值长度通常大于流行对称密钥强度。所以,HMAC算法的强度,通常也是由对称密钥决定。简单起见,**对于流行的HMAC算法,我们只需要考虑对称密钥的安全强度**。
## 有哪些常见的HMAC算法?
HMAC算法是由单向散列函数的算法确定的。下面的表格,我列出了一些常见的算法。同样的,我们把HMAC算法也按照退役的、遗留的以及现行的算法来分类。

其中,**HmacSHA256和HmacSHA384是目前最流行的两个HMAC算法**。和以前的讨论一样,为了最大限度的互操作性和兼容性,我们应该选择当前最流行的算法。
如果单独的加密并不能解决信息的有效传递问题,有没有加密算法,能够综合考虑信息的机密性和完整性?如果存在这样的算法,我们就不需要额外设计消息验证码了。下一次,我们来讨论这个问题。
## Take Away(今日收获)
今天,我们讨论了防止数据被调包的技术,也就是消息验证码。我们讨论了消息验证码要解决的问题,以及消息验证码的工作原理。我们还谈到如何选择消息验证函数,最常见的方案就是选择基于单向散列函数的消息验证码,也就是HMAC。
为什么我们需要对称密钥?其实是为了解决单向散列函数的遗留问题,因为对称密钥的参与,可以确保散列值来源于原始数据,而不是篡改的数据。
最后,我们还研究了怎么计算HMAC算法的强度,还列出了目前常见的HMAC算法。我们应该选择当前最流行的算法,而对于流行的HMAC算法,我们只需要考虑对称密钥的安全强度。
通过今天的讨论,我们要:
- 了解消息验证码要解决的问题;
- 尽量选用现行的、流行的算法:HmacSHA256和HmacSHA384。
## 思考题
今天的思考题,是一个复习题,也是一个改进的题目。
我们前面讨论过的牛郎织女的约会问题。我们再来看看现在,我们有没有更好的办法解决这个问题。如果牛郎要给织女发信息,七夕相约鹊桥会。
>
织女:
七月初七晚七点,鹊桥相会。不见不散。
牛郎