QQ数据包解密

Windows旧版qq数据包格式
特征:

  1. 包头一个字节为02,包尾一个字节为03
  2. udp 8000端口
  3. OICQ协议

OICQ协议格式如下:

typedef struct
{
uchar taghdr;	//02
ushort version;	//版本
ushort cmd;		//命令
ushort seq;		//包序号
uint qqnum;		//qq号码

uchar data[undefined size];		//数据内容,长度为udp数据包长度减去包头其他字段的长度

uchar tagend;	//03

}OICQ_HEADER;

wireshark抓OICQ包截图:
在这里插入图片描述

windows新版及android版数据包
特征:

  1. tcp8080端口
  2. 偏移0-3的4字节表示长度,偏移4-7的4字节表示版本,第8字节表示是否定点加密(1是定点加密,即密钥为16个字节的0,2表示非定点加密,即密钥需要协商获得),第9-12字节的整数表示从本字节开始的偏移量,需要跳过这些字节解析,接下来的一个字节表示:len(qq号码)+4

c语言的头部和qq号码结构体表示如下:

typedef struct
{
uint size;			//包长度,网络字节顺序
uint version;		//版本
uchar isfix;		//命令
uint offset;		//qq号码与本结构尾部位置的偏移
}ANDROID_OQ_HEADER;

typedef struct
{
uint len;			//长度,减去4是qq号码长度
uchar qq;
}ANDROID_OQ_NUMBER;

截图如下:
在这里插入图片描述
在这里插入图片描述

解密后的数据,带有手机IMEI、QQ昵称、手机型号等信息:
在这里插入图片描述

密钥:16个0。

算法:tea_crypt算法,具体实现看代码。

pc版qq 0825数据包解密源码:

#include "qq.h"
#include "qqcrypt.h"
#include <WinSock2.h>
#include "../public.h"
#include "../ProtocolParser.h"
#include "../ResultFile.h"
#include "../fileOper.h"
#include <windows.h>


int QQ::isQQ(const char * data, int len, DATALISTHEADER hdr) {
	if (hdr.sock.protocol == 0x11 )
	{
		if ( hdr.sock.dstport == 8000)
		{
			int firstsize = hdr.sizelist->size;
			if (hdr.datalist->data[0] == 0x02 && hdr.datalist->data[firstsize-1] == 0x03 )
			{
				return TRUE;
			}
		}
	}
	return FALSE;
}




int QQ::processQQ(LPDATABLOCKLIST list, LPPACKSIZELIST sizelist, DATALISTHEADER hdr) {
	int ret = 0;

	char lpbuf [0x1000];
	int offset = 0;
	while (list && sizelist)
	{
		int len = DataBlockList::getNextPacket(list, offset, sizelist, (char*)lpbuf);
		if (len > 0)
		{
			QQHEADER * qqhdr = (QQHEADER*)(lpbuf + 1);
			if (qqhdr->cmd == 0x2508)
			{
				int pad = sizeof(QQHEADER) ;
				if (memcmp(lpbuf + 1 + pad, "\x03\x00\x00\x00", 4) == 0)//010101
				{
					pad += 15;
				}else if (memcmp(lpbuf + 1 + pad,"\x00\x00\x00",3) == 0)
				{
					pad += 15;
				}
				char * offset = lpbuf + 1 + pad;
				int size = len - 1 - pad - 1 ;

				unsigned char *key = (unsigned char*)offset;

				int decodelen = size + 1024;
				unsigned char *decodebuf = new unsigned char[size + 1024];

				int ret = qq_decrypt((unsigned char*)offset + 16, size - 16, key, decodebuf, &decodelen);
				if (ret > 0)
				{
					Public::WriteDataFile("qq.dat", (const char*)decodebuf, decodelen);
				}

				delete decodebuf;

				char szqq[16];
				sprintf(szqq, "%u", ntohl(qqhdr->qq));
				ResultFile::writeRecord(hdr, "qq", "on", szqq);
			}
// 			else if (qqhdr->cmd == 0x3608)
// 			{
// 				char szqq[16];
// 				sprintf(szqq, "%u", ntohl(qqhdr->qq));
// 				ResultFile::writeRecord(hdr, "qq", "on", szqq);
// 			}
		}
		else {

// 			string fn = ProtocolParser::formatfn(hdr, "qq_error");
// 			ret = ProtocolParser::writeBlocks(list, fn);
 			break;
		}
	}
	
	return 0;
}


/*
POST /qbrowser HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0) QQBrowser/9.0
Host: update.browser.qq.com
Content-Length: 345
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: uin_cookie=2210853762; euin_cookie=53DFE9A7024225C8649F40745723E578AC136F6862ECF843

{
"COS": "10.0.17763",
"CSoftID": 22,
"CVer": "1.6.6699.999",
"Cmd": 1,
"ExeVer": "1.0.1118.400",
"GUID": "9308ec3d7b7602d10f39e90f88399236",
"InstallTimeStamp": 1557478990,
"QID": 16785570,
"QQVer": "9.1.3.25332",
"SupplyID": 0,
"TriggerMode": 1,
"UIN": 0,
"bPatch": 0,
"osDigit": 64
}
HTTP/1.1 200
Date: Sun, 11 Aug 2019 03:14:20 GMT
Content-Length: 450
Connection: keep-alive

{ "CSoftID": 22, "CommandLine": "", "Desp": "\u0031\u002e\u0030\u002e\u0031\u0031\u0036\u0030\u002e\u0034\u0030", "DownloadUrl": "http://dl_dir.qq.com/invc/tt/minibrowser11.zip", "ErrCode": 0, "File": "minibrowser11.zip", "Flags": 1, "Hash": "b1309eb4312bd83d154a4b2b1b66547b", "InstallType": 0, "NewVer": "1.0.1160.400", "PatchFile": "QBDeltaUpdate.exe", "PatchHash": "b1309eb4312bd83d154a4b2b1b66547b", "Sign": "", "Size": 36003449, "VerType": "" }
*/

Android版qq解密代码(包含包头处理):


#include "mobileQQ.h"
#include "winsock2.h"
#include "qqcrypt.h"
#include "../public.h"
#include "../ProtocolParser.h"
#include "../ResultFile.h"
#include "../fileOper.h"
#include "../SearchData.h"


int parseHeartbeat(const char * data, int len) {
	const char * pos = SearchData::getstring("Heartbeat.Alive", lstrlenA("Heartbeat.Alive"), data, len);
	if (pos)
	{
		pos = pos - lstrlenA("Heartbeat.Alive") - 2;
		int len = ntohl(*(short*)pos);
		pos += len;

		len = ntohs(*(short*)pos);
		pos += len;

		len = ntohs(*(short*)pos);
		string imei = string(pos + 2, len - 2);
		pos += len;

		len = ntohs(*(short*)pos);
		pos += len;

		len = ntohs(*(short*)(pos -2));
		if (*pos == '|')
		{
			string imsi = string(pos, len - 2);
			imsi = imsi.substr(1);
			int dot = imsi.find("|");
			if (dot > 0)
			{
				imsi = imsi.substr(0, dot);
			}
		}		
	}

	return 0;
}

int MobileQQ::parsePacket(const char * data, int &len,int dport,int sport,DATALISTHEADER hdr) {

	const char * qqdata = data;

	LPMOBILEQQ_PACK_HDR qqhdr = (LPMOBILEQQ_PACK_HDR)qqdata;
	int offset = ntohl(qqhdr->offset);
	if (offset >= 0x80 || offset < 0)
	{
		offset = 4;
	}

	qqdata = qqdata + sizeof(MOBILEQQ_PACK_HDR) + offset;

	string qqno = "";
	char qqnolen = *qqdata - sizeof(int);
	if (qqnolen >= 5 && qqnolen <= 10)
	{
		qqdata++;
		qqno = string(qqdata, qqnolen);
	}
	else {
		printf("error qq no len\r\n");
		return -1;
	}

	qqdata += qqnolen;

	if (qqhdr->cryption == 2)
	{
		ResultFile::writeRecord(hdr, "mqq", "on", qqno);

		unsigned char key[16] = { 0 };

		int cryptlen = len - (qqdata - data);
		unsigned char *decodebuf = new unsigned char[cryptlen + 4096];
		int decodelen = cryptlen + 4096;
		int ret = qq_decrypt((unsigned char*)qqdata, cryptlen, key, decodebuf, &decodelen);
		if (/*ret && */decodelen > 0)
		{
			*(decodebuf + decodelen) = 0;
			printf("succeed decrypted size:%u,encrypted size:%u\r\n", decodelen, cryptlen);
			Public::WriteDataFile("mobileqq.dat", (const char*)decodebuf, decodelen);

			//ResultFile::writeRecord(hdr, "mqq", "on", qqno);
		}
		else {
			printf("error:decrypted size:%u,encrypted size:%u\r\n", decodelen, cryptlen);
			//printf("decrypt mobile qq fix crypt packet error\r\n");
		}

		delete decodebuf;
	}
	else if(qqhdr->cryption == 0){
		printf("no cryption mobile qq packet\r\n");
	}
	else if (qqhdr->cryption == 1)
	{

	}
	else {
		printf("error qq packet cryption\r\n");
		return -1;
	}

	return 0;
}


int MobileQQ::isMobileQQPack(DATALISTHEADER hdr) {
	int dport = hdr.sock.dstport;
	char * data = hdr.datalist->data;
	int len = hdr.sizelist->size;

	if (hdr.sock.protocol == 6 &&(dport == 8080 || dport == 443 || dport == 80 || dport == 14000))
	{
		int packlen = ntohl(*(int*)data);
		if (len == packlen )
		{
			char crypt = *(data + 8);
			if (crypt == 1 || crypt == 2 || crypt == 0)
			{
				int ver = *(int*)(data + sizeof(int));
				//3 = 2010 11 = 2016
				if (ver == 0x0a000000 || ver == 0x0b000000 || ver == 0x09000000)
				{
					return TRUE;
				}
			}
		}
	}

	return FALSE;
}







tea_crypt算法解密源码:

/**
* The QQ2003C protocol plugin
*
* for gaim
*
* Copyright (C) 2004 Puzzlebird
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*
* OICQ encryption algorithm
* Convert from ASM code provided by PerlOICQ
*
* Puzzlebird, Nov-Dec 2002
*/

/*****************************************************************************/
/*Notes: (OICQ uses 0x10 iterations, and modified something...)

IN : 64  bits of data in v[0] - v[1].
OUT: 64  bits of data in w[0] - w[1].
KEY: 128 bits of key  in k[0] - k[3].

delta is chosen to be the real part of
the golden ratio: Sqrt(5/4) - 1/2 ~ 0.618034 multiplied by 2^32.

0x61C88647 is what we can track on the ASM codes.!!
*/

//#ifndef _WIN32
//#include <arpa/inet.h>
//#else
//#include "win32dep.h"
//#endif
#ifndef _QQ_QQ_CRYPT_C_
#define _QQ_QQ_CRYPT_C_

#include <string.h>
#include "qqcrypt.h"
#include <winsock2.h>
#include <stdlib.h>

void qq_encipher(
	unsigned long *const        v,
	const unsigned long *const  k,
	unsigned long *const        w);

void qq_decipher(
	unsigned long *const        v,
	const unsigned long *const  k,
	unsigned long *const        w);

void qq_encrypt(
	unsigned char*  instr,
	int             instrlen,
	unsigned char*  key,
	unsigned char*  outstr,
	int*            outstrlen_prt);

int qq_decrypt(
	unsigned char*  instr,
	int             instrlen,
	unsigned char*  key,
	unsigned char*  outstr,
	int*            outstrlen_ptr);

/*****************************************************************************/
void qq_encipher(
	unsigned long *const        v,
	const unsigned long *const  k,
	unsigned long *const        w)
{
	register unsigned long
		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 = 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);
}

/*****************************************************************************/
void qq_decipher(
	unsigned long *const        v,
	const unsigned long *const  k,
	unsigned long *const        w)
{
	register unsigned long
		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);
}

/********************************************************************
* encrypt part
*******************************************************************/

void qq_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*/

						  //  int rand(void);
						  //  void encrypt_every_8_byte (void);    
						  //  int rand(void) {    /* it can be the real random seed function*/
						  //    return 0xdead; }  /* override with number, convenient for debug*/

						  /*** we encrypt every eight byte ***/
						  //  void encrypt_every_8_byte (void) {
						  //    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*/
						  //    qq_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(); } 
			//void encrypt_every_8_byte (void) 
			{
				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*/
				qq_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*/
		}
	}

	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(); }
			//void encrypt_every_8_byte (void)
			{
				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*/
				qq_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*/
		}
	}

	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(); 
			//void encrypt_every_8_byte (void)
			{
				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*/
				qq_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*/
		}
	}

	*outstrlen_prt = count;
}/* qq_encrypt*/


 /********************************************************************
 * [decrypt part]
 * return 0 if failed, otherwise return 1
 ********************************************************************/

int qq_decrypt(
	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;
	//  int decrypt_every_8_byte (void);
	//  int decrypt_every_8_byte (void) {
	//    for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte ++ ) {
	//        if (context_start + pos_in_byte >= instrlen) return 1;
	//        decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
	//    }
	//    qq_decipher( (unsigned long *) decrypted, 
	//       	  	     (unsigned long *) key, 
	//        	  	   (unsigned long *) decrypted);
	//    
	//    context_start +=  8;
	//    crypt_buff    +=  8;
	//    pos_in_byte   =   0;
	//    return 1;
	//  }/* decrypt_every_8_byte*/

	/* at least 16 bytes and %8 == 0*/
	if ((instrlen % 8) || (instrlen < 16)) return 0;
	/* get information from header*/
	qq_decipher((unsigned long *)instr,
		(unsigned long *)key,
		(unsigned long *)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; 
			//	  int decrypt_every_8_byte (void);
			//	  int decrypt_every_8_byte (void)
			{
				for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
					if (context_start + pos_in_byte >= instrlen)
						return 0;
					decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
				}
				qq_decipher((unsigned long *)decrypted,
					(unsigned long *)key,
					(unsigned long *)decrypted);

				context_start += 8;
				crypt_buff += 8;
				pos_in_byte = 0;
				//		  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;
			//	  int decrypt_every_8_byte (void);
			//	  int decrypt_every_8_byte (void)
			{
				for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
					if (context_start + pos_in_byte >= instrlen)
						return 0;
					decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
				}
				qq_decipher((unsigned long *)decrypted,
					(unsigned long *)key,
					(unsigned long *)decrypted);

				context_start += 8;
				crypt_buff += 8;
				pos_in_byte = 0;
				//		  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;
			//	  int decrypt_every_8_byte (void);
			//	  int decrypt_every_8_byte (void)
			{
				int haveData = 1;
				for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
					if (context_start + pos_in_byte >= instrlen)
					{
						haveData = 0;
						break;
					}
					decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
				}
				if (haveData == 1)
				{
					qq_decipher((unsigned long *)decrypted,
						(unsigned long *)key,
						(unsigned long *)decrypted);

					context_start += 8;
					crypt_buff += 8;
					pos_in_byte = 0;
				}
				//		  return 0;
			}/* decrypt_every_8_byte*/
		}
	}/* for*/
	return 1;
}/* qq_decrypt*/

 /*****************************************************************************/
 /* This is the Public Function */
 /* return 1 is succeed, otherwise return 0*/
int qq_crypt(
	unsigned char   flag,
	unsigned char*  instr,
	int             instrlen,
	unsigned char*  key,
	unsigned char*  outstr,
	int*            outstrlen_ptr)
{
	if (flag == DECRYPT)
		return qq_decrypt(instr, instrlen, key, outstr, outstrlen_ptr);
	else if (flag == ENCRYPT)
		qq_encrypt(instr, instrlen, key, outstr, outstrlen_ptr);

	return 1; /* flag must be DECRYPT or ENCRYPT*/
}/* qq_crypt*/
 /*****************************************************************************/
 /* END OF FILE*/











int qq_decrypt2(
	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;
	//  int decrypt_every_8_byte (void);
	//  int decrypt_every_8_byte (void) {
	//    for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte ++ ) {
	//        if (context_start + pos_in_byte >= instrlen) return 1;
	//        decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
	//    }
	//    qq_decipher( (unsigned long *) decrypted, 
	//       	  	     (unsigned long *) key, 
	//        	  	   (unsigned long *) decrypted);
	//    
	//    context_start +=  8;
	//    crypt_buff    +=  8;
	//    pos_in_byte   =   0;
	//    return 1;
	//  }/* decrypt_every_8_byte*/

	/* at least 16 bytes and %8 == 0*/
	if ((instrlen % 8) || (instrlen < 16)) return 0;
	/* get information from header*/
	qq_decipher((unsigned long *)instr,
		(unsigned long *)key,
		(unsigned long *)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;

	//   if(count!=285 && count!=143)
	// 	  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; 
			//	  int decrypt_every_8_byte (void);
			//	  int decrypt_every_8_byte (void)
			{
				for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
					if (context_start + pos_in_byte >= instrlen)
						return 0;
					decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
				}
				qq_decipher((unsigned long *)decrypted,
					(unsigned long *)key,
					(unsigned long *)decrypted);

				context_start += 8;
				crypt_buff += 8;
				pos_in_byte = 0;
				//		  return 0;
			}/* decrypt_every_8_byte*/
		}
	}/* while*/

	bool bcheck = false;
	outp = outstr;
	while (count != 0) {

		if ((outp - outstr)>4 && false == bcheck)
		{
			int aat = outstr[0] * 256 + outstr[1];
			if (*outstrlen_ptr - aat != 4)
				return 0;

			if (outstr[2] == 0 && outstr[3] == 0)
			{
				bcheck = true;
			}
			else if (outstr[2] == 1 &&
				(outstr[3] >= '0' && outstr[3] <= '9') ||
				(outstr[3] >= 'a' && outstr[3] <= 'z') ||
				(outstr[3] >= 'A' && outstr[3] <= 'Z')
				)
			{
				bcheck = true;
			}
			else
				return 0;
			// 		  if(memcmp(outstr+2,"\x00\x00",2)==0)
			// 		  {
			// 			 // return 1;
			// 		  }
			// 		  else
			// 		  {
			// 			  return 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;
			//	  int decrypt_every_8_byte (void);
			//	  int decrypt_every_8_byte (void)
			{
				for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
					if (context_start + pos_in_byte >= instrlen)
						return 0;
					decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
				}
				qq_decipher((unsigned long *)decrypted,
					(unsigned long *)key,
					(unsigned long *)decrypted);

				context_start += 8;
				crypt_buff += 8;
				pos_in_byte = 0;
				//		  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;
			//	  int decrypt_every_8_byte (void);
			//	  int decrypt_every_8_byte (void)
			{
				int haveData = 1;
				for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
					if (context_start + pos_in_byte >= instrlen)
					{
						haveData = 0;
						break;
					}
					decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
				}
				if (haveData == 1)
				{
					qq_decipher((unsigned long *)decrypted,
						(unsigned long *)key,
						(unsigned long *)decrypted);

					context_start += 8;
					crypt_buff += 8;
					pos_in_byte = 0;
				}
				//		  return 0;
			}/* decrypt_every_8_byte*/
		}
	}/* for*/
	return 1;
}/* qq_decrypt*/



int qq_crypt2(
	unsigned char   flag,
	unsigned char*  instr,
	int             instrlen,
	unsigned char*  key,
	unsigned char*  outstr,
	int*            outstrlen_ptr
)
{
	if (flag == DECRYPT)
		return qq_decrypt2(instr, instrlen, key, outstr, outstrlen_ptr);
	else if (flag == ENCRYPT)
		qq_encrypt(instr, instrlen, key, outstr, outstrlen_ptr);

	return 1; /* flag must be DECRYPT or ENCRYPT*/
}/* qq_crypt*/


#endif
  • 12
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值