学习笔记3

第五章 散列函数

散列函数是一类将任意长度的输入位(或字节)串转换为固定长度的输出的函数。散列函数的一个典型应用是数字签名。给定一个消息m,当然可以对这个消息本身进行签名。然而,大多数数字签名方案所采用的公钥运算的运算代价很大,直接对消息本身签名非常不经济。因此不会直接对m进行签名,而是应用散列函数h,对h(m)进行签名。相对于成千上万位长度的消息而言,散列函数的输出一般在128位到1024位之间。对h(m)的签名比对消息m直接签名要快得多。为保证采取这种方法构造的签名是安全的,必须要求散列函数h满足以下条件:很难构造出两个消息m_1和m_2,使得h(m_1 )=h(m_2)。
散列函数有时又称为消息摘要函数,其散列结果也称作摘要或者指纹。
本章讨论的散列函数和数据结构中的映射函数并非同一个概念。

5.1 散列函数的安全性

散列函数需要满足的最基本的要求就是单向性,即对给定的消息m,计算h(m)很容易;而对于给定的x,不可能求出满足x=h(m)的m。简单来说,单向性就是计算容易但求逆困难。
在散列函数的所有性质中,最常提到的是它的抗碰撞性。一对碰撞是指两个不同的输入m_1和m_2使得 h(m_1 )=h(m_2)。任意一个散列函数都会有无穷多个这样的碰撞(因为有无限个可能输入值,有限个可能输出值)。因此,散列函数不可能是无碰撞的。抗碰撞性是要求虽然碰撞存在,但很难被找到。
理想散列函数的定义:理想的散列函数是从所有可能的输入值得到所可能的有限输出值集合的一个随机映射。
对于散列函数的攻击:对散列函数的攻击是一个区分散列函数与理想散列函数的非通用(non-generic)的方法。

5.2 实际的散列函数

目前好的散列函数主要从SHA系列中进行选择:SHA-1、SHA-224、SHA-256和SHA-512,还有一些其他的已经公布的方案。
散列函数的迭代设计:

  • 首先将输入分成固定长度的分组序列m_1,m_2,⋯,m_k,最后一个分组要进行填充以使其达到固定的长度,分组的长度一般为512位,最后一个分组通常包含一个表示输入长度的位串。
  • 然后使用一个压缩函数和固定大小的中间状态对这些消息分组按顺序进行处理,这个过程由固定的值H_0开始,随后计算H_i=h^' (H_(i-1),m_i)。
  • 最后一个H_k即为散列函数的输出。
    散列函数的这种迭代设计有应用上的优势。首先,与直接处理可变长度的输人相比,这样的迭代运算易于规定和实现;其次,这种结构使得我们可以在得到消息的第一部分时就开始计算,在实际应用中对一个数据流计算散列值时,可以实时地进行散列,而无须存储这些数据。

5.2.2 MD5

MD5是由Ron Riverst设计的一个128位散列函数,MD5存在一定缺陷,但是仍然应用于实际系统中。
计算MD5的第一步是将消息分为512位序列分组,对最后一个分组进行填充。MD5有128位的状态变量,它们被分为4个32位的字。压缩函数h'共有4轮,在每一轮中,消息分组与状态变量进行混合,这种混合运算由32位的字上的加法、异或、与、或、轮转运算组合而成。每一轮将整个消息分组都混合在状态变量中,因此每个消息字都使用了4次。在4轮的压缩h'完成之后,将结果与输入状态相加得到输出。
对于大多数应用来说,MD5的128位散列长度是不够的。由生日悖论可知,对128位散列函数大约进行264次计算就可以找到一个碰撞。这也就是说通过264个MD5的计算就可以发现碰撞,这对现在的密码系统来说是不够的。
这些年来MD5算法的选代压缩函数h^'已经被证明可以产生碰撞,对MD5的安全造成了一定威胁。

5.2.3 SHA-1

