QQ_TEA算法如何实现 ?

CODE:
// in 实际数据,inlen实际数据长度,key密钥(16字节长度),out处理结果,outlen处理结果长度值
void encrypt_msg(unsigned char *in, int inlen, unsigned long *key, unsigned char *out, unsigned long *outlen)
{
register int m, i, j, count, [color=Red]p = 1[/color];
unsigned char q[12], *q1, *q2, *inp;
unsigned char mkey[8];

m = (inlen+10)%8; // 为什么不用m = (inlen)%8; 来保证明文长度为 8 整数倍 ????
if (m) m = 8-m;
q[0] = (rand()&0xf8) | m; // 加密结果不唯一的原因采用了随机数
i = j = 1;
while(m>0) {
q[i++] = rand()&0xff;
m --;
}
count = *outlen = 0; // 传入的outlen值岂不没有用?????
q2 = q1 = out;
memset(mkey, 0, sizeof(mkey));
while( [color=Red]p <= 2[/color] ) { // 初值p = 1确定了,这个循环执行2次
if (i < 8) {
q[i++] = rand()&0xff;
p ++;
}
if (i == 8) { // 此时m=7,
for (i = 0; i < 8; i ++)
q[i] ^= mkey[i];
encrypt_qword((unsigned long *)q, key, (unsigned long *)out); // TEA 加密算法
for (i = 0; i < 8; i ++)
q1[i] ^= mkey[i];
q2 = q1;
q1 += 8;
count += 8;
memcpy(mkey, q, 8);
j = i = 0;
}
}
inp = in;
while (inlen > 0) {
if (i < 8) {
q[i] = inp[0];
inp ++;
i ++;
inlen --;
}
if (i == 8) {
for (i = 0; i < 8; i ++) {
if (j) q[i] ^= mkey[i];
else q[i] ^= q2[i];
}
j = 0;
encrypt_qword((unsigned long *)q, key, (unsigned long *)q1);
for (i = 0; i < 8; i ++)
q1[i] ^= mkey[i];
count += 8;
memcpy(mkey, q, 8);
q2 = q1;
q1 += 8;
i = 0;
}
}
p = 1;
while (p < 8) {
if (i < 8) {
memset(q+i, 0, 4);
p++;
i++;
}
if (i == 8) {
for (i = 0; i < 8; i ++)
q[i] ^= q2[i];
encrypt_qword((unsigned long *)q, key, (unsigned long *)q1);
for (i = 0; i < 8; i ++)
q1[i] ^= mkey[i];
memcpy(mkey, q, 8);
count += 8;
q2 = q1;
q1 += 8;
i = 0;
}
}
*outlen = count;
}


对上面这段QQ_TEA程序有点不明白,大家帮忙解释下
以下是网上对QQ_TEA的一点介绍,能对上吗?
QQ使用的TEA虽然是标准的TEA,但是QQ在使用这个算法的时候,由于需要加密不定长的数据,所以使用了一些常规的填充办法和交织算法(也就是说,把前一组的加密结果和后一组未加密的结果进行运算,产生新的结果)。QQ消 息被分为多个加密单元,每一个加密单元都是8字节,使用TEA进行加密,加密结果再作为下一个单元 的密钥。如果明文本身的长度不是8的倍数,那么还要进行填充,使其成为8的倍数。填充的时候会用一 个32位随机数存放于明文的开始位置,再在明文的最后用0填充为整个长度是8的 倍数。由于会向后反馈,这样即使对于相同的明文,因为使用了不同的随机数,也会产生完全不同的密文。使用这种特殊的填充反馈算 法所导致的结果就是,一段密文只能用加密它的密钥进行解密,如果使用不正确的密钥,就无法得到正确的填充结果。最常见的就是解密后得到的填充数值不是0, 这样就判断解密失败。

QQ消息的加密算法是一个16次的迭代过程,并且是反馈的,每一个加密单元是8字节,输出也是8字节,密钥是16字节
以prePlain表示前一个明文块,plain表示当前明文块,crypt表 示当前明文块加密得到的密文块,preCrypt表示前一个密文块
f表示加密算法, 那么从plain得到crypt的 过程是: crypt = f(plain ˆ preCrypt ) &circ
d表示解密算法,从crypt得到plain的过程 自然是 plain = d(crypt ˆ prePlain) ˆ
填充机制,其会在明文前和明文后分别填充一定的字节数,以保证明文长度是8字节的倍数填充的字节数与原始明 文长度有关,填充的方法是:

------- 消息填充算法 ----------- 
a = (明文长度 + 10) mod 8 //计算填充长度
if(a 不等于 0) a = 8 - a;
b = 随机数 & 0xF8 | a; //这个的作用是把a的值保存了下来
plain[0] = b; //然后把b做为明文的第0个字节,这样第0个 字节就保存了a的信息,这个信息在解密时就要用来找到真正明文的起始位置
plain[1 至 a+2] = 随机 数 & 0xFF; // 这里用随机数填充明文的第1到 第a+2个字节
plain[a+3 至 a+3+明文长度-1] = 明文; //从a+3字 节开始才是真正的明文
plain[a+3+明文长度, 最后] = 0; //在最后,填充0,填充到总长度为8的 整数为止。到此为止,结束了,这就是最后得到的要加密的明文内容

 

void EvaQQCrypt::Encrypt ( 
unsigned char* instr,
int instrlen,
unsigned char* key,
unsigned char* outstr,
int* outstrlen_prt)
{
unsigned char 
plain[8], /* plain text buffer*/
plain_pre_8[8], /* plain text buffer, previous 8 bytes*/
* crypted, /* crypted text*/
* crypted_pre_8, /* crypted test, previous 8 bytes*/
* inp; /* current position in instr*/
int 
pos_in_byte = 1, /* loop in the byte */
is_header=1, /* header is one byte*/
count=0, /* number of bytes being crypted*/
padding = 0; /* number of padding stuff*/

//void encrypt_every_8_byte (void); 

/*** we encrypt every eight byte ***/
#define encrypt_every_8_byte() /
{/
for(pos_in_byte=0; pos_in_byte<8; pos_in_byte++) {/
if(is_header) { plain[pos_in_byte] ^= plain_pre_8[pos_in_byte]; }/
else { plain[pos_in_byte] ^= crypted_pre_8[pos_in_byte]; }/
} /* prepare plain text*//
Tea_Encipher( (unsigned long *) plain,/
(unsigned long *) key, /
(unsigned long *) crypted); /* encrypt it*//
/
for(pos_in_byte=0; pos_in_byte<8; pos_in_byte++) {/
crypted[pos_in_byte] ^= plain_pre_8[pos_in_byte]; /
} /
memcpy(plain_pre_8, plain, 8); /* prepare next*//
/
crypted_pre_8 = crypted; /* store position of previous 8 byte*//
crypted += 8; /* prepare next output*//
count += 8; /* outstrlen increase by 8*//
pos_in_byte = 0; /* back to start*//
is_header = 0; /* and exit header*//
}/* encrypt_every_8_byte*/

pos_in_byte = (instrlen + 0x0a) % 8; /* header padding decided by instrlen*/
if (pos_in_byte) { 
pos_in_byte = 8 - pos_in_byte; 
}
plain[0] = (rand() & 0xf8) | pos_in_byte;

memset(plain+1, rand()&0xff, pos_in_byte++);
memset(plain_pre_8, 0x00, sizeof(plain_pre_8));

crypted = crypted_pre_8 = outstr;

padding = 1; /* pad some stuff in header*/
while (padding <= 2) { /* at most two byte */
if(pos_in_byte < 8) { plain[pos_in_byte++] = rand() & 0xff; padding ++; } 
if(pos_in_byte == 8){ encrypt_every_8_byte(); } 
}

inp = instr;
while (instrlen > 0) {
if (pos_in_byte < 8) { plain[pos_in_byte++] = *(inp++); instrlen --; }
if (pos_in_byte == 8){ encrypt_every_8_byte(); }
}

padding = 1; /* pad some stuff in tailer*/
while (padding <= 7) { /* at most sever byte*/
if (pos_in_byte < 8) { plain[pos_in_byte++] = 0x00; padding ++; }
if (pos_in_byte == 8){ encrypt_every_8_byte(); }


*outstrlen_prt = count;

}
作者: nxzcc 发布日期: 2010-7-23
直接看不懂
作者: lemonade 发布日期: 2010-7-23
顶一下
作者: vfdff 发布日期: 2010-8-21

QQ_TEA算法仅仅对标准的 TEA算法进行了一些调整,使适应输入长度不定的情况而已,本身不包括md5算法

http://www.linuxdiyf.com/viewarticle.php?id=182915

 

 

 个人为开发一些QQ应用程序,研究分析了QQ的通讯协议...


现遇到的麻烦就是所有的QQ通信均采用了TEA算法进行加必或解密,如果是公用的TEA算法,那么一下子就知道了....

QQ公司改TEA算法,用C语言实现如下:

 

#include <stdio.h>

#include <string.h>

#ifdef _WIN32

#include <winsock.h>

#else

#include <arpa/inet.h>

#endif

#include "qqcrypt.h"

#include "debug.h"

static int random(void)

{

 /* it can be the real random seed function*/

 return 0xdead; /* override with number, convenient for debug*/ 

}

 

static void encipher(unsigned int *const v, const unsigned int *const k, 

   unsigned int *const w)

{

 register unsigned int 

  y     = ntohl(v[0]),

  z     = ntohl(v[1]),

  a     = ntohl(k[0]),

  b     = ntohl(k[1]),

  c     = ntohl(k[2]),

  d     = ntohl(k[3]),

  n     = 0x10,       /* do encrypt 16 (0x10) times */

  sum   = 0,

  delta = 0x9E3779B9; /*  0x9E3779B9 - 0x100000000 = -0x61C88647 */

 while (n-- > 0) {

  sum += delta;

  y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);

  z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);

 }

 w[0] = htonl(y); w[1] = htonl(z);

}

static void decipher(unsigned int *const v, const unsigned int *const k, 

   unsigned int *const w)

{

 register unsigned int

  y     = ntohl(v[0]),

  z     = ntohl(v[1]),

  a     = ntohl(k[0]),

  b     = ntohl(k[1]),

  c     = ntohl(k[2]),

  d     = ntohl(k[3]),

  n     = 0x10,

  sum   = 0xE3779B90, 

  /* why this ? must be related with n value*/

  delta = 0x9E3779B9;

 /* sum = delta<<5, in general sum = delta * n */

 while (n-- > 0) {

  z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);

  y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);

  sum -= delta;

 }

 w[0] = htonl(y); w[1] = htonl(z);

}

void qqencrypt( unsigned char* instr, int instrlen, unsigned char* key,

   unsigned char*  outstr, int* outstrlen_ptr)

{

 unsigned char 

  plain[8],         /* plain text buffer*/

  plain_pre_8[8],   /* plain text buffer, previous 8 bytes*/

  * crypted,        /* crypted text*/

  * crypted_pre_8,  /* crypted test, previous 8 bytes*/

  * inp;            /* current position in instr*/

 int 

  pos_in_byte = 1,  /* loop in the byte */

  is_header=1,      /* header is one byte*/

  count=0,          /* number of bytes being crypted*/

  padding = 0;      /* number of padding stuff*/

 //void encrypt_every_8_byte (void);    

 /*** we encrypt every eight byte ***/

#define encrypt_every_8_byte()  /

 {/

 for(pos_in_byte=0; pos_in_byte<8; pos_in_byte++) {/

 if(is_header) { plain[pos_in_byte] ^= plain_pre_8[pos_in_byte]; }/

   else { plain[pos_in_byte] ^= crypted_pre_8[pos_in_byte]; }/

 } /* prepare plain text*//

 encipher( (unsigned int *) plain,/

 (unsigned int *) key, /

 (unsigned int *) crypted);   /* encrypt it*//

 /

 for(pos_in_byte=0; pos_in_byte<8; pos_in_byte++) {/

 crypted[pos_in_byte] ^= plain_pre_8[pos_in_byte]; /

 } /

 memcpy(plain_pre_8, plain, 8);     /* prepare next*//

 /

 crypted_pre_8   =   crypted;       /* store position of previous 8 byte*//

 crypted         +=  8;             /* prepare next output*//

 count           +=  8;             /* outstrlen increase by 8*//

 pos_in_byte     =   0;             /* back to start*//

 is_header       =   0;             /* and exit header*//

 }/* encrypt_every_8_byte*/

 pos_in_byte = (instrlen + 0x0a) % 8; /* header padding decided by instrlen*/

 if (pos_in_byte) { 

  pos_in_byte = 8 - pos_in_byte; 

 }

 plain[0] = (random() & 0xf8) | pos_in_byte;

 

 memset(plain+1, random()&0xff, pos_in_byte++);

 memset(plain_pre_8, 0x00, sizeof(plain_pre_8));

 crypted = crypted_pre_8 = outstr;

 padding = 1; /* pad some stuff in header*/

 while (padding <= 2) { /* at most two byte */

  if(pos_in_byte < 8) { plain[pos_in_byte++] = random() & 0xff; padding ++; } 

  if(pos_in_byte == 8){ encrypt_every_8_byte(); } 

 }

 inp = instr;

 while (instrlen > 0) {

  if (pos_in_byte < 8) { plain[pos_in_byte++] = *(inp++); instrlen --; }

  if (pos_in_byte == 8){ encrypt_every_8_byte(); }

 }

 padding = 1; /* pad some stuff in tailer*/

 while (padding <= 7) { /* at most sever byte*/

  if (pos_in_byte < 8) { plain[pos_in_byte++] = 0x00; padding ++; }

  if (pos_in_byte == 8){ encrypt_every_8_byte(); }

 } 

 *outstrlen_ptr = count;

}

