首页 | 数据结构 | 文件列表 | 数据字段 | 全局定义

crypt.c

浏览该文件的文档。
00001 
00029 // START OF FILE
00030 /*****************************************************************************/
00031 /*Notes: (OICQ uses 0x10 iterations, and modified something...)
00032 
00033 IN : 64  bits of data in v[0] - v[1].
00034 OUT: 64  bits of data in w[0] - w[1].
00035 KEY: 128 bits of key  in k[0] - k[3].
00036 
00037 delta is chosen to be the real part of 
00038 the golden ratio: Sqrt(5/4) - 1/2 ~ 0.618034 multiplied by 2^32. 
00039 
00040 0x61C88647 is what we can track on the ASM codes.!!
00041 */
00042 
00043 #ifndef _WIN32
00044 #include <arpa/inet.h>
00045 #else
00046 #include "win32dep.h"
00047 #endif
00048 
00049 #include <string.h>
00050 
00051 #include "crypt.h"
00052 
00053 /*****************************************************************************/
00054 void qq_encipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w)
00055 {
00056         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 */
00057 
00058         while (n-- > 0) {
00059                 sum += delta;
00060                 y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
00061                 z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
00062         }                       // while
00063 
00064         w[0] = htonl(y);
00065         w[1] = htonl(z);
00066 }                               // qq_enciper
00067 
00068 /*****************************************************************************/
00069 void qq_decipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w)
00070 {
00071         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
00072             delta = 0x9E3779B9;
00073 
00074         /* sum = delta<<5, in general sum = delta * n */
00075         while (n-- > 0) {
00076                 z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d);
00077                 y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b);
00078                 sum -= delta;
00079         }
00080 
00081         w[0] = htonl(y);
00082         w[1] = htonl(z);
00083 }                               // qq_decipher
00084 
00085 /********************************************************************
00086  * encrypt part
00087  *******************************************************************/
00088 
00089 void qq_encrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_prt)
00090 {
00091         unsigned char plain[8], // plain text buffer
00092          plain_pre_8[8],        // plain text buffer, previous 8 bytes
00093         *crypted,               // crypted text
00094         *crypted_pre_8,         // crypted test, previous 8 bytes
00095         *inp;                   // current position in instr
00096         int pos_in_byte = 1,    // loop in the byte 
00097             is_header = 1,      // header is one byte
00098             count = 0,          // number of bytes being crypted
00099             padding = 0;        // number of padding stuff
00100 
00101         int rand(void) {        // it can be the real random seed function
00102                 return 0xdead;
00103         }                       // override with number, convenient for debug
00104 
00105   /*** we encrypt every eight byte ***/
00106         void encrypt_every_8_byte(void) {
00107                 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
00108                         if (is_header) {
00109                                 plain[pos_in_byte] ^= plain_pre_8[pos_in_byte];
00110                         } else {
00111                                 plain[pos_in_byte] ^= crypted_pre_8[pos_in_byte];
00112                         }
00113                 }               // prepare plain text
00114                 qq_encipher((unsigned long *) plain, (unsigned long *) key, (unsigned long *) crypted); // encrypt it
00115 
00116                 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
00117                         crypted[pos_in_byte] ^= plain_pre_8[pos_in_byte];
00118                 }
00119                 memcpy(plain_pre_8, plain, 8);  // prepare next
00120 
00121                 crypted_pre_8 = crypted;        // store position of previous 8 byte
00122                 crypted += 8;   // prepare next output
00123                 count += 8;     // outstrlen increase by 8
00124                 pos_in_byte = 0;        // back to start
00125                 is_header = 0;  // and exit header
00126         }                       // encrypt_every_8_byte
00127 
00128         pos_in_byte = (instrlen + 0x0a) % 8;    // header padding decided by instrlen
00129         if (pos_in_byte) {
00130                 pos_in_byte = 8 - pos_in_byte;
00131         }
00132         plain[0] = (rand() & 0xf8) | pos_in_byte;
00133 
00134         memset(plain + 1, rand() & 0xff, pos_in_byte++);
00135         memset(plain_pre_8, 0x00, sizeof(plain_pre_8));
00136 
00137         crypted = crypted_pre_8 = outstr;
00138 
00139         padding = 1;            // pad some stuff in header
00140         while (padding <= 2) {  // at most two byte 
00141                 if (pos_in_byte < 8) {
00142                         plain[pos_in_byte++] = rand() & 0xff;
00143                         padding++;
00144                 }
00145                 if (pos_in_byte == 8) {
00146                         encrypt_every_8_byte();
00147                 }
00148         }
00149 
00150         inp = instr;
00151         while (instrlen > 0) {
00152                 if (pos_in_byte < 8) {
00153                         plain[pos_in_byte++] = *(inp++);
00154                         instrlen--;
00155                 }
00156                 if (pos_in_byte == 8) {
00157                         encrypt_every_8_byte();
00158                 }
00159         }
00160 
00161         padding = 1;            // pad some stuff in tailer
00162         while (padding <= 7) {  // at most sever byte
00163                 if (pos_in_byte < 8) {
00164                         plain[pos_in_byte++] = 0x00;
00165                         padding++;
00166                 }
00167                 if (pos_in_byte == 8) {
00168                         encrypt_every_8_byte();
00169                 }
00170         }
00171 
00172         *outstrlen_prt = count;
00173 }                               // qq_encrypt
00174 
00175 
00176 /******************************************************************** 
00177  * [decrypt part]
00178  * return 0 if failed, otherwise return 1
00179  ********************************************************************/
00180 
00181 int qq_decrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_ptr)
00182 {
00183         unsigned char decrypted[8], m[8], *crypt_buff, *crypt_buff_pre_8, *outp;
00184         int count, context_start, pos_in_byte, padding;
00185 
00186         int decrypt_every_8_byte(void) {
00187                 for (pos_in_byte = 0; pos_in_byte < 8; pos_in_byte++) {
00188                         if (context_start + pos_in_byte >= instrlen)
00189                                 return 1;
00190                         decrypted[pos_in_byte] ^= crypt_buff[pos_in_byte];
00191                 }
00192                 qq_decipher((unsigned long *) decrypted, (unsigned long *) key, (unsigned long *) decrypted);
00193 
00194                 context_start += 8;
00195                 crypt_buff += 8;
00196                 pos_in_byte = 0;
00197                 return 1;
00198         }                       // decrypt_every_8_byte
00199 
00200         // at least 16 bytes and %8 == 0
00201         if ((instrlen % 8) || (instrlen < 16))
00202                 return 0;
00203         // get information from header
00204         qq_decipher((unsigned long *) instr, (unsigned long *) key, (unsigned long *) decrypted);
00205         pos_in_byte = decrypted[0] & 0x7;
00206         count = instrlen - pos_in_byte - 10;    // this is the plaintext length
00207         // return if outstr buffer is not large enought or error plaintext length
00208         if (*outstrlen_ptr < count || count < 0)
00209                 return 0;
00210 
00211         memset(m, 0, 8);
00212         crypt_buff_pre_8 = m;
00213         *outstrlen_ptr = count; // everything is ok! set return string length
00214 
00215         crypt_buff = instr + 8; // address of real data start 
00216         context_start = 8;      // context is at the second 8 byte
00217         pos_in_byte++;          // start of paddng stuff
00218 
00219         padding = 1;            // at least one in header
00220         while (padding <= 2) {  // there are 2 byte padding stuff in header
00221                 if (pos_in_byte < 8) {  // bypass the padding stuff, none sense data
00222                         pos_in_byte++;
00223                         padding++;
00224                 }
00225                 if (pos_in_byte == 8) {
00226                         crypt_buff_pre_8 = instr;
00227                         if (!decrypt_every_8_byte())
00228                                 return 0;
00229                 }
00230         }                       // while
00231 
00232         outp = outstr;
00233         while (count != 0) {
00234                 if (pos_in_byte < 8) {
00235                         *outp = crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte];
00236                         outp++;
00237                         count--;
00238                         pos_in_byte++;
00239                 }
00240                 if (pos_in_byte == 8) {
00241                         crypt_buff_pre_8 = crypt_buff - 8;
00242                         if (!decrypt_every_8_byte())
00243                                 return 0;
00244                 }
00245         }                       // while
00246 
00247         for (padding = 1; padding < 8; padding++) {
00248                 if (pos_in_byte < 8) {
00249                         if (crypt_buff_pre_8[pos_in_byte] ^ decrypted[pos_in_byte])
00250                                 return 0;
00251                         pos_in_byte++;
00252                 }
00253                 if (pos_in_byte == 8) {
00254                         crypt_buff_pre_8 = crypt_buff;
00255                         if (!decrypt_every_8_byte())
00256                                 return 0;
00257                 }
00258         }                       // for
00259         return 1;
00260 }                               // qq_decrypt
00261 
00262 /*****************************************************************************/
00263 /* This is the Public Function */
00264 // return 1 is succeed, otherwise return 0
00265 int qq_crypt(unsigned char flag,
00266              unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_ptr)
00267 {
00268         if (flag == DECRYPT)
00269                 return qq_decrypt(instr, instrlen, key, outstr, outstrlen_ptr);
00270         else if (flag == ENCRYPT)
00271                 qq_encrypt(instr, instrlen, key, outstr, outstrlen_ptr);
00272 
00273         return 1;               // flag must be DECRYPT or ENCRYPT
00274 }                               // qq_crypt
00275 
00276 /*****************************************************************************/
00277 // END OF FILE

Generated at Mon May 8 15:41:23 2006 for OpenQ by  doxygen 1.4.4