密码学入门(6):消息认证码
上次讲到的单向散列函数只能保证数据传输的完整性,不能提供认证功能,即 Bob 不能确定消息是否来自 Alice,只能确定消息是完整的,没有被篡改。
假设有以下场景,现在 Alice 和 Bob 分别是两家银行:
- Alice 银行向 Bob 银行发送一条汇款请求:从账户 A 向账户 B 汇款1000万元。
- Bob 银行能保证收到的汇款请求与 Alice 银行所发送的内容完全一致,如果主动攻击者 Mallory 在中途将汇款请求进行了篡改,Bob 银行能识别出这种篡改。
- 但现在问题是,汇款请求到底是不是 Alice 银行发送的?有可能 Alice 银行根本就没有发送过汇款请求,而是由主动攻击者 Mallory 伪装成 Alice 银行发送的。
所以我们除了要关注汇款请求(消息)的“完整性”,还要关注“认证”问题,即“消息是否来自正确的发送者”。下面要介绍的消息认证码即能保证消息的完整性,还能对消息进行认证。
什么是消息认证码?
消息认证码(Message Authentication Code)是一种确认完整性并进行认证的技术,简称为MAC。
消息认证码的输入为任意长度的消息和一个发送者与接收者之间共享的密钥,它可以输出固定长度的数据,这个数据称为 MAC 值。
根据任意长度的消息输出固定长度的数据,这一点和单向散列函数很类似。但由于计算 MAC 值必须持有共享密钥,没有共享密钥的人就无法计算 MAC 值,因此消息认证码利用这一性质来完成认证。此外,消息认证码和单向散列函数一样具有雪崩效应,哪怕消息中发生 1 1 1比特的变化,也会导致 MAC 值发生不可区分的改变。
消息认证码有多种实现方式,我们可以先简单的将其理解为:消息认证码是一种与密钥相关联的单向散列函数:
我们仍然假设 Alice 和 Bob 是两家银行,消息认证码的使用步骤如下:
消息认证码的密钥配送问题:由于发送者和接收者之间需要共享密钥,这一点和对称密码很相似。实际上,对称密码的密钥配送问题在消息认证码中同样会发生。要解决该问题,我们需要像对称密码一样使用一些共享密钥的方法,至于使用哪种配送方法,需要根据具体的目的来进行选择。
消息认证码的实现方式
使用 AES之 类的分组密码可以实现消息认证码。
我们将分组密码的密钥作为消息认证码的共享密钥来使用,并用 CBC 模式将消息全部加密,然后将最后一个密文分组用作 MAC 值。这是因为 CBC 模式的最后一个分组会受到整个消息以及密钥的双重影响,因此可以将它用作消息认证码。
下面我们来看一下使用单向散列函数实现的消息认证码:HMAC。
HMAC
HMAC是一种使用单向散列函数来构造消息认证码的方法,其中 HMAC 的 H 就是 Hash 的意思。
HMAC 中使用的单向散列函数并不局限于一种,任何高强度的单向散列函数都可以被用于 HMAC。例如用 SHA-256、SHA-512 所构造的 HMAC,分别称为 HMAC-SHA-256、HMAC-SHA-512。
HMAC 的步骤:
- 密钥填充
- 如果密钥比单向散列函数的分组长度要短,就在密钥的末尾填充 0 0 0。
- 如果密钥比分组长度长,则用单向散列函数求出密钥的散列值,然后将这个散列值用作HMAC的密钥。
- 填充后的密钥与 ipad 的 XOR
- 将填充后的密钥与被称为 ipad 的比特序列进行 XOR 运算。ipad 是将
00110110
(0x36
)不断循环反复直到分组长度所形成的比特序列,其中 ipad 的 i 是 inner(内部)的意思。 - XOR 运算所得到的值,就是一个和单向散列函数分组长度相同,且和密钥相关的比特序列,这个比特序列称为 ipadkey。
- 将填充后的密钥与被称为 ipad 的比特序列进行 XOR 运算。ipad 是将
- 与消息组合:将 ipadkey 附加在消息的开头。
- 计算散列值:将 ( 3 ) (3) (3)的结果输入单向散列函数,并计算出散列值。
- 填充后的密钥与 opad 的 XOR
- 将填充后的密钥与被称为 opad 的比特序列进行 XOR 运算。opad 是将
01011100
(0x5C
)不断循环反复直到分组长度所形成的比特序列,其中 opad 的 o 是 outer(外部)的意思。 - XOR 运算所得到的值也是一个和单向散列函数分组长度相同,且和密钥相关的比特序列,这个比特序列称为 opadkey。
- 将填充后的密钥与被称为 opad 的比特序列进行 XOR 运算。opad 是将
- 与散列值组合:将 (