第5章消息认证与数字签名 本章导读 消息认证是用来防止主动攻击的重要技术,用以保证消息的完整性。常见的消息认证密码技术包括消息认证码(MAC)和安全散列函数。另外,消息加密也可以提供一种形式的认证。 MAC是需要使用密钥的算法,其输入是可变长度的消息和密钥,其输出是一个定长的认证码。只有拥有密钥的消息,发送方和接收方才可以生成消息认证码和验证消息的完整性。 散列函数和MAC算法类似,也是一个单向函数,但是无需密钥,其输入是可变长度的消息,其输出是固定长度的散列值,也叫消息摘要。 数字签名是基于公钥密码技术的认证技术。它和手写签名类似,使得消息的发送方可以使用自己的私钥为初始消息生成一个有签名作用的签名码,接收方接收到初始消息和相应的签名码,可以使用消息发送方的公钥对该消息的签名码进行验证。数字签名可以保证消息的来源和消息本身的完整性。 使用数字签名,通常需要和散列函数配合使用。 5.1认证 加密通常用于保密,对某个信息的加密操作使得其内容对于未授权的人而言是保密的、安全的。但是,在某些情况下,完整性比保密性更重要。例如,在某个医院的医疗系统中检索到的病人的医疗记录,或者银行系统中检索到的某个人的信用记录,检索到的这些信息和所存储的正本是否一致是非常重要的。在传统的或者没有考虑完整性的系统中,文件的组成部分或者消息的组成部分,即每字节、位或者每个字符都是彼此独立的,由于缺乏彼此的绑定,使得攻击者对于信息的修改无法被发现。在目前的电子商务系统中的各种应用中,这类问题造成的后果更加严重。能否为文件或者网络中通信的消息打上一个标签,当文件或消息出现了任何改变,即便只修改了一位信息时,我们都可以从标签和信息的关系上知道有内容被修改了。这种想法和中世纪在信封上使用蜡封类似。在密码技术中,提供这样的蜡封技术或标签技术的就是为信息提供一种认证,这样的蜡封或者标签在密码技术中称为认证码,如后文中讨论的哈希值、校验和等都是某种形式的认证码。 同样,在网络通信环境中,保密的目的是防止攻击者破译系统中的机密信息,但在大多数网络应用中,仅提供保密性是远远不够的。网络安全的威胁来自两个方面: 一是被动攻击,攻击者只是通过侦听和截取等手段被动地获取数据,并不对数据进行修改; 二是主动攻击,攻击者通过伪造、重放、篡改、改变顺序等手段改变数据。认证则是防止主动攻击的重要技术,它对于开放环境中的各种信息系统的安全性有重要作用,可以防止如下一些攻击。 信息安全原理与技术(第4版) 第5章消息认证与数字签名  伪装: 攻击者生成一个消息并声称这条消息是来自某个合法实体,或者攻击者冒充消息接收方向消息发送方发送的关于收到或未收到消息的欺诈应答。  内容修改: 对消息内容的修改,包括插入、删除、转换和修改。  顺序修改: 对通信双方消息顺序的修改,包括插入、删除和重新排序。  计时修改: 对消息的延迟和重放。在面向连接的应用中,攻击者可能延迟或重放以前某合法会话中的消息序列,也可能会延迟或重放消息序列中的某一条消息。 认证的目的主要有两个: 第一,验证消息的发送方是合法的,不是冒充的,这称为实体认证,包括对信源、信宿等的认证和识别; 第二,验证信息本身的完整性,这称为消息认证,验证数据在传送或存储过程中没有被篡改、重放或延迟等。 保密和认证是信息系统安全的两个重要方面,但它们又是不同的。认证不能自然地提供保密性,而保密性也不能自然地提供认证功能。但从某个层面上而言,我们也可以说保密性提供了某种认证功能,因为攻击者如果无法获得用于加密的密钥,而消息接收方收到了密文,并使用密钥进行解密,同时可以确认解密后得到的信息是正确的(如根据解密后的信息的含义),在这种情况下,整个密文就提供了认证功能。但如果发送方发送的信息是无意义的字符,消息接收方即便正确解密了,也无法通过字符的含义来判定所收到的消息是否是正确的。 因此,如果考虑加密函数的某种认证功能,我们考虑的可用于提供认证功能的认证码的函数则可以分为以下3类。  加密函数: 使用消息发送方和消息接收方共享的密钥对整个消息进行加密,则整个消息的密文将作为认证符。  消息认证码(Message Authentication Code): 它是消息和密钥的函数,用于产生定长度值,该值将作为消息的认证符。  散列函数: 它是将任意长的消息映射为定长的hash值的函数,以该hash值作为认证符。 一个基本的认证系统模型如图5.1所示。 图5.1基本的认证系统模型 5.2消息认证码 消息认证码(MAC)是一种使用密钥的认证技术,它利用密钥来生成一个固定长度的短数据块,并将该数据块附加在消息之后。在这种方法中假定通信双方A和B共享密钥K。若A向B发送消息M时,则A使用消息M和密钥K,计算MAC=C(K,M),其中:  M=输入消息,可变长  C=MAC函数  K=共享的密钥  MAC=消息认证码 消息认证码MAC为消息M的认证符,MAC也称为密码校验和。 如图5.2所示,发送方将消息M和MAC一起发送给接收方。接收方收到消息后,假设该消息为M′,使用相同的密钥K进行计算得出新的MAC′=C(K,M′),比较MAC′和所收到的MAC。假设双方共享的密钥没有被泄露,则比较计算得出的MAC′和收到的MAC的结果,如果两者是相同的话,则可以认为: (1) 接收方可以相信消息未被修改。因为若攻击者篡改了消息,他必须同时相应地修改MAC值。而我们已假定攻击者不知道密钥,所以他不知道应如何改变MAC才能使其与修改后的消息相一致。 (2) 接收方可以相信消息来自真正的发送方。因为其他各方均不知道密钥,他们不能产生具有正确MAC的消息。 (3) 如果消息中含有消息序列号,那么接收方可以相信消息的顺序是正确的,因为攻击者无法成功地修改序列号。 图5.2消息认证码的使用 从使用密钥上看,MAC函数与加密函数类似,需要生成MAC方和验证MAC方共享一个密钥。但它们又存在本质的区别,区别之一为MAC算法不要求可逆性,而加密算法必须是可逆的。一般而言,MAC函数是多对一函数,其定义域由任意长的消息组成,而值域由所有可能的MAC和密钥组成。若使用n位长的MAC,则有2n个可能的MAC,而有m条可能的消息,其中m2n,而且若密钥长为k,则有2k种可能的密钥。 例如,假定使用100位的消息和10位的MAC,那么总共有2100不同的消息,但仅有210种不同的MAC。所以平均而言,同一MAC可以由2100/210条不同的消息产生。若使用的密钥长为5位,则从消息集合到MAC值的集合有25=32种不同的映射。可见密钥的位数太短,很容易通过穷举进行攻击,但只要位数足够长,则可以保证其安全性。 图5.2给出的消息认证码的使用只是对传送消息提供单纯的认证性。它还可以和加密函数一起提供消息认证和保密性。如图5.3所示,发送方在加密消息M之前,先计算M的认证码,然后使用加密密钥将消息及其认证码一起加密; 接收方收到消息后,先解密得到消息及其认证码,再验证解密得到的消息和验证码是否匹配,如果匹配则表示消息在传输中没有被改动。 图5.3结合加密函数的消息认证码的使用方法 5.2.1MAC的安全要求 MAC中使用了密钥,这点和对称密钥加密一样,如果密钥泄露了或者被攻击了,则无法保证MAC的安全性。在基于算法的加密函数中,攻击者可以尝试所有可能的密钥以进行穷举攻击,一般对k位的密钥,穷举攻击需要2k-1步。对于仅依赖于密文的攻击,若给定密文C,攻击者要对所有可能的Ki计算Pi=DKi(C),直到产生的某Pi具有适当的明文结构为止(前提是这样的明文结构是可以判断的)。 MAC函数是多对一函数,这就意味消息的取值空间比MAC的取值空间大,则一定存在着不同的消息会对应于相同的MAC。假设MAC所使用的密钥位数为k,计算所得的MAC位数为n。若k>n,即假定密钥位数比MAC长,则对满足MAC1=CK1(M1)的M1和MAC1,密码分析者要对所有可能的密钥值Ki计算MACi=CKi(M1),那么至少有一个密钥会使得MACi=MAC1。因为k个密钥总共会产生2k个MAC,但只有2n(2n<2k)个不同的MAC值,所以不同密钥都会产生正确的MAC,而攻击者却不知其中哪一个是正确的密钥。平均来说,有2k/2n=2k-n个密钥会产生正确的MAC,因此攻击者必须重复下述攻击。 (1) 第1轮。  给定M1,MAC1=CK(M1)。  对所有2k个密钥判断MACi=CKi(M1)。  匹配数≈2k-n。 (2) 第2轮。  给定M2,MAC2=CK(M2)。  对循环1中找到的2k-n个密钥判断MACi=CKi(M2)。  匹配数≈2k-2n。 攻击者可以按此方法不断对密钥进行测试,直到将匹配数缩小到足够小的范围。平均来讲,若k=a×n,则需a次循环。例如,如果使用80位的密钥和长为32位的MAC,那么第1次循环会得到约248个可能的密钥,第2次循环会得到约216个可能的密钥,第3次循环则得到唯一一个密钥,这个密钥就是发送方所使用的密钥。这样看来,若密钥的长度小于或等于MAC的长度,则很可能在第1次循环中就得到一个密钥。 由此可见,如果密钥足够长,用穷举方法来确定MAC的密钥就不是一件容易的事。 当然,以上的穷举攻击是建立在算法安全强度可信的前提下。针对不同的MAC算法,攻击者可能不需要使用穷举攻击即可找到密钥。攻击者针对下面的MAC算法,则不需要使用穷举攻击即可获得密钥信息。 设消息M=(X1‖X2‖…‖Xm),即由64位分组Xi连接而成。定义: Δ(M)=X1X2… Xm Ck(M)=EK[Δ(M)] 其中是异或(XOR)运算,加密算法是电码本方式实现的DES算法,则密钥长为56位,MAC长为64位。若攻击者获取{M‖Ck(M)},并使用穷举攻击,则确定K须执行至少256次加密,但是攻击者可以用任何期望的Y1~Ym-1替代X1~Xm-1,用Ym替代Xm来进行攻击,其中Ym的计算方法如下。 Ym=Y1Y2…Ym-1Δ(M) 攻击者可以将Y1~Ym-1与原来的MAC连接成一个新的消息M′,接收方收到(M′,Ck(M))时,由于Δ(M′)=Y1Y2… Ym=Δ(M),因此Ck(M)=EK[Δ(M′)],接收方会认为该消息是真实的。利用这种办法,攻击者可以插入任意长为64×(m-1)位的消息。 因此,一个安全的MAC函数应具有下列性质。  若攻击者知道M和Ck(M),则构造满足Ck(M′)=Ck(M)的消息M′在计算上是不可行的。  Ck(M)应是均匀分布的,即对任何随机选择的消息M和M′,Ck(M)=Ck(M′)的概率是2-n,其中n是MAC的位数。  设M′是M 的某个已知的变换,即M′=f(M),则Ck(M)=Ck(M′)的概率为2-n。 5.2.2基于DES的消息认证码 数据认证算法(FIPS PUB 113)是使用最广泛的MAC算法之一,它也是一个ANSI标准(X9.17)。该算法建立在DES算法之上,利用了密文链接模式(CBC)对消息进行加密处理。该算法在实际中的应用很广泛,特别是在银行系统中。 如图5.4所示,数据认证算法取初始值为0,这个初始值没有实际意义,只是用于第1次计算,需要认证的消息被划分成64位的分组D1,D2,…,DN,若最后分组不足64位,则在其后填0直至成为64位的分组。利用DES加密算法E和密钥K,计算认证码的过程如图5.4所示。 O1=EK(D1) O2=EK([D2O1]) O3=EK([D3O2])  ON=EK([DNON-1]) 不输出最后一个分组的加密结果,取其最左边的n位作为认证码。 图5.4数据认证算法 5.3Hash函数 Hash函数(也称散列函数或杂凑函数)是将任意长的输入消息作为输入生成一个固定长的输出串的函数,即h=H(M)。这个输出串h称为该消息的散列值(或消息摘要、杂凑值)。散列函数通常和一个安全的Hash函数H应该至少满足以下几个条件。 (1) H可以应用于任意长度的数据块,产生固定长度的散列值。 (2) 对每一个给定的输入m,计算H(m)是很容易的。 (3) 给定Hash函数的描述,对于给定的散列值h,找到满足H(m)=h的m在计算上是不可行的。 (4) 给定Hash函数的描述,对于给定的消息m1,找到满足m2≠m1且H(m2)=H(m1)的m2在计算上是不可行的。 (5) 找到任何满足H(m1)=H(m2)且m1≠m2的消息对(m1,m2)在计算上是不可行的。 条件(1)和条件(2)指的是Hash函数的“单向”(OneWay)特性,条件(3)和条件(4)是对使用散列值的数字签名方法所做的安全保障。否则攻击者可以由已知的明文及相关数字签名任意伪造对其他明文的数字签名。条件(5)的主要作用是防止后文将要提到的“生日攻击”。通常我们称满足条件(1)~条件(4)的散列函数为“弱散列函数”,若能同时满足条件(5),则称其为“强散列函数”。 Hash函数主要用于完整性校验和提高数字签名的有效性,目前已有很多方案。这些算法都是伪随机函数。早在1978年,Rabin就利用DES算法,使用密文分组链接(CBC)方式,提出一种简单快速的散列函数,方法如下所示。 将明文M分成固定长度的64位的分组: m1,m2,…,mk。使用DES的CBC操作模式,对每个明文分组进行加密,令h0=初始值,hi=Emi[hi-1],最后散列值为hk,这个方法和第5.2.2节中的基于DES的MAC算法类似,但不同的是该算法中的加密没有使用任何密钥。但需要指出的是,使用Rabin散列函数的数字签名是不安全的,已经发现可以在有限的计算范围内,不通过获得签名私钥的方法即可实现伪造签名。 好的散列函数的输出以不可辨别的方式依赖于输入。任何输入串中单个位的变化,将会导致输出位串中大约一半的位发生变化。其处理思想是先要将明文分成固定长度的明文分组,再对每个分组做相同的处理,比较有名的有MD5、Ripend160、SHA、Whirlpool等算法。所有的散列函数都具有图5.5中的处理结构,这种结构称为迭代Hash函数,它是由Merkle提出的。其中的f算法即是散列函数中对分组进行迭代处理的压缩函数。散列函数重复使用压缩函数f,它的输入是前一步得出的n位输出(称为链接值)和一个b位消息分组,输出为一个n位分组。链接值的初始值由算法在开始时指定,其终值即为散列值。这样,一般结构的Hash函数可归纳如下: CV0=IV=n位初始值 CVi=f(CVi-1,Yi-1)1≤ i≤ L H(M)=CVL 其中Hash函数的输入为消息M,经填充后的消息分成L个分组,分别是Y0,Y1,…,YL-1。 图5.5Hash函数的一般结构 Hash函数和MAC函数不同,不需要使用密钥,因此也觉得了Hash函数无法像图5.1中所示的那样单独提供对消息的认证,通常它和数字签名结合使用来提供认证性。在网络安全通信中,Hash函数和对称密码、非对称密码结合使用以提供不同的安全服务。图5.6给出了几种基本应用。 图5.6Hash的基本应用 图5.6(a)给出了Hash函数和数字签名的典型使用方法。对消息M的数字签名通常不是直接对消息进行计算,而是先使用Hash函数得到消息的散列值,再使用发送方的签名私钥PRa对代表消息的散列值进行签名,这样既可以提供消息的认证性,又可以保证效率。图5.6(b)所给出的消息认证方式和MAC有点类似,因为Hash函数不使用密钥,如果直接对消息进行散列值计算,并和消息进行连接传送,则攻击者很容易篡改消息并相应地重新计算散列值。因此,对于计算出来的散列值,使用密钥加密的方法则可以避免发生上述问题,攻击者即便篡改了消息,也因为没有相应的加密密钥伪造消息散列值的密文。图5.6(c)中提供的安全服务是保密性和认证性。除此之外,根据应用需求提供,Hash函数还可以和其他密码函数结合使用提供不同的应用模式。 5.3.1散列函数的安全要求 将第5.3节中给出的安全Hash函数需要满足的后面3个条件重新描述如下(即是Hash函数的安全要求)。 (1) 单向性: 对任何给定的散列码h,找到满足H(x)=h的x在计算上是不可行的。 (2) 抗弱碰撞性: 对任何给定的消息x,找到满足y≠x且H(x)=H(y)的y在计算上是不可行的。 (3) 抗强碰撞性: 找到任何满足H(x)=H(y)的偶对(x,y)在计算上是不可行的。 在图5.5所示的一般结构的Hash函数中,其输入消息被划分成L个固定长度的分组,每一分组长为b位,最后一个分组不足b位时需填充为b位,最后一个分组包含输入的总长度。由于输入中包含长度,所以攻击者必须找出具有相同散列值且长度相等的两条消息,或者找出两条长度不等但加入消息长度信息后散列值相同的消息,从而增加了攻击的难度。Merkle和Damgard发现,如果压缩函数具有抗碰撞能力,那么迭代Hash函数也具有抗碰撞能力,因此Hash函数常使用上述迭代结构,这种结构可用于对任意长度的消息产生安全Hash函数。 1. 生日攻击(Birthday Attack) 如果攻击者希望伪造消息M的签名来欺骗接收方,则他需要找到满足H(M′)=H(M)的M′来替代M。对于生成64位散列值的散列函数,平均需要尝试263次以找到M′。但是建立在生日悖论上的生日攻击法,则会更有效。 对于上述问题换种说法: 假设一个函数有n个函数值,且已知一个函数值H(x)。任选k个任意数作为函数的输入值,则k必须为多大才能保证至少找到一个输入值y且H(x)=H(y)的概率大于0.5? 对于任意的y,能够满足H(x)=H(y)的概率是1/n,反之,满足H(x)≠H(y)的概率为1-1/n。对于所选的k个任意的输入值y都没有一个满足H(x)=H(y)的概率则是(1-1/n)k。这样,至少有一个y满足H(x)=H(y)的概率是1-(1-1/n)k。 二项式定理可描述如下: (1-a)k=1-ka+k(k-1)2!a2-k(k-1)(k-2)3!a3+… 当a趋近0时,(1-a)k趋近1-ka,因此至少有一个y满足H(x)=H(y)的概率约为1-(1-1/n)k≈1-(1-k/n)=k/n。当k> n/2时,这个概率将超过0.5。 若散列值为m位,则可能有2m个散列值,使上述概率为0.5的k为k=2m-1。即对于生成64位散列值的散列函数而言,攻击者至少需要尝试263对明文,才能有大约0.5的成功概率。这个结果似乎表明选择64位的散列函数是安全的,但事实并非如此。Yuval提出的“生日悖论”对于之前提到的Rabin散列函数的数字签名攻击,只需要232次的运算。 在讨论Yuval的方法之前,先来解释一下“生日悖论”的数学背景。我们可以这样描述这类问题: k为多大时,在k个人中至少找到两个人的生日相同的概率大于0.5?不考虑2月29日,并且假定每个生日出现的概率相同。 首先k个人的生日排列的总数目是365k。这样,k个人有不同生日的排列数为: N=365×364×…×(365-k+1)=365!(365-k)! 因此,k个人有不同生日的概率为不重复的排列数除以总数目,得到: Q(365,k)=365!(365-k)!(365)k 则,k个人中,至少找到两个人同日出生的概率是: P(365,k)=1-Q(365,k)=1-365!(365-k)!(365)k 当k=100时,P(365,100)=0.9999997,这意味着只有一个重复的概率接近于百分百。如果只考虑同日出生的概率超过0.5时,则根据P(365,23)=0.5037,k只需要为23。 Yuval的生日攻击法描述如下。 (1) 合法的签名方对于其认为合法的消息愿意使用自己的私钥对该消息生成的m位的散列值进行数字签名。 (2) 攻击者为了伪造一份有(1)中的签名者签名的消息,首先产生一份签名方将会同意签名的消息,再产生出该消息的2m/2种不同的变化,且每一种变化表达相同的意义(如在文字中加入空格、换行字符)。然后,攻击者再伪造一条具有不同意义的新的消息,并产生该伪造消息的2m/2种变化。 (3) 攻击者在上述两个消息集合中找出可以产生相同散列值的一对消息。根据“生日悖论”理论,能找到这样一对消息的概率是非常大的。如果找不到这样的消息,攻击者将再产生一条有效的消息和伪造的消息,并增加每组中的明文数目,直至成功为止。 (4) 攻击者用第一组中找到的明文提供给签名方要求签名,这样,这个签名就可以被用来伪造第二组中找到的明文的数字签名。这样,即使攻击者不知道签名私钥也能伪造签名。 生日攻击表明Hash值的长度必须达到一定的值,如果过短,则容易受到穷举攻击,如一个40位的Hash值,只需要穷举一百万次。一般建议Hash值需要160位,SHA1的最初选择是128位,后来改为160位,这就是为了防止利用生日攻击原理穷举Hash值。 2. 中间相遇攻击法(Meet in the Middle Attack) 中间相遇攻击是生日攻击的一种变形,它不比较散列值,而是比较处理链中的中间变量。这种攻击主要适用于攻击具有分组链接结构的Hash函数。其基本原理为: 将消息分成两部分,对伪造消息的第一部分从初始值开始逐步向中间阶段产生r1个变量; 对伪造消息的第二部分从Hash结果开始逐步退回中间阶段产生r2个变量。在中间阶段有一个匹配的概率与生日攻击成功的概率一样。 这种攻击方法让攻击者可以仅根据已知的明文及其数字签名,来任意伪造其他明文的数字签名。 (1) 根据已知数字签名的明文,先产生散列函数值h。 (2) 再根据意图伪造签名的明文,将其分成每个64位长的明文分组Q1,Q2,…,QN-2。Hash函数的压缩算法为hi=EQi[hi-1],1≤i≤N-2。 (3) 任意产生232个不同的X,对每个X计算EX[hN-2]。同样地,任意产生232个不同的Y,对每个Y计算DY[G],D是相对应E的解密函数。 (4) 根据“生日悖论”,有很大的概率可以找到很多X及Y满足EX[hN-2]=DY[G]。 (5) 如果找到了这样的X和Y,攻击者重新构造一个明文: Q1,Q2,…,QN-2,X,Y。这个新的明文的散列值也为h,因此攻击者可以使用已知的数字签名为这个构造的明文伪造新的明文的签名。 5.3.2SM3 SM3是国家商用密码管理局于2010年12月17日发布的商用散列算法。本标准适用于商用密码应用中的数字签名和验证、消息认证码的生成与验证以及随机数的生成,可满足多种密码应用的安全需求。同时,本标准还可为安全产品生产商提供产品和技术的标准定位以及标准化的参考,提高安全产品的可信性与互操作性。SM3是将长度为L(L< 264) 比特的消息m,压缩输出为256比特的摘要值,如图5.7所示。 图5.7SM2主要处理过程 SM3算法描述如下。 1) 填充与分组 SM3对输入消息先填充,再分组,分组的长度为512比特,消息填充后的比特长度为512的倍数。填充方法如下: 假设消息m的长度为L比特。首先将比特“1”添加到消息的末尾,再添加k个“0”,k是满足L+1+k≡448 mod 512的最小的非负整数。然后再添加一个64位比特串,该比特串是长度L的二进制表示。填充后的消息m′的比特长度为512的倍数。 例如: 对消息01100001 01100010 01100011,其长度L=24,经填充得到比特串: 01100001 01100010 01100011 1 00…00423比特 00…01100064比特 1的二进制表示 2) 初始化 SM3采用8个寄存器ABCDEFGH存储散列运算中间结果和最终结果,首先对寄存器值进行初始化为IV=7380166f 4914b2b9 172442d7 da8a0600 a96f30bc 163138aa e38dee4d b0fb0e4e。这些字节采用高端(bigendian)格式存储,高端格式存储规定: 左边为高有效位,右边为低有效位。数的高阶字节放在存储器的低地址,数的低阶字节放在存储器的高地址。 3) 压缩过程 (1) 迭代过程。 以512位的分组为单位进行迭代压缩计算,将填充后的消息m′按512比特进行分组, m′=Y0Y1…Yn-1 其中n=(L+k+65)/512。 对m′按下列方式迭代: FOR i=0 TO n-L Vi+1=CF(VI,Yi) ENDFOR 其中CF是压缩函数,V0为256比特初始值IV,Yi为填充后的消息分组,迭代压缩的结果为Vn。 (2) 消息扩展。 将消息分组Yi按以下方法扩展生成132个字W0,W1,…,W67,W′0,W′1,…,W′63,用于压缩函数CF: a) 将消息分组Yi划分为16个字,即W0,W1,…,W15。 b) FOR j=16 TO 67 Wj←P1(Wj-16⊕j-9⊕(Wj-3<<<15))⊕(Wj-13<<<7)⊕Wj-6 ENDFOR c) FOR j=0 TO 63 W′j=Wj⊕Wj+4 ENDFOR 其中,⊕表示32比特异或运算,<<