3.2 消息认证
网络通信面临着诸多安全问题,例如,消息可能是由攻击者伪造身份发送的,消息在网络传输过程中可能遭受篡改,消息也可能是过时消息的重放或排序被打乱后的消息。消息认证,也称为“报文认证”“消息鉴别”,指的是通信双方对各自接收的消息进行验证,确定消息的一些属性是否真实的过程,经常被验证的消息属性包括发送方的身份、接收方的身份、内容的完整性以及消息的顺序等。以下介绍消息属性的主流认证方法。
3.2.1 报文源的认证
报文源的认证是指认证发送方的身份,确定消息是否由所声称的发送方发送而来。
首先,可以采用公开密钥密码系统来实现对报文源的认证,如图3-1 (a)所示,发送方A用其私钥SKA对消息加密,接收方用发送方的公钥PKA进行解密。如果解密成功,则说明消息是A发送的,因为只有A拥有PKA对应的私钥SKA。这一过程也称为数字签名(将在3.3节介绍)。
图3-1 报文源认证
上述方法中,如何判断解密成功是一个问题,这也是所有数据解密工作中必须面对的问题。如果传输的是可读的文本信息,那么接收方可以根据恢复出的文本信息是否有意义来判断解密是否成功。但是对于二进制数据,由于没有直观的可读内容,接收方很难判断解密是否成功。如果二进制数据是一种有结构的数据(比如,协议报文的字段信息,每个字段的特征信息等,或话音数据、视频数据),则可根据结构特征或是否听得懂(语音)或看得懂(视频)来判断消息的正确性。如果是纯随机的无结构二进制数据,则无法判断解密是否成功。我们将在本章的3.2.3节介绍这个问题的解决方案。
报文源认证也能够采用对称密钥密码系统实现。举例来看,A是消息的发送方,B是消息的接收方,甲乙双方共享密钥K。在发送消息M之前,A用密钥K通过对称密钥加密算法E加密消息M,得到密文C=E(K,M),之后将密文C发送给B。B在接收消息以后,利用密钥K通过相应的对称密钥解密算法D解密,M=D(K,C),恢复消息M。在加解密的过程中,密钥K由A、B双方共享,对其他人保密。现在的问题是:B作为接收方,如果接收到能够利用密钥K解密的密文,是否可以确定密文一定由A产生的?如果答案是肯定的,那么B可以采用这种方法确定消息的发送方。
对于上面提出的问题,答案是B方无法判定A是消息的发送方。举例来看,B用密钥K加密消息发送给A,消息被攻击者截获。由于消息经过了加密,攻击者无法获取消息内容,也不能对消息进行有效篡改。但是攻击者可以将消息保存,并在随后的时间发送给B。在这种情况下,B接收到的密文可以通过密钥K恢复,但并不是由A所产生,而是B自己在之前的时间发送的。
可以对前面提到的采用对称密钥密码系统加密的方法进行简单扩展达到报文源认证的目的。一种最简单的扩展方法是通过标识号标识用户身份,在发送消息时增加发送方的标识号。例如,以标识号IDA作为A的身份标识。如图3-1(b)所示,A在发送消息时,将标识号IDA与消息M拼接,利用密钥K加密后发送给B,即发送的加密消息为E(K,M||IDA)。B在接收密文后使用密钥K解密,依据消息中的标识号IDA确定发送方的身份。
上述两种方法均不能应对重放攻击。如果不考虑信息重放攻击,用公开密钥密码系统实现的报文源认证可以保证信息的不可否认性,因为包括B在内的其他人不知道A的私钥,伪造不出报文E(SKA,M)。但是,用对称密钥密码系统实现的报文源认证则不能保证信息的不可否认性,因为通信双方都拥有共同的密钥K,接收方B完全可以自己伪造一个报文E(K,M||IDA),声称是A发送的,而事实上A并没有发送这个报文。
由于采用加密方式对传输的报文进行了加密,因此,上述两种方法在实现报文源认证的同时,还可保证报文传输的机密性。
3.2.2 报文宿的认证
报文宿的认证是对报文接收方的身份进行认证,具体来看,它指的是消息的接收方在接收到报文以后判断报文是否是发送给自己的。
报文宿的认证在很多场合具有重要意义。例如,在战斗时我军的指挥员将一则要求撤退的命令发送给A,并且为了确保接收方能够认证自己的身份,指挥员对命令进行了数字签名。攻击者截获该命令后,将该命令以指挥员的名义发送给B。由于命令有指挥员的数字签名,B通过数字签名确定命令由指挥员产生,同时,B认为命令是由指挥员发送给自己的。在这种情况下,B错误地执行了撤退命令,这个行动错误可能给我军带来很大损失。
报文宿的认证可以采用多种方法。公开密钥密码系统也可用于进行报文宿的认证,如图3-2(a)所示。认证的核心思想是发送方A在发送消息M时,使用接收方B的公钥PKB加密消息,密文C=E(PKB,M)。只有接收方使用自己的私钥SKB才能解密消息,D(SKB,E(PKB,M))=M,其他人由于没有相应密钥将无法解密。
图3-2 报文宿认证
同样,也可以用对称密钥密码系统为基础,采用与报文源认证相类似的方法认证报文宿,如图3-2(b)所示。具体来看,通信双方共享一个密钥K,发送方在发送消息时,在消息中增加能够标识接收方身份的标识号IDB,并将标识号与消息内容一起加密成E(K,M||IDB)发送。接收方在接收到消息以后通过解密提取标识号,判断自己是否是报文的接收方。
3.2.3 报文内容的认证
报文内容的认证是指接收方在接收到报文以后对报文进行检查,确保自己接收的报文与发送方发送的报文相同,即报文在传输过程中的完整性没有受到破坏,也称为“完整性检测”。
1.加密的方法
加密是确保报文内容完整性的有效方法。以A表示消息的发送方,B表示消息的接收方,通信双方如果采用对称密钥密码系统,A在发送消息前使用密钥加密消息,B接收到消息后,使用相同的密钥解密消息。在此过程中,由于密钥为A、B共享,其他人没有掌握密钥也就无法对消息内容进行修改了。
这种方法必须解决一个问题,如何判断解密出来的消息是发送方发送的原始消息,而没有被修改过,也就是前面提到的如何判断解密是否成功的问题。
针对这一问题,可以利用前面介绍的哈希函数验证消息的完整性。如图3-3(a)所示,以M表示消息,通过哈希函数H产生消息的哈希值h=H(M),利用A、B双方共享的密钥K,A使用加密函数E,将消息与哈希值拼接后加密的密文E(K,M||h)发送给B。B通过解密提取消息M,利用哈希函数获得消息的哈希值h',如果该值与B发送的哈希值h相同,则可以推断消息没有被篡改。这种方式可以保障消息传输的机密性和完整性。如上一小节所解释的那样,这种方案同样不能保证不可否认性。
图3-3 用加密的方法实现报文内容认证
哈希函数属于典型的消息校验手段。除了使用哈希函数,还可以利用其他能够产生校验信息的函数,比如通信中经常用来检测消息是在传输过程中发生了误码的循环冗余校验(Cyclic Redundancy Check,CRC)函数。这些函数的使用方法与哈希函数类似,发送方和接收方独立使用函数进行计算,并比较计算结果,根据结果是否相同判断消息的完整性。与哈希函数相比,校验和函数检测消息是否被修改的能力要弱一些。此外,为了防范攻击者同时修改消息以及消息的校验信息,发送方通常会加密消息的校验信息再进行传输。
通信双方采用公开密钥密码系统认证报文内容的方法与采用对称密钥密码系统类似。消息发送方(A)利用接收方(B)的公钥PKB加密消息以及消息的校验信息,接收方(B)通过自己的私钥SKB解密后进行认证,计算消息的哈希值h',并与消息后面的哈希值h进行比较。如果相同,则说明消息没有被篡改,如图3-3(b)所示。同样,这种方式可以保证消息传输的机密性和完整性。
消息发送方(A)还可以利用自己的私钥SKA加密消息以及消息的校验信息,接收方(B)通过发送方的公钥PKA解密后进行认证,计算消息的哈希值h',并与消息后面的哈希值h进行比较。如果相同,则说明消息没有被篡改,如图3-3(c)所示。这种方式下,可以保证消息传输的不可否认性和完整性,但不能保证消息的机密性,因为发送方的公钥PKA是公开的,任何了解其公钥的人均可解密消息。这种方式实现了对消息的数字签名和完整性保护。
上述三种方式除了实现消息的完整性保护,还实现了其他安全功能,如不可否认性、机密性。如果只需要实现完整性保护,则发送方只需加密哈希值(h)即可,并将加密后的哈希值(C)拼接在明文M之后一起发送给接收方,接收方解密C,计算消息M的散列值,并将它们进行比较就可验证消息的完整性。如图3-4(a)和图3-4(c)所示,攻击者由于缺少能够对完整性保护信息C进行修改的密钥,所以难以破坏消息的完整性。但在图3-4(b)中,由于接收者的公钥PKB是公开的且消息M没有加密,因此攻击者完全可以在截获消息后,对消息进行修改,重新计算修改后的消息的散列值,并用PKB加密后发送给接收者。接收者是无法发现消息被修改过的,因此完整性无法保证。还有一个问题,图3-4(c)是否可以如图3-3(c)一样,可以实现不可否认性呢?答案是肯定的,因为除了A,其他人因为不知道SKA,所以无法伪造出被加密保护的消息M的散列值,这也是下面将要介绍的最常见的不保证机密性的数字签名方法。
与图3-3所示的方法相比,图3-4的方法虽然不能保证机密性,但由于只对散列值加密,速度要快多了。
图3-4 用加密散列值的方法实现报文内容认证
2.消息认证码的方法
消息认证码(Message Authentication Code,MAC),也称为密码校验和(Cryptographic Checksum),是一种不依赖于加密技术实现报文内容完整性验证的方法。所有需要进行完整性验证的消息,将会以消息本身为基础,相应生成称为“消息认证码”的固定大小的数据块。这种消息认证码是对消息完整性进行验证的关键。
采用消息认证码的方法,通信双方需要共享一个密钥,以K来表示。同时,需要用于生成消息认证码的函数F。对于消息M,其消息认证码MACM与M和K相关,可以表示为:
MACM=F(M,K)
发送方将消息认证码MACM与消息M一起发给接收方。图3-5是利用消息认证码进行认证的过程。消息M在网络上传输,由于可能被篡改,因此在图中以M′表示接收方接收到的消息。
图3-5 利用消息认证码进行认证
接收方在接收到消息M′以后,利用与发送方共享的密钥K,为消息生成消息认证码MACM'=F(M′,K)。如果MACM′=MACM,则可以推断收到的消息M′与发送方所发出的消息M相同。其原因在于MACM的计算涉及到收发双方共享的密钥K,其他人不掌握该密钥,无法对MACM进行有效篡改。如果消息M在传输过程中遭到篡改,那么接收方结合M′和K计算得到的消息认证码MACM′将不同于发送方发送来的MACM。
有很多方法可以生成MAC,NIST标准FIPS PUB 113推荐使用DES。用DES生成密文,将密文的最后若干个比特用作MAC。典型的有16或32比特的MAC。
如果函数F采用前面介绍的散列函数,如MD5或SHA-1,则将这种消息认证码称为“散列消息认证码(Hashed Message Authentication Codes,HMAC)”。散列消息认证码是将消息M和密钥K拼接后作为散列函数H的输入进行散列运算后所产生的结果。
HMACM=H(M|| K)
因为秘密值本身并不会发送,所以攻击者不可能修改所截获的消息。只要不泄露秘密值K,攻击者就不可能伪造消息。
RFC 2104中定义的HMAC算法,如下所述:
HMACk(M)=H[(k+⊕opad)||H(k+⊕ipad)||M]
其中,
H:散列函数(MD5或SHA-1)。
M:HMAC的消息输入。
k+:密钥,长度不规则时左侧用0补齐,使其长度等于散列码块长(b,对MD5或SHA-1而言,其块长等于512比特)。
ipad:比特串00110110重复b/8次。
opad:比特串01011100重复b/8次。
简单来说,上述HMAC的主要过程如下:
(1)在k的左端追加0构成b比特的字符串k+(如k的长度为160比特,b=512,k将被追加44个0字节0x00)。
(2)ipad与k+进行按比特异或生成b比特的分组Si。
(3)将M追加在Si上。
(4)将H应用步骤(3)所产生的数据流。
(5)opad与k+进行异或生成b比特的分组So。
(6)将步骤(4)产生的散列结果追加在So上。
(7)将H应用步骤(6)产生的数据流,输出结果。
上述HMAC方法被广泛应用于IPsec、SSL/TLS、SET等安全协议中,我们将在后续章节进行介绍。
消息认证码除了能够认证报文内容的完整性,也能够用于报文源认证和报文顺序认证。消息认证码的生成涉及了一个保密的密钥,只要在发送消息时增加发送方的标识号,将发送方的身份标识号ID与消息M拼接,并在生成消息认证码时包含此信息:MACM=F(M|| ID,K),则消息认证码也能够准确判断发送方的身份。如果在生成消息认证码时包含能够表示报文先后顺序的信息(如时间戳、序列号等),而攻击者不能正确地修改认证码中所包含的顺序信息,则接收者就可以确认消息的正确序列,以避免重放攻击。
消息认证码方法与加密方法之间存在一些明显区别。首先,虽然两者都要求通信双方共享密钥,但是消息认证码使用的密钥与密码系统中使用的密钥不同,其使用并不是为了控制加解密过程,而是利用这个共享密钥使得他人难以有效篡改消息认证码。其次,用于产生消息认证码的函数不需要具有可逆性,即生成消息认证码以后,不要求通过消息认证码恢复原始消息。而加密过程要求具有可逆性,对于加密得到的密文必须可以通过解密恢复成明文。因此,消息认证码的函数在设计上相对简单。
在图3-5中,消息认证码的使用并不能保证消息的保密性。如果攻击者在网络上监听,则能够获取传输的消息内容。如果要求确保消息的保密性,还需要对消息进行加密。
3.2.4 报文顺序的认证
报文的发送顺序在通信中具有重要的安全意义。重放攻击就是攻击者利用通信双方没有有效认证消息的发送顺序,将截获的消息在以后的时间重新发送,扰乱正常通信的一种攻击方式。举例来看,在战斗时我军的指挥员发送消息给甲,要求甲执行进攻任务。该消息被攻击者截获并保存,几天以后攻击者将消息再次发送给甲,甲如果没有对消息的发送顺序进行认证,则可能执行错误的命令。
对报文顺序进行认证,最重要的一点就是在通信中增加标识报文顺序的信息。报文顺序信息可以多种形式出现。
首先的一种形式是序列号。发送方为每条消息增加序列号,接收方根据序列号判断消息的发送顺序,并依据序列号及时发现消息的重复和乱序。重放攻击这种利用过时消息进行攻击的方法将无法成功。采用序列号的形式对报文顺序进行认证,很重要的一个条件是通信双方能准确记录通信的序列号信息,以确保通信按序进行。
第二种报文顺序信息的表现形式是时间戳。在发送的消息中增加时间戳,接收方接收消息时,可以根据时间戳判断消息是否按序到达。时间戳这种形式要求通信双方保持时间同步,以便能够以时间信息为依据判断消息的顺序。
采用挑战及响应(challenge/response)的认证方式可以根据通信需要进行认证,防范消息乱序导致的问题。采用这种方式,通信双方通常需要共享一个密钥,并在认证的过程中使用对称密钥密码算法进行加密。实施认证的一方产生不可预测的随机信息,这种随机信息被称为挑战(challenge)。随机信息发送到被认证方,被认证方在随机信息的基础上进行计算,并将计算结果作为响应返回。根据响应是否正确,实施认证的一方可以判断通信源的身份并防止重放攻击。
举例来看,如果甲向乙发送消息,其通信顺序如下:
(1)甲向乙发送消息,请求乙对自己进行认证。
(2)乙在接收到消息以后,随机产生一个字符串、整数或者其他类型的数据返回给甲,以t表示该随机信息。
(3)甲利用与乙共享的密钥k使用加密算法E加密t,得到t1=E(k,t),并将t1发送给乙。
(4)乙在收到t1后,利用密钥k通过解密算法D解密t1,得到t2=D(k,t1),如果t2=t,则可以判断消息的发送者是甲。
以上过程可以看作甲向乙发送消息之前进行的握手。在此基础上,甲可以t1为基础产生标识顺序信息的参数并加入到消息中,开始消息的发送。挑战及响应的认证方式由于必须先完成认证再进行通信。因此,攻击者很难实施重放攻击。
比较三种顺序认证方式,采用序列号的方法需要维护具有全局性的序列号,每一方都要记住其他各方与其通信时的最后一个序列号,管理起来比较复杂。采用时间戳的方法要求保证通信主机间的时间同步。挑战及响应的认证方式在每次通信前握手,通过握手使双方确定通信状态,不必从始至终维护序列号、时间之类的状态信息,相对而言灵活性较强。
总体来看,报文顺序认证最重要的前提是确保攻击者无法修改消息的顺序信息,即顺序信息的完整性不受破坏。在实际应用中,常常将报文顺序的认证和报文内容的认证结合实现。最典型的一种方法是将顺序标识附加在消息上,同时利用报文内容的认证方法确保消息整体的完整性。
在上述顺序认证方案中,都有一个随时间变化的参数,一般将这个参数称为“现时(Nonce)”。Nonce是Number used once或Number once的缩写,是一个随时间而改变的参数,在密码学中通常是一个只被使用一次的任意或非重复的随机数值。在计算机系统中,大部分程序设计语言中产生的随机数是由可确定的函数(比如线性同余),通过一个种子(如时钟)来产生随机数的。这意味着:如果知道了种子,或者已经产生的随机数,都可能获得接下来随机数序列的信息(可预测性)。因此,用这种方法产生的随机数通常称为“伪随机数(pseudorandom number)”。真随机数一般是用某些随机物理过程来产生的,如放射性衰变、电子设备的热噪音、宇宙射线的触发时间等。也可以通过软硬结合的方法来实现,通过不断收集非确定性的设备事件,如机器运行环境中产生的硬件噪音(如键盘敲击速度、鼠标移动速度、电磁波、磁盘写入速度等)作为种子来产生随机数。IETF在RFC 4086中列出了一些可能的随机源,如声音/图像输入、磁盘驱动时产生的随机波动等,用于计算机来产生真随机数。在实际应用中,只有安全要求非常高的应用场景中,才使用真随机数发生器。
Nonce在很多加密方法的初始向量和加密散列函数中发挥着重要作用(后续章节将会介绍),在各类认证协议中被用来确保认证信息不被重复使用以对抗重放攻击。此外,Nonce也用于流密码加密过程中,如果需要使用相同的密钥加密一个以上的消息,就需要Nonce来确保不同的消息与该密钥加密的密钥流不同。