int qqdecrypt( unsigned char* instr, int instrlen, unsigned char* key,

   unsigned char*  outstr, int* outstrlen_ptr)

{

 unsigned char 

  decrypted[8], m[8],

  * crypt_buff, 

  * crypt_buff_pre_8, 

  * outp;

 int 

  count, 

  context_start, 

  pos_in_byte, 

  padding;

#define decrypt_every_8_byte()  {/

 char bNeedRet = 0;/

 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte ++ ) {/

 if (context_start + pos_in_byte >= instrlen) /

 {/

 bNeedRet = 1;/

 break;/

 }/

 decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];/

 }/

 if( !bNeedRet ) { /

 decipher( (unsigned int *) decrypted, /

 (unsigned int *) key, /

 (unsigned int *) decrypted);/

 /

 context_start +=  8;/

 crypt_buff    +=  8;/

 pos_in_byte   =   0;/

 }/

}/* decrypt_every_8_byte*/

 /* at least 16 bytes and %8 == 0*/

 if ((instrlen % 8) || (instrlen < 16)) return 0; 

 /* get information from header*/

 decipher( (unsigned int *) instr, 

  (unsigned int *) key, 

  (unsigned int *) decrypted);

 pos_in_byte = decrypted[0] & 0x7;

 count = instrlen - pos_in_byte - 10; /* this is the plaintext length*/

 /* return if outstr buffer is not large enought or error plaintext length*/

 if (*outstrlen_ptr < count || count < 0) return 0;

 memset(m, 0, 8);

 crypt_buff_pre_8 = m;

 *outstrlen_ptr = count;   /* everything is ok! set return string length*/

 crypt_buff = instr + 8;   /* address of real data start */

 context_start = 8;        /* context is at the second 8 byte*/

 pos_in_byte ++;           /* start of paddng stuffv*/

 padding = 1;              /* at least one in header*/

 while (padding <= 2) {    /* there are 2 byte padding stuff in header*/

  if (pos_in_byte < 8) {  /* bypass the padding stuff, none sense data*/

   pos_in_byte ++; padding ++;

  }

  if (pos_in_byte == 8) {

   crypt_buff_pre_8 = instr;

   //if (! decrypt_every_8_byte()) return 0; 

   decrypt_every_8_byte();

  }

 }/* while*/

 outp = outstr;

 while(count !=0) {

  if (pos_in_byte < 8) {

   *outp = crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte];

   outp ++;

   count --;

   pos_in_byte ++;

  }

  if (pos_in_byte == 8) {

   crypt_buff_pre_8 = crypt_buff - 8;

   //if (! decrypt_every_8_byte()) return 0;

   decrypt_every_8_byte();

  }

 }/* while*/

 for (padding = 1; padding < 8; padding ++) {

  if (pos_in_byte < 8) {

   if (crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte]) {

    return 0;

   }

   pos_in_byte ++; 

  }

  if (pos_in_byte == 8 ) {

   crypt_buff_pre_8 = crypt_buff;

   //if (! decrypt_every_8_byte()) return 0; 

   decrypt_every_8_byte();

  }

 }/* for*/

 return 1;

}

 

http://bbs.phpchina.com/thread-163517-1-1.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值