消息认证码
消息认证码是密码学家工具箱中6个重要的工具之一。回忆一下,这6个重要的工具分别是:对称密码、公钥密码、单向散列函数、消息认证码、数字签名和伪随机数生成器。
消息认证码(Message Authentication Code)是一种确认完整性并进行认证的计算,取三个单词的首字母,简称MAC
消息认证码的输入包括任意长度的消息和一个发送者与接收者之间的共享的密钥,它可以输出固定长度的数据,这个数据成为MAC值。
根据任意长度的雄性输出固定长度的数据,这一点和散列函数很类似。但是单向散列函数中计算散列值时不需要密钥,相对地,消息认证码中则需要使用发送者与接收者之间的共享密钥。
要计算MAC必须持有共享密钥,没有共享密钥的人就无法计算MAC值,消息认证正是利用这一性质来完成认证的。此外,和单向散列函数的散列值一样,哪怕消息中发生1比特的变化,MAC值一会产生变化,消息认证码正是利用这一性质来确认完整性的。
消息认证码是一种与密钥相关联的单向散列函数
消息认证码的使用步骤
发送者与接收者之间事先共享密钥
消息认证码的密钥配送问题
这个问题,在前面的内容中,提到过,这里不再赘述。
消息认证码的应用实例
SWIFT
SWIFT的全称是Society for Worldwide Interbank Financial Telecommunication(环境银行金融电信协会),是于1973年成立的一个组织,其目的是为国际银行之间的交易保驾护航。该组织成立时有15个成员国,2008年时,已经发展到了208个成员国。
银行与银行之间是通过SWIFT来传递交易信息的。而为了确认消息的完整性以及对消息进行验证,SWIFT中使用了消息认证码。
在使用公钥密码进行密钥交换之前,消息认证码所使用的共享密钥都是由人来进行配送的。
IPsec
IPsec 是对互联网基本通信协议——IP协议(Internet Protocol)增加安全性的一种方式。IPsec中,对通信内容的认证和完整性校验都是采用的消息认证吗来完成的。
SSL/TLS
SSL/TLS是我们在网上购物等场景中所使用的通信协议。 SSL/TLS中对通信内容的认证和完整性校验也使用了消息认证吗。
消息认证码的实现方式
使用单向散列函数实现
使用SHA-2之类的单向散列函数可以实现消息认证码,其中一种实现方法称为HMAC。
使用分组密码实现
使用AES之类的分组密码可以实现消息认证码。
将分组密码的密钥作为消息认证码的共享密钥来使用,并用CBC模式将消息全部加密。此时,初始化向量是固定的。由于消息认证码不需要解密,因此将除最后一个分组以外的密文部分全部丢弃,而将最后一个分组用作MAC值。由于CBC模式的最后一个分组会受到整个消息以及密钥的双重影响,因此可以将它用作消息认证码。例如AES-CMAC(RFC4493)就是一种基于AES来实现的消息认证码。
其他实现方法
使用流密码和公钥密码等也可以实现消息认证码。
认证加密
2000年以后,关于认证加密(缩写为AE或AEAD)的研究逐步展开。认证加密是一种将对称密码与消息认证相结合,同事满足机密性、完整性和认证三大功能的机制。
有一种认证加密方式叫作Encrypt-then-MAC,这种方式是先用对称密码将明文加密,然后计算密文的MAC值。在Encrypt-then-MAC方式中,消息认证码的输入是消息的密文,通过MAC值就可以判断“这段密文的确是由制定明文和密钥的人生成多的”。使用这一机制,我们可以防止攻击者通过发送任意伪造的密文,并让服务器解密来套取信息的攻击。
还有其他加密认证方式,如Encrypt-and-MAC(将明文用对称密码加密,并对明文计算MAC值)和MAC-then-Encrypt(先计算明文的MAC值,然后将明文和MAC值同时用对称密码加密)。
GCM与GMAC
GCM(Galois/Counter Mode)是一种加密认证方式。GCM中使用AES等128比特分组密码的CTR模式,并使用一个反复进行加法和乘法运算的散列函数来计算MAC值。由于CTR模式的本质是对递增的计数器值进行加密,因此可通过对若干分组进行并行处理提高运算速度。此外,由于CTR模式加密与MAC值计算使用的是相同的密钥,因此在密钥管理方面也更加容易。专门用于消息认证码的GCM称为GMAC。
HMAC的详细介绍
HMAC是一种使用简单单向散列函数来构造消息认证码的方法,其中HMAC的H就是Hash的意思。
HMAC中所使用的单向散列函数并不仅限于一种,任何高强度的单向散列函数都可以被用于HMAC,如果将来设计出新的单向散列函数,也同样可以使用。
使用SHA-1、SHA-224、SHA-256、SHA-384、SHA-512所构造的MAC,分别称为HMAC-SHA1、HMAC-SHA-224、HMAC-SHA-256、HMAC-SHA-384、HMAC-SHA-512。
HMAC的步骤
- 密钥填充
如果密钥比单向散列函数的分组长度要短,就需要在末尾填充0,知道其长度达到单向散列函数的分组长度为止。
如果密钥分组长度要长,则要用单向散列函数求出密钥的散列值,然后将这个散列值用作HMAC的密钥。 - 填充后的密钥与ipad的XOR
将填充后的密钥与被称为ipad的比特序列进行XOR运算。ipad是将00110110这一比特序列不断循环反复直到达到分组所形成的比特序列,其中ipad的i是inner的意思。 - 与消息结合
随后,将ipadkey与消息进行组合,也就是将和密钥相关的比特序列(ipadkey)附加在消息的开头。 - 计算散列值
将(3)的结果输入单向散列函数,并计算出散列值。 - 填充后的密钥与opad的XOR
将填充后的免邮与被称为opad的比特序列进行XOR运算。opad是将01011100这一比特序列不断循环反复直到达到分组长度所形成的比特序列,其中opad的o是 outer的意思。
XOR运算所得到的结果也是一个和单向散列函数的分组长度相同,且和密钥相关的比特序列。这里我们将这个比特序列称为opadkey。 - 与散列值组合
将(4)的散列值拼在opadkey后面。 - 计算散列值
将(6)的结果输入单向散列函数,并计算出散列值。这个散列值就是最终的MAC值。
通过上述流程,最后得到MAC值,一定是一个和输入的消息长度以及密钥都相关的长度固定的比特序列。
对消息认证码的攻击
重放攻击
攻击者将事先保存正确的MAC值,不断重放发动攻击,即将MAC值保存下来重复利用,这种方式成为重放攻击。
防御方法:
- 序号
约定每次都对发送的消息赋予一个递增的编号(序号),并且在计算MAC值时将这个序号也包含在消息中,这样一来,由于攻击者无法计算序号递增之后MAC值,因此就可以抵御重放攻击。这种方法虽然有效,但是对每个通信对象都需要积累最后一个消息的序号。 - 时间戳
约定在发送消息时包含当前的时间,如果收到以前的消息,即便MAC正确也将其当做错误的消息来处理,这样就能欧防御重放攻击。这种方法虽然有效,但是发送者和接收者的时钟必须一致,而且考虑到通信的延迟,必须在时间判断上流下缓冲,于是多多少少还是会存在重放攻击的的空间的。 - nonce
在通信之前,接收者先向发送者发送一个一次性的随机数,这个随机数一般称为nonce。发送者咋消息中包含这个nonce并计算MAC值。由于每次通信时nonce的值都会发生变化,因此无法进行重放攻击。这种方法虽然有效,但通信的数据量会有所增加。
密钥推测攻击
和单向散列函数的攻击一样,对消息认证码也可以进行暴力破解以及生日攻击。
对消息认证码来说,应保证不能根据MAC值推测出通信双方所使用的密钥。如果主动攻击者能够从MAC值算出密钥,就可以进行篡改、伪装等攻击。例如HMAC中就是利用单向散列函数的单向性和抗碰撞性来保证无法根据MAC值推测出密钥的。
此外,在生成消息认证码所使用的密钥时,必须使用密码学安全的、高强度的伪随机数生成器。如果密钥是认为选定,则会增加密钥别推测的风险。
消息认证码无法解决的问题
对第三方证明
假设Bob在接收了来自Alice的消息之后,想要向第三方验证者Victor证明这条消息的确是Alice发送的,但用消息认证码无法进行这样的证明。
首先,Victor要校验MAC值,就需要制定Alice和Bob之间共享密钥。
假设Bob相信Victor,同意将密钥告诉Victor,即便如此,Victor也无法判断这条消息是由Alice发送的,因为Victor可以认为:“即使MAC值是真确的,发送这条消息的人也不一定是Alice,还有可能是Bob”。
能够计算出正确的MAC值的人只有Alice和Bob,在他们两个人之间进行通信,可以判定是对方计算了MAC值,这是因为共享这个密钥的双方之中,有一方就是自己。然后,对于第三方Victor,Alice或Bob却无法证明是对方计算了MAC值,而不是自己。
防止否认
假设Bob收到了包含MAC值的消息,这个MAC值是用Alice和Bob共享的密钥计算出来的,因此Bob能够判定这条消息的确来自Alice。
但是,上面我们讲过,Bob无法向验证者Victor证明这一点,也就是说,发送者Alice可以向Victor生成:“我没有向Bob发送过这条消息”。这样的行为就称为否认。
Alice可以说“这条消息是Bob自己编的吧”,“说不定Bob的密钥被主动攻击者给盗取了,我的密钥可是妥善保管者呢”等。
即便Bob拿MAC值来举证,Victor也无法判断Alice和Bob谁的主张才是正确的,也就是说,用消息认证码无法防止否认。
该系列的主要内容来自《图解密码技术第三版》
我只是知识的搬运工
文章中的插图来源于原著