📄 crypt.cpp
字号:
/**
* 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
*/
// START OF FILE
/*****************************************************************************/
/*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
*/#include <winsock2.h>#pragma comment(lib,"WS2_32.lib")
#include <string.h>#include <stdio.h>
#include "crypt.h"
/*****************************************************************************/
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);
} // while
w[0] = htonl(y);
w[1] = htonl(z);
} // qq_enciper
/*****************************************************************************/
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);
} // qq_decipher
/********************************************************************
* encrypt part
*******************************************************************/ int qq_rand(void) { // it can be the real random seed function return 0xdead; } void encrypt_every_8_byte(unsigned char *plain, unsigned char *plain_pre_8, unsigned char **crypted, unsigned char **crypted_pre_8, unsigned char *inp,unsigned char *key, int *pos_in_byte,int * is_header,int *count,int *padding) { 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}
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
// override with number, convenient for debug
/*** we encrypt every eight byte ***/
// 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] = (qq_rand() & 0xf8) | pos_in_byte;
memset(plain + 1, qq_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++] = qq_rand() & 0xff;
padding++;
} inp=NULL; if (pos_in_byte == 8) { encrypt_every_8_byte(plain, plain_pre_8, &crypted, &crypted_pre_8,inp,key,&pos_in_byte,&is_header,&count,&padding); }
}
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(plain, plain_pre_8, &crypted, &crypted_pre_8,inp,key,&pos_in_byte,&is_header,&count,&padding); }
}
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(plain, plain_pre_8, &crypted, &crypted_pre_8,inp,key,&pos_in_byte,&is_header,&count,&padding); }
}
*outstrlen_prt = count;
} // qq_encrypt
/********************************************************************
* [decrypt part]
* return 0 if failed, otherwise return 1
********************************************************************/
int decrypt_every_8_byte(unsigned char *decrypted,unsigned char *m,unsigned char **crypt_buff,unsigned char *crypt_buff_pre_8,unsigned char *outp,unsigned char *key, int *count, int *context_start,int *pos_in_byte,int *padding,int *instrlen) { 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; } 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;
// 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 stuff
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; outp=NULL; if (!decrypt_every_8_byte(decrypted,m,&crypt_buff,crypt_buff_pre_8,outp,key,&count,&context_start,&pos_in_byte,&padding,&instrlen))
return 0;
}
} // 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(decrypted,m,&crypt_buff,crypt_buff_pre_8,outp,key,&count,&context_start,&pos_in_byte,&padding,&instrlen))
return 0;
}
} // 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(decrypted,m,&crypt_buff,crypt_buff_pre_8,outp,key,&count,&context_start,&pos_in_byte,&padding,&instrlen))
return 0;
}
} // for
return 1;
} // qq_decrypt
/*****************************************************************************/
/* This is the Public Function */
// return 1 is succeed, otherwise return 0
extern "C" 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -