qq.h
#define uchar unsigned char
class qq
{
const int delta = 0x9E3779B9;//黄金数
int c;//轮数
uchar* buf;
void EncryptProc();
void DecryptProc();
public:
uchar* enData=0;
uchar* deData=0;
int* key;
int len;
int oriLen;
qq();
void setKey(int* key);
void setKey(uchar* key);
void Decrypt(uchar* enStr,int c=0x10);
void Encrypt(uchar* str,int size,int c=0x10);
~qq();
};
qq.cpp
#include "qq.h"
#include <ctime>
#include<cstring>
#include<cmath>
#include<iostream>
using namespace std;
qq::qq(){
}
void qq::setKey(int* key){
this->key = key;
}
void qq::setKey(uchar* key){
this->key = new int[4];
for(int i=0;i<4;++i)//将key分为4部分
{
int tmp2=0;
int counter=24;
for(int j=0;j<12;j+=3){
int tmp=0;
int c1=key[i*4*3+j];
int c2=key[i*4*3+j+1];
if(c1>64&&c1<91){
tmp+=(c1-'A'+10)*16;
}
else if(c1>96&&c1<123){
tmp+=(c1-'a'+10)*16;
}
else{
tmp += (c1-'0')*16;
}
if(c2>64&&c2<91){
tmp+=(c2-'A'+10);
}
else if(c2>96&&c2<123){
tmp+=(c2-'a'+10);
}
else{
tmp += (c2-'0');
}
tmp=tmp<<counter;
counter-=8;
tmp2|=tmp;
}
this->key[i]=tmp2;
//cout<<this->key[i]<<endl;
}
}
//加密后结构 buf[0] +a(rand) + 2(rand) + data +7(0),参考TX
void qq::Encrypt (uchar* str, int size,int c){
srand(time(0));
this->c = c;
int a = ceil((size+10)/8.0)*8- (size+10);//a表示随机填充字节数,buf[0]高3位写入a,buf[0]其余位随机填充
len = size + a + 10;//加密后总长度
buf = new uchar[len];
int f=(a&0x7)| (rand() % 32<<3);//将f放在高3位处,其余位随机填充
buf[0] = f;
for(int i=1;i<=a+2;++i)
{
buf[i] = rand() % 256;//填充a+2个随机数
}
memcpy(buf + a + 3, str, size);
memset(buf + (len - 7), 0, 7);//末尾填充7个0,使得长度为 a+3+7 +size
EncryptProc();
}
void qq::Decrypt(uchar* enStr,int c){
this->c = c;
if(enStr==0){
}
else
{
int len=strlen((char*)enStr);
this->len=len/3;
if(this->enData!=0){
delete this->enData;
}
this->enData=new uchar[this->len];
for(int i=0;i<len;i+=3){
uchar tmp=0;
int c1=enStr[i];
int c2=enStr[i+1];
if(c1>64&&c1<91){
tmp+=(c1-'A'+10)*16;
}
else if(c1>96&&c1<123){
tmp+=(c1-'a'+10)*16;
}
else{
tmp += (c1-'0')*16;
}
if(c2>64&&c2<91){
tmp+=(c2-'A'+10);
}
else if(c2>96&&c2<123){
tmp+=(c2-'a'+10);
}
else{
tmp += (c2-'0');
}
this->enData[i/3]=tmp;
}
}
DecryptProc();
}
void qq::EncryptProc()
{
enData = new uchar[len];
int times = len / 8;
int lastLeft1=0,lastRight1=0;
int lastLeft2=0,lastRight2=0;
for(int i=0;i<times;++i)
{
int c1 = c;
int b = 8 * i;
int sum = 0;
int left=0,right=0,tmpLeft=0,tmpRight=0;
left= ((int)*(buf+b))<<24|((int)*(buf+b+1))<<16|((int)*(buf+b+2))<<8|*(buf+b+3);
right= ((int)*(buf+b+4))<<24|((int)*(buf+b+1+4))<<16|((int)*(buf+b+2+4))<<8|*(buf+b+3+4);
left^=lastLeft2;
right^=lastRight2;
tmpLeft=left;
tmpRight=right;
while(c1-->0)
{
sum += delta;
left += (((right << 4)&0xFFFFFFF0) + key[0]) ^ (right + sum) ^ (((right >> 5)&0x07ffffff) + key[1]);
right += (((left << 4)&0xFFFFFFF0) + key[2]) ^ (left + sum) ^ (((left >> 5)&0x07ffffff) + key[3]);
}
left^=lastLeft1;
right^=lastRight1;
*(enData+b)=left>>24;
*(enData+b+1)=left>>16;
*(enData+b+2)=left>>8;
*(enData+b+3)=left;
*(enData+b+4)=right>>24;
*(enData+b+1+4)=right>>16;
*(enData+b+2+4)=right>>8;
*(enData+b+3+4)=right;
lastLeft1=tmpLeft;
lastRight1=tmpRight;
lastLeft2=left;
lastRight2=right;
}
delete buf;
}
void qq::DecryptProc()
{
uchar* temp=deData = new uchar[len];
int times = len / 8;
int lastLeft1=0,lastRight1=0;
int lastLeft2=0,lastRight2=0;
for (int i = 0; i<times; ++i)
{
int c1 = c;
int b = 8 * i;
int sum = delta<<(int)(log(c)/log(2));//计算加密后的sum值 和下面这句意思一样
// int sum=c1*delta;
int left, right,tmpLeft,tmpRight;
//千万别用memcpy或者memmove,int在内存中的字节序是反的,低位在前,高位在后(从左到右),而此时uchar数组的顺序是高位在前的
//还有特别需要说明的是,int仅仅是字节序存储从人的角度上来说是反的,左移右移操作其实也在站在人的角度上描述的,右移如果在内存中横向看的话其实一直都是在向左走的。还有就是我看到有人提到大小存储,现在基本都是小存储,即低位对应低位,这个问题应该是不会遇到的
left= ((int)*(enData+b))<<24|((int)*(enData+b+1))<<16|((int)*(enData+b+2))<<8|*(enData+b+3);
right= ((int)*(enData+b+4))<<24|((int)*(enData+b+1+4))<<16|((int)*(enData+b+2+4))<<8|*(enData+b+3+4);
tmpLeft=left;
tmpRight=right;
left^=lastLeft1;
right^=lastRight1;
//cout<<left<<' '<<right<<endl;
while (c1-->0)
{
right -= (((left << 4)&0xFFFFFFF0) + key[2]) ^ (left + sum) ^ (((left >> 5)&0x07ffffff) + key[3]); //这个地方一定要& 因为int是有符号的,所以负数右移会采用算术右移
left -= (((right << 4)&0xFFFFFFF0) + key[0]) ^ (right + sum) ^ (((right >> 5)&0x07ffffff) + key[1]);
sum -= delta;
}
//cout<<left<<' '<<right<<endl;
lastLeft1=left;//解密后的密文块,未做XOR
lastRight1=right;
left^=lastLeft2;
right^=lastRight2;
lastLeft2=tmpLeft;//本次的原始密文块,未做XOR
lastRight2=tmpRight;
//同样,这个地方也别用memcpy或者memmove,uchar数组需将高位放在前面以还原数据
*(temp+b)=left>>24;
*(temp+b+1)=left>>16;
*(temp+b+2)=left>>8;
*(temp+b+3)=left;
*(temp+b+4)=right>>24;
*(temp+b+1+4)=right>>16;
*(temp+b+2+4)=right>>8;
*(temp+b+3+4)=right;
}
int a=temp[0] &0x7 ;
//cout<<a<<endl;
oriLen = len - a - 10 ;
deData = new uchar[oriLen];
memcpy(deData, temp + a + 3, oriLen);
delete temp;
}
qq::~qq()
{
delete enData;
delete deData;
}
test.cpp
#include "qq.h"
#include<cstring>
#include<iostream>
using namespace std;
char* getHexStr(uchar* data,int len){
char* buf=new char[len*3+1];
for(int i=0,j=0;i<len;++i,j+=3){
buf[j]= data[i]>>4;
buf[j+1]= data[i]&0xF;
buf[j+2]=' ';
if(buf[j]>9){
buf[j]=buf[j]-10+'A';
}
else{
buf[j]+='0';
}
if(buf[j+1]>9){
buf[j+1]=buf[j+1]-10+'A';
}
else{
buf[j+1]+='0';
}
}
buf[3*len]='\0';
return buf;
}
int main(int argc, char const *argv[])
{
// char* str="hello world";
// int len=strlen(str);
// qq* t=new qq();
// int key[]={111,222,333,444};
// t->setKey(key);
// t->Encrypt((uchar*)str,len+1);
// t->Decrypt(0);
// cout<<"sourceHex:"<<getHexStr((uchar*)str,len+1)<<endl;
// cout<<"encryptHex:"<<getHexStr(t->enData,t->len)<<endl;
// cout<<"decryptHex:"<<getHexStr(t->deData,t->oriLen)<<endl;
// cout<<"decryptData:"<<t->deData<<endl;
//qq数据包测试
uchar* enStr=(uchar*)"fa c7 38 a6 ee ec f6 b6 ea 8e e6 e5 81 01 29 83 b5 b9 3a cb e1 2d fc 02 b0 7b ca 3d 87 88 3e 86 ed 78 ca a5 62 08 44 49 74 3c 16 89 c6 5f cf 95 32 26 54 dc 7a aa 4d 16 5b 1a 39 0f 84 26 4d f7 46 5f 1f 61 5c 2d 80 97 3e 1f 1a 74 95 38 b1 11 aa db 76 8e 8d 86 1d b7 32 58 8d a7 0f 30 63 c2 af 6a af b3 85 8e 8b 51 03 ";
qq* t=new qq();
t->setKey((uchar*)"c9 b8 07 73 16 a3 0b 57 db 46 91 b9 16 b3 31 64 ");
t->Decrypt(enStr);
cout<<getHexStr(t->enData,t->len)<<endl;
cout<<getHexStr(t->deData,t->oriLen)<<endl;
cout<<getHexStr((uchar*)t->key,16)<<endl;
cin.get();
cin.get();
/* code */
return 0;
}