SHA-1是160位的散列函数,与MD5有很多相似点,SHA-1算法同样是不安全的。
SHA-1算法的每一个160位的状态是由5个32位的字组成。与MD5算法类似,SHA-1算法总共也有4轮,每一轮都由定义在32位字长上的基本运算混合而成。所不同的是, MD5对每个消息分组进行4次处理,而SHA-1用线性递归的方法将16个字长的消息分组扩展为它所需要的80个字长。这是对MD4技术的一种推广。在MD5中,消息的每一位在混合函数中都被使用4次,而SHA-1的线性递归保证了消息的每一位都至少影响混合函数12次。有趣的是,从SHA-0到SHA-1的唯一改变是对线性递归增加了1位的轮转。
SHA-1的主要问题不是内部缺陷,而是输出为160位的长度。进行280步运算就可以使160位的散列函数产生碰撞,这个安全等级低于我们对于分组密码密钥长度为128~256位的要求,当然也不符合对于分组密码128位的设计安全等级。虽然进行SHA-1运算要比MD5花费更多的时间,但是已经可以证明采用少于280步的运算就可以使SHA-1产生碰撞。

5.2.4 SHA-224、SHA-256、SHA-384和SHA-512

这些散列函数都属于SHA-2系列,分别有224位、256位、384位、512位的输出,设计用于与密钥长度为128位、192位、256位的AES算法以及112位的3DES算法一起使用。这些算法的结构和SHA-1非常类似。
SHA-2比SHA-1安全性更强,但计算速度要慢很多。

5.3 散列函数的缺陷

5.3.1 长度扩充

存在长度扩充问题是因为在散列函数计算的最后一步缺少一个特殊的处理,结果导致h(m)恰好是计算h(m^')时完成前k个块计算的中间状态。
这个性质对于那些我们期望作为随机映射的散列函数来说是非常不理想的,因为这个性质使得前面提到的散列函数都不能满足我们给出的安全性的定义。区分器只需构造一些合适的消息对(m,m^'),然后验证这样的关系是否成立。对于理想的散列函数,这样的关系一定不成立。这是一个利用了散列函数本身性质的非通用攻击,所以是一个有效的攻击。这样的攻击需要很少次数的计算,因此速度非常快。
长度扩充存在的缺陷在SHA-3算法中得到解决,NIST对于SHA-3的要求之一就是不存在长度扩充问题。

5.3.2 部分消息碰撞

这个问题是采用迭代结构的散列函数固有的缺陷。
用下面这个场景进行解释:
假设有一个系统使用h(X∥m)作为对消息m的认证,其中X为认证密钥。攻击者可以选择消息m,但系统只能认证一个消息。
对于输出大小为n的理想的散列函数,我们希望它具有n位的安全性。攻击者选择消息m并使系统对其用h(X∥m)进行认证,除了对X进行穷举搜索外,没有更好的攻击方法。
对于选代散列函数,攻击者可以采用更加有效的方法。当使用h进行散列处理时可以通过生日攻击用大约2n/2步找到两个发生碰撞的消息m和m',并使系统对消息m进行认证,然后用消息m'代替。由于散列函数的选代计算结构,只要出现了碰撞而且余下的输入一样,那么散列值就一定相同,而消息m和m'有相同的散列值,因此对任意的X,有h(X∥m)=h(X∥m')。注意该攻击与X无关,同一对m和m^'对任何X都适用。

5.4 修复缺陷

5.4.1 一个临时的修复方法

设h是前面提到的某个散列函数,我们用m↦h(h(m)∥m)代替m↦h(m)作为散列函数。我们将h(m)放在要进行散列运算的消息的前面,这可以保证散列函数的迭代运算与消息的每一位都有关,从而避免长度扩充和部分消息碰撞的攻击。
设h是一个迭代的散列函数,散列函数h_DBL (m):=h(h(m)∥m)
如果h是SHA-2系列散列函数中任一散列函数,这样构造的h_DBL具有n位的安全性。
这个方案的缺点是比较慢,原因是必须对消息进行两次散列运算,使得时间为原来的2倍。另一个缺点是该方法需要缓冲整个消息序列m的值后才能进行运算,无法随着数据流的产生直接进行计算。在一些实际的应用中,就是需要随着数据流的产生过程中不断进行散列运算,所以在这种应用中不能使用h_DBL。

5.4.2 一个更有效的修复方法

设h是迭代散列函数,b是压缩函数的分组长度,散列函数h定义为h≔h(h(0^b∥m)),其声称安全等级为min⁡(k,n/2),其中k和n是散列函数h的安全等级和输出的大小。
通常结合SHA系列的散列函数来应用这种构造。

5.5 散列算法的选择

目前,很多提交给NIST的SHA-3候选算法中都有一些新的算法设计,其中也考虑了本书中所提到的散列函数的弱点以及其他的相关缺陷。然而,NIST还没有最终确定SHA-3的标准算法。对SHA-3算法真正的放心使用还需要进行进一步分析。短期内,我们建议使用SHA系列的散列函数,包括SHA-224、SHA-256、SHA-384、SHA-512.此外,也可以使用SHA系列散列函数,或者使用SHA-512的截断输出函数,得到256位结果。从长远来看,建议使用最终将确定的SHA-3标准算法。

问题与思考:

  1. MD5的碰撞问题一直是关注的重点,目前MD5有很多快速碰撞方法,最常用的方法是彩虹表法,将128位的MD5值映射回原文空间——其结果几乎一定不是真正的原文,但只要能映射回到原文的解空间,且有一定的抗碰撞性,就可以达到目的。
  2. 在5.3.1长度扩充一节中指出,h(m)恰好是计算h(m^')时完成前k个块计算的中间状态,根据这一点可以在消息m后附加文本,然后计算出新的认证信息,这样即便不了解最初需要散列处理的信息,也可以求出最后的散列值。
  3. 在5.3.2一节中,将消息m与认证密钥X交换位置,就可以有效避免上面的问题,只能对X进行穷举搜索,但是碰撞问题依然存在。

第六章 消息认证码

消息认证码,或者MAC,用于检测对消息的篡改。加密使Eve不能够获取消息的内容,但不能防止Eve对消息进行操纵,这时就需要消息认证码。与加密消息一样,MAC也使用个密钥K, Alice和Bob知道这个密钥但Eve不知道。当 Alice向Bob发送消息m时,不仅仅发送消息m,而且还发送一个由MAC函数计算得到的MAC值。Bob检验接收到的消息的MAC值与收到的MAC值是否相等,如果不匹配则丢弃这个没能通过认证的信息。由于Eve不知道密钥K,所以不能为篡改后的消息找到正确的MAC值,从而保证Eve不能对消息进行操纵。

6.1 MAC的作用

MAC函数有两个输入,其中一个是固定长度的密钥K,另一个是任意长度的消息m,产生固定长度的MAC值。这里将MAC函数表示为MAC(K,m)。为了对一个消息进行认证, Alice把消息m与MAC值MAC(K,m)一起发送,这个MAC值也称为标签(tag)。假设Bob(同样有密钥K)收到消息m和标签T后,可以使用MAC验证算法来检验T=MAC(K,m)是否成立。

6.2 理想MAC与MAC的安全性

理想MAC的定义:理想的MAC函数是一个从所有可能的输入到n位输出的随机映射。
MAC安全性定义:对于MAC的攻击是区分MAC函数和理想MAC函数的非通用方法。

6.3 CBC-MAC和CMAC

CBC-MAC是一种将分组密码转换为MAC的经典方法,密钥K被用作分组密码的密钥。 CBC-MAC所采用的方法是对消息m用CBC模式进行加密,而只保留密文的最后一个分组,其余全部丢弃。对一个由分组P_1,⋯,P_k组成的消息,MAC计算过程为:
H_0≔IV
H_i≔E_k (P_i⨁H_(i-1) )
MAC≔H_k
有时也会取最后一个分组的一部分(例如一半)作为 CBC-MAC函数的输出。CBC MAC的常见定义要求IV固定为0。
一般情况下,在加密和认证中不能使用相同的密钥。在CBC加密和 CBC-MAC认证中使用相同的密钥尤其危险,因为MAC的值为最后一个密文分组。而且,根据使用CBC加密和 CBC-MAC的时间和方式,对二者使用相同的密钥可能会同时导致对CBC加密的隐私性和 CBC-MAC可认证性的破坏。
争对CBC-MAC的碰撞攻击:
设M是一个 CBC-MAC函数,如果已知M(a)=M(b),则对任意的c都有M(a∥c)=M(b∥c)。
这是由 CBC-MAC的结构所导致的。
攻击分为两个阶段。在第一个阶段,攻击者收集大量消息的MAC值,直到产生碰撞。
由生日悖论可知,对于128位的分组密码,需要进行264步计算。在这个阶段攻击者得到了两个消息a和b且满足(a)=M(b)。若攻击者从发送者那里得到对消息a∥c的认证码,他就可以用b∥c代替消息a∥c而无须改变MAC值,这个值完全可以通过接收者对MAC值的验证,从而使接收者接到一个伪造的消息。
这是一个非通用攻击,因为它对理想的MAC函数无效。对于理想的MAC函数,找到了碰撞并不是问题,即使得到了满足条件M(a)=M(b)的两个消息a和b时,也不能够为新消息伪造一个MAC值,而在 CBC-MAC模式中是可以的。
还有另外一种攻击手法,假设c为一个分组长度的消息,且满足M(a∥c)=M(b∥c),那么对于对任意分组d,有M(a∥d)=M(b∥d)。攻击过程类似于上述攻击。首先攻击者收集大量消息的MAC值,直到产生碰撞,得到产生碰撞的a和b。然后攻击者从发送者获取a∥d的认证码,就可以用b∥d代替消息a∥d而无须改变MAC值。
如果使用CBC-MAC算法,应该按照如下方法进行:

  • 从l∥m构造位串s,其中l是消息m在固定长度格式下的编码长度
  • 对s进行填充使得其长度为分组长度的整数倍
  • 对填充后的位串s应用 CBC-MAC
  • 输出最后一个密文分组或它的一部分,切记不要输出任何中间值
    CBC-MAC的优点是它使用与分组密码加密模式相同类型的计算。在很多系统中,加密和MAC是仅有的两个需要应用于大量数据的函数,所以速度对它们来说很重要,让它们拥有相同的基本函数有助于更有效地实现功能,尤其是在硬件实现中。
    尽管如此,我们也不推荐直接使用 CBC-MAC方法,因为这种方法很难恰当地使用。
    我们推荐CMAC作为备选方法,CMAC基于 CBC-MAC并且最近已由NST标准化。CMAC的工作原理和 CBC-MAC几乎相同,只是对最后一个分组的处理有所区别。确切地说,在进行最后一次分组密码加密之前,CMAC将两个特殊值中的一个与最后一个分组进行异或。这些特殊值从CMAC的密钥产生,被CMAC用到的那个值取决于消息的长度是否为分组块长度的倍数。在MAC运算中引入对这些值的异或可以防御在不同长度的消息中使用 CBC-MAC所面临的攻击。

6.4 HMAC

HMAC的设计思路是利用散列函数来构造MAC,所以在HMAC中计算h(K⨁a∥h(K⨁b)∥m),其中a和b为指定的常数,即首先对消息进行一次散列运算,输出结果再与密钥一起进行散列运算。
HMAC的设计使得它不会遇到和SHA-1一样的碰撞攻击,这是因为在HMAC中,对消息的头部进行散列运算时基于一个密钥,这个密钥对于攻击者来说是未知的。这也就是说,基于SHA-1的HMAC算法不会比SHA-1算法差。但是由于攻击手段的不断进步,基于SHA-1的HMAC也面临着越来越多的风险,这里不推荐使用。
HMAC的设计者对HMAC进行了精心的设计来抵御这些攻击,并且证明了相应构造的安全性界。HMAC避免了将密钥K泄露给攻击者的密钥恢复攻击,避免了攻击者无须与系统交互即可完成的攻击。然而,与CMAC一样,HMAC函数仍然只有n/2位的安全性,因为可以利用选代散列函数的内部碰撞来对函数进行通用的生日攻击。HMAC的构造使得攻击需要与系统进行2n/2次交互,这比在自己的计算机上完成2n/2次计算要困难得多。

6.5 GMAC

近期NIST公布了一种新的标准化MAC方法,称之为GMAC,这种方法无论在硬件实现还是软件实现方面都非常有效。GMAC是针对128位的分组密码设计的。
GMAC的工作原理完全不同于 CBC-MAC、CMAC以及HMAC。GMAC的认证函数有三个输入:密钥、待认证的消息、瞬时值,该瞬时值只使用一次。 CBC-MAC、CMAC和HMAC的算法中都没有使用瞬时值作为输入。如果使用密钥和瞬时值对消息进行MAC运算,接收者也需知道这个瞬时值,所以需要发送者通过某种方式将瞬时值发送给接收者,瞬时值也可以是隐含的,如发送者和接收者都维护的包计数器。
目前GMAC已经成为标准化,也是许多应用环境中的合理选择。GMAC与HMAC和CMAC不同,如果减少标签长度,GMAC的安全性就会降低。
最后,要求系统提供瞬时值是有风险的,因为要求系统产生唯一的瞬时值是一件困难的事。

6.6 如何选择MAC

从前面的讨论可以推断出我们主张选择 HMAC-SHA-256——一个以SHA-256作为散列函数的HMAC。我们希望使用256位的全部输出,而很多系统使用64位或96位的MAC值,即便这样,似乎总的开销也会很大。如果以传统的方式使用MAC,碰撞攻击就不会存在,因此基于目前的研究来看,将 HMAC-SHA-256的结果截短为128位应当是安全的。
目前的状况并不乐观,我们希望能够构造出更快的MAC函数。但是在合适的函数公布和经过分析并被广泛接受之前,我们所能做的并不多。GMAC的运行效率不错,但只能提供最多64位的安全性,并且不适用于生成短标签。而且GMAC算法还需要产生瞬时值,这会导致很多安全隐患。

6.7 MAC的使用

当Bob收到MAC(K,m)后,他就知道某个知道密钥K的人认可了消息m。这样的声明隐含了所有的安全性质,因此在使用MAC时需要格外小心。比如Eve可以记录 Alice发送给Bob的消息,在以后某个时间给Bob发送这个消息的一个副本。如果没有抵御这类攻击的措施,Bob将把这个消息的副本当作来自 Alice的有效消息而接收。在双向通信中,如果Alice和Bob使用相同的密钥,类似的问题也会出现。Eve可以将这个消息返回给 Alice,她可能会相信这是来自Bob的消息。
在许多情况下, Alice和Bob不仅想对消息m进行认证,而且要包括附加数据d。这个附加数据包括防止重放攻击的消息编号,还有消息源和目的地等,这些域通常是被认证的(通常是已加密的)消息头的一部分。MAC必须认证d和m,一般的方法是对d∥m应用MAC函数,而不是仅仅应用于m。
Horton原则:消息认证是认证消息的含义,而不是消息本身。
MAC仅仅对字节串进行认证,而Alice和Bob想对具有特定含义的消息进行认证,字节串(发送的字节)和字节串的含义(对消息的理解)这两者的差别是很重要的。
在Horton原则中,MAC认证的不仅是消息m,还包括Bob解析消息m以获取含义所需要的所有信息,这通常包括协议标识符、协议版本号以及协议消息标识符和各个数据域的长度等信息。一种方法是不仅将各个域连接起来,还使用诸如XML那样的数据结构,无须更多信息即可用来解析数据。

问题与思考:

  1. CMAC和HMAC都存在碰撞的缺陷,但是HMAC为了避免对于密钥K的攻击,要求攻击者必须与系统交互才能尝试攻击,与在本机上完成计算相比会困难很多。
  2. 注意体会Horton原则在MAC中的应用,对消息的认证和对消息理解的认证是两个截然不同的概念。
posted @ 2023-03-08 22:20  acacacac  阅读(269)  评论(0编辑  收藏  举报