在本文第一章中提到,协议用到的对称加密算法为反馈随机交织填充的TEA(Tiny Encryption Algorithm,一种分组加密算法)变形加密算法,记作QQTEA。那么这里将主要介绍填充、交织和反馈这三点,如果大家对TEA算法的加密过程感兴趣,可参考相关文献[1]。 (1)填充算法
为了适用TEA算法,需要使得明文的字节数是8的倍数。如果明文本身的长度不是8的倍数,那么还要进行填充以使其成为8的倍数。以字节为单位,令N=原始字符串+10+填充字节数n,则N应该是8的倍数。
具体的填充方法:第一个字节为:(random()&0xf8)|n,随后填充(n+2)个字节random()&0xff ,后面接原始数据,最后填充7 个字节0x00 。因为使用了不同的随机数,所以填充的结果使得即使对于相同的明文,密文的结果也会不同。 如图:
1Byte
填充长度(n)+2 明文长度
明文
7Byte 0x00
随机数 填充长度 随机数 random()&0xf8 n random()&0xf8
3Byte 填充长度(n)=8-((明文长度+2)%8) (2)交织算法
消息被分为多个加密单元,每一个加密单元都是8字节,使用TEA进行加密,加密结果与下一个加密单元做异或运算后再作为待加密的明文。 (3)反馈加密
因为TEA是分组加密算法,所以需要将明文分块。plain[i]表示明文的第i个分组,crypted[i]表示密文的第i个分组,所有分组加密使用的密钥是相同的,设为key。具体的反馈加密过程如下图所示:
plain[i]
crypted[i-1]
key TEA plain[i-1]
crypted[i]
当i=1时,crypted[i] = E(key, plain[i]);
6
当i>1时,crypted[i] = plain[i-1] xor E(key, plain[i] xor crypted[i-1])。
在参考文献[1]中提到要验证一个密钥是否是正确的,那么只需要取明文和密文的最后16Byte(也就是两个分组)就行了。可是根据上面给出的式子,我们就会发现,对于第一个分组,其实并没有进行反馈处理,因此,只需要对前8Byte(即一个分组)出来解密,通过比较也能判断出测试密钥的正确性。
2.3 伪随机数生成器
在QQ2012客户端程序中使用了伪随机数生成器(PRNC),下面简单介绍伪随机数及其安全性。 (1)伪随机数
真正意义上的随机数(或者随机事件)在某次产生过程中是按照实验过程中表现的分布概率随机产生的,其结果是不可预测的,是不可见的。而计算机中的随机函数是按照一定算法模拟产生的,其结果是确定的,是可见的。所以用计算机随机函数所产生的“随机数”并不随机,是伪随机数。
(2)伪随机数生成器
伪随机数字生成器(PRNG)是一种生成伪随机数的方法。在很多的加密算法以及诸多安全协议中都涉及到了随机数的生成,由此可以看出,一个安全的伪随机数生成器对于密码学来说是至关重要的。因此研究伪随机数的安全性是尤为必要的,但是由于计算机的确定性,那么研究伪随机数的安全性往往是指在多项式时间内不可预测。需要指出的是,QQ2012客户端程序中使用的伪随机数生成器是一种线性同余发生器LCG(Linear congruential generator)。QQ2012 客户端使用的 LCG 来自Microsoft Visual/Quick C/C++ 的rand() 函数。具体的计算方法如下:Xn = (Xn-1 * A + B ) mod M
其中Xn 是序列的第n个数,Xn-1 是序列的第n-1个数,A,B,M都是常数(一般会取质数)。当B=0时,叫做乘同余法。引出一个概念叫seed,它会被作为X0被代入上式中,然后每次调用rand()函数都会用上一次产生的随机值来生成新的随机值。可以看出实际上用rand()函数生成的是一个递推的序列,一切值都来源于最初的 seed。所以当初始的seed取一样的时候,得到的序列都相同。 rand()函数原型:
int __cdecl rand (void){
return(((holdrand=holdrand*214013L+2531011L)>>16)&0x7fff); }
若是要使用该线性同余发生器LCG来产生随机密钥,那么有两种方法:第一种是每次产生两个字节,另一种是每次产生一个字节。作为一个通用的函数例程,其使用的应该是是第二种方法,具体函数例程如下: int fillrandom (char *buffer, const int size) { int i;
7
for(i=0;i { buffer[i]=rand()&0xff; }} 通过上文可以了解到,当选取恰当的A和B时,产生的序列周期是可以达到M的。对于32位的程序来说,这样的周期还是安全的。但是,如果按照上述例程来产生密钥,由于只使用到了8-15的比特位(最低位是第0位),其周期是大大缩短了。这样产生的一个完整周期,它的长度为2^24。在允许的时间范围内检索完这个序列是绝对有可能的,这样一来便为离线字典攻击提供了机会。 第3章 QQ登录协议的漏洞及改进 3.1漏洞1-伪随机数生成器攻击 上文中已经对伪随机数及QQ2012客户端程序中使用的伪随机数生成器进行了简要介绍,并分析了安全性。由此可知,因为伪随机数生成器的安全漏洞,才让我们能够对其生成的随机密钥进行有效预测。从本文第1章对QQ登录协议的介绍可以了解到,一旦我们预测到了Key0,就可以获得{Key1,Key2};获得了Key2,进而就知道了{Key3,Key4};通过Key3就能最终获得SessionKey(会话密钥)。所以,我们可以这样理解:对Key0的攻击,实际上就是对于SessionKey。因此,直接研究对QQ登录协议中极为重要的SessionKey会话秘钥的攻击就可以了。下面重点讲解对SessionKey的攻击(相关数据可参照第1章QQ登录协议流程图): a. 开始捕捉pcap_loop(UDP数据包) b. 判断数据包是否捕捉成功,是则进行c,否则重新捕捉 8 c. 判断数据包是否满足条件: dport=8000并且包含RKey,E(RKey,En(RKey,En(M2P,Key0)));满足便在Rand.bin中寻找RKey对应的偏移量offset,并保存offset,再执行步骤b;不满足则进行d。 d. 判断数据包是否满足条件: sport=8000并且包含En(Key0,{Key1,Key2});满足便在Rand.bin中从offset开始测试每一个可能的密钥,得到Key0,使用Key0解密En(Key0,{Key1,Key2})获得并且保存Key2,再执行步骤b;不满足则进行e。 e. 判断数据包是否满足条件: sport=8000并且包含En(Key2,{Key3,Key4});满足使用Key2解密En(Key2,{Key3,Key4})获得并且保存Key3,再执行步骤b;不满足则进行f。 f. 判断数据包是否满足条件: sport=8000并且包含En(Key3,SessionKey);满足使用Key3解密En(Key3,SessionKey)获得并且保存Key3;不满足则进行b。 相关说明: dport:表示UDP数据包的目的端口 sport:表示UDP数据包的源端口 Rand.bin:使用上一节提到的方法生成的随机数的完整一个周期的数据文件。 寻找RKey对应的偏移量:可以使用暴力的方法 Rand.bin大小只有16MByte。如果这个周期比较大,通过合理的组织数据结构和预先的计算,可以在更快的时间内找到其对应的偏移量。 从offset开始测试每一个可能的密钥:通过多次的试验发现Key0处于offset-16的偏移量位置。复杂的客户端登录操作可能会改变这个偏移量,所以需要采用搜索的方式,而offset-16这个偏移量位置在大部分情况下是正确的。 包含:只需根据UDP数据包的第4个和第5个字节来判断即可。 另外需要注意的是,这种攻击方式并不是适用于所有的情况,至少在“登录保护”情况下就是是无效的。因为在“登录保护”下的Key0应该是至少与登录IP有关的一个MD5校验值。 3.2漏洞2-离线字典攻击 所谓字典攻击,指的是收集好密码可能包含的字符串,然后通过各种方式组合,逐一测试。其实就是猜密码,只不过用电脑来完成。在参考文献[1]中已经提出了一种针对QQ2008的离线字典攻击的方法,在参考文献[2]也简要提到了关于QQ2010的离线字典攻击,其实这些方法对于QQ2012来说同样适用,本文对这个攻击方法将不再赘述。 参照本文第2章关于QQTEA算法的分析可以了解到,要想验证一个口令的正确性,除了选择最后的16Byte进行检验,我们也可以先对开头的8Byte采取解密检验。这样一来,第一个分组便没有反馈,而且第一个字节的最低的三位包含着已知信息(随机填充的字节数)。实际上,如果明文中的任何两个连续分组是 9 已知的,那么它们都是可以用来做解密检验的。下面将讲解测试密钥验证程序(相关数据参照本文第2章QQTEA算法): a. 输入测试密钥key,前8个字节的密文crypted b. 使用测试密钥解密得到明文plain=D(key, crypted) c. 判断是否满足条件:plain[0]&0x7等于1;若满足条件,则进行d;否则,返 回信息“错误的密钥key”。 该判断原因:对于正确的身份验证来说,服务器返回的数据包大小总是为285Byte明文,按照填充规则,填充的头一个字节的最低8位应该等于(8-(285+2)%8)=1 d. 判断是否满足条件:plain[4,5,6,7]等于0x01,0x19,0x00,0x00;若满足条件, 则进行e; 否则,返回信息“错误的密钥key”。 该判断原因:对于正确的身份验证来说,服务器返回的前四个字节是固定的。 e. 判断是否满足条件:plain的最后7个字节都是0x00;若满足条件,则返回信 息“找到正确的密钥key”; 否则,返回信息“错误的密钥key”。 该判断原因:实际上,步骤c和步骤d这两个判断足以判定测试密钥的正确性,但是出于严谨的角度增设此判断。 D(key, crypted):表示使用密钥key对密文 3.3 QQ登陆协议的改进意见 本章给出的改进方法,主要是针对上文中两种攻击提出的。 1.防御伪随机数生成器攻击的方法 通过上文介绍可知,如果想要防御伪随机数生成器攻击,只需修改随机数生成密钥的方式(这里涉及两点:序列周期和K0),那么具体的实现方法如下: (1)周期:使用周期更长的随机数生成器。 (2)K0:关于K0,主要是增加其被预测到的难度。由第1章QQ登录协议流程图可知,K0的生成有随机数的参数。其实,除了有随机数的参数之外,还可与MD5({QQNumber,QQPassword,Time}) 进行一次异或操作,这样攻击者便无法通过简单的随机数预测来获得 K0 的信息。 2. 防御离线字典攻击的方法 这里我们假设攻击者采用离线字典攻击,那么在攻击者和合法用户之间并没有更多信息上的差异。首先我们尝试采用安全的密钥交换协议来抵御离线字典攻击,但是目前使用的密钥交换协议至少是基于Diffie-Hellman密钥交换协议/算法(Diffie-Hellman Key Exchange/Agreement Algorithm)。此协议的巧妙在于需要安全通信的双方可以用这个方法确定对称密钥,然后可以用这个密钥进行加密和解密。但是这一类协议需要一定的存储量和计算量,并不太适合一些 QQ 终端。在第3章提到字典攻击就是收集好密码可能包含的字符串,然后通过各种方式组合,逐一测试,从而获得正确的密钥。那么我们可以通过增加字典攻击的复杂度来抵御攻击: (1)增加TEA变换的轮次(因为TEA加密算法的迭代次数可以改变,建议的迭代次数为32轮。而QQ采用16轮的TEA算法加密) 10 百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说综合文库毕业论文--基于QQ聊天平台的安全通信(2)在线全文阅读。
相关推荐: