Mercurial > pidgin
comparison src/protocols/qq/crypt.c @ 14021:ef8490f9e823
[gaim-migrate @ 16618]
Replaced all C++-style comments with C-style ones.
Cleaned up some comments and implemented a more consistent formatting scheme.
committer: Tailor Script <tailor@pidgin.im>
| author | Mark Huetsch <markhuetsch> |
|---|---|
| date | Wed, 02 Aug 2006 15:35:36 +0000 |
| parents | 96947ec79828 |
| children |
comparison
equal
deleted
inserted
replaced
| 14020:13e7ba964993 | 14021:ef8490f9e823 |
|---|---|
| 24 * Convert from ASM code provided by PerlOICQ | 24 * Convert from ASM code provided by PerlOICQ |
| 25 * | 25 * |
| 26 * Puzzlebird, Nov-Dec 2002 | 26 * Puzzlebird, Nov-Dec 2002 |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 // START OF FILE | |
| 30 /*****************************************************************************/ | |
| 31 /*Notes: (OICQ uses 0x10 iterations, and modified something...) | 29 /*Notes: (OICQ uses 0x10 iterations, and modified something...) |
| 32 | 30 |
| 33 IN : 64 bits of data in v[0] - v[1]. | 31 IN : 64 bits of data in v[0] - v[1]. |
| 34 OUT: 64 bits of data in w[0] - w[1]. | 32 OUT: 64 bits of data in w[0] - w[1]. |
| 35 KEY: 128 bits of key in k[0] - k[3]. | 33 KEY: 128 bits of key in k[0] - k[3]. |
| 43 #include <arpa/inet.h> | 41 #include <arpa/inet.h> |
| 44 | 42 |
| 45 #include <string.h> | 43 #include <string.h> |
| 46 | 44 |
| 47 #include "crypt.h" | 45 #include "crypt.h" |
| 48 #include "debug.h" // gaim_debug | 46 #include "debug.h" |
| 49 | 47 |
| 50 /******************************************************************** | 48 /******************************************************************** |
| 51 * encryption | 49 * encryption |
| 52 *******************************************************************/ | 50 *******************************************************************/ |
| 53 | 51 |
| 52 /* TODO: convert these data types to proper glib ones */ | |
| 54 static void qq_encipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w) | 53 static void qq_encipher(unsigned long *const v, const unsigned long *const k, unsigned long *const w) |
| 55 { | 54 { |
| 56 register unsigned long y = ntohl(v[0]), | 55 register unsigned long y = ntohl(v[0]), |
| 57 z = ntohl(v[1]), | 56 z = ntohl(v[1]), |
| 58 a = ntohl(k[0]), | 57 a = ntohl(k[0]), |
| 71 | 70 |
| 72 w[0] = htonl(y); | 71 w[0] = htonl(y); |
| 73 w[1] = htonl(z); | 72 w[1] = htonl(z); |
| 74 } | 73 } |
| 75 | 74 |
| 76 static int rand(void) { // it can be the real random seed function | 75 static int rand(void) { /* it can be the real random seed function */ |
| 77 return 0xdead; | 76 return 0xdead; |
| 78 } // override with number, convenient for debug | 77 } /* override with number, convenient for debug */ |
| 79 | 78 |
| 80 // we encrypt every eight byte chunk | 79 /* we encrypt every eight byte block */ |
| 81 static void encrypt_every_8_byte(unsigned char *plain, unsigned char *plain_pre_8, unsigned char **crypted, | 80 static void encrypt_every_8_byte(unsigned char *plain, unsigned char *plain_pre_8, unsigned char **crypted, |
| 82 unsigned char **crypted_pre_8, unsigned char *key, int *count, int *pos_in_byte, int *is_header) | 81 unsigned char **crypted_pre_8, unsigned char *key, int *count, int *pos_in_byte, int *is_header) |
| 83 { | 82 { |
| 84 // prepare plain text | 83 /* prepare plain text */ |
| 85 for (*pos_in_byte = 0; *pos_in_byte < 8; (*pos_in_byte)++) { | 84 for (*pos_in_byte = 0; *pos_in_byte < 8; (*pos_in_byte)++) { |
| 86 if (*is_header) { | 85 if (*is_header) { |
| 87 plain[*pos_in_byte] ^= plain_pre_8[*pos_in_byte]; | 86 plain[*pos_in_byte] ^= plain_pre_8[*pos_in_byte]; |
| 88 } else { | 87 } else { |
| 89 plain[*pos_in_byte] ^= (*crypted_pre_8)[*pos_in_byte]; | 88 plain[*pos_in_byte] ^= (*crypted_pre_8)[*pos_in_byte]; |
| 90 } | 89 } |
| 91 } | 90 } |
| 92 qq_encipher((unsigned long *) plain, (unsigned long *) key, (unsigned long *) *crypted); // encrypt it | 91 /* encrypt it */ |
| 92 qq_encipher((unsigned long *) plain, (unsigned long *) key, (unsigned long *) *crypted); | |
| 93 | 93 |
| 94 for (*pos_in_byte = 0; *pos_in_byte < 8; (*pos_in_byte)++) { | 94 for (*pos_in_byte = 0; *pos_in_byte < 8; (*pos_in_byte)++) { |
| 95 (*crypted)[*pos_in_byte] ^= plain_pre_8[*pos_in_byte]; | 95 (*crypted)[*pos_in_byte] ^= plain_pre_8[*pos_in_byte]; |
| 96 } | 96 } |
| 97 memcpy(plain_pre_8, plain, 8); // prepare next | 97 memcpy(plain_pre_8, plain, 8); /* prepare next */ |
| 98 | 98 |
| 99 *crypted_pre_8 = *crypted; // store position of previous 8 byte | 99 *crypted_pre_8 = *crypted; /* store position of previous 8 byte */ |
| 100 *crypted += 8; // prepare next output | 100 *crypted += 8; /* prepare next output */ |
| 101 *count += 8; // outstrlen increase by 8 | 101 *count += 8; /* outstrlen increase by 8 */ |
| 102 *pos_in_byte = 0; // back to start | 102 *pos_in_byte = 0; /* back to start */ |
| 103 *is_header = 0; // and exit header | 103 *is_header = 0; /* and exit header */ |
| 104 } // encrypt_every_8_byte | 104 } /* encrypt_every_8_byte */ |
| 105 | 105 |
| 106 | 106 |
| 107 static void qq_encrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_prt) | 107 static void qq_encrypt(unsigned char *instr, int instrlen, unsigned char *key, |
| 108 { | 108 unsigned char *outstr, int *outstrlen_prt) |
| 109 unsigned char plain[8], // plain text buffer | 109 { |
| 110 plain_pre_8[8], // plain text buffer, previous 8 bytes | 110 unsigned char plain[8], /* plain text buffer */ |
| 111 *crypted, // crypted text | 111 plain_pre_8[8], /* plain text buffer, previous 8 bytes */ |
| 112 *crypted_pre_8, // crypted test, previous 8 bytes | 112 *crypted, /* crypted text */ |
| 113 *inp; // current position in instr | 113 *crypted_pre_8, /* crypted test, previous 8 bytes */ |
| 114 int pos_in_byte = 1, // loop in the byte | 114 *inp; /* current position in instr */ |
| 115 is_header = 1, // header is one byte | 115 int pos_in_byte = 1, /* loop in the byte */ |
| 116 count = 0, // number of bytes being crypted | 116 is_header = 1, /* header is one byte */ |
| 117 padding = 0; // number of padding stuff | 117 count = 0, /* number of bytes being crypted */ |
| 118 | 118 padding = 0; /* number of padding stuff */ |
| 119 pos_in_byte = (instrlen + 0x0a) % 8; // header padding decided by instrlen | 119 |
| 120 pos_in_byte = (instrlen + 0x0a) % 8; /* header padding decided by instrlen */ | |
| 120 if (pos_in_byte) { | 121 if (pos_in_byte) { |
| 121 pos_in_byte = 8 - pos_in_byte; | 122 pos_in_byte = 8 - pos_in_byte; |
| 122 } | 123 } |
| 123 plain[0] = (rand() & 0xf8) | pos_in_byte; | 124 plain[0] = (rand() & 0xf8) | pos_in_byte; |
| 124 | 125 |
| 125 memset(plain + 1, rand() & 0xff, pos_in_byte++); | 126 memset(plain + 1, rand() & 0xff, pos_in_byte++); |
| 126 memset(plain_pre_8, 0x00, sizeof(plain_pre_8)); | 127 memset(plain_pre_8, 0x00, sizeof(plain_pre_8)); |
| 127 | 128 |
| 128 crypted = crypted_pre_8 = outstr; | 129 crypted = crypted_pre_8 = outstr; |
| 129 | 130 |
| 130 padding = 1; // pad some stuff in header | 131 padding = 1; /* pad some stuff in header */ |
| 131 while (padding <= 2) { // at most two bytes | 132 while (padding <= 2) { /* at most two bytes */ |
| 132 if (pos_in_byte < 8) { | 133 if (pos_in_byte < 8) { |
| 133 plain[pos_in_byte++] = rand() & 0xff; | 134 plain[pos_in_byte++] = rand() & 0xff; |
| 134 padding++; | 135 padding++; |
| 135 } | 136 } |
| 136 if (pos_in_byte == 8) { | 137 if (pos_in_byte == 8) { |
| 147 if (pos_in_byte == 8) { | 148 if (pos_in_byte == 8) { |
| 148 encrypt_every_8_byte(plain, plain_pre_8, &crypted, &crypted_pre_8, key, &count, &pos_in_byte, &is_header); | 149 encrypt_every_8_byte(plain, plain_pre_8, &crypted, &crypted_pre_8, key, &count, &pos_in_byte, &is_header); |
| 149 } | 150 } |
| 150 } | 151 } |
| 151 | 152 |
| 152 padding = 1; // pad some stuff in tail | 153 padding = 1; /* pad some stuff in tail */ |
| 153 while (padding <= 7) { // at most seven bytes | 154 while (padding <= 7) { /* at most seven bytes */ |
| 154 if (pos_in_byte < 8) { | 155 if (pos_in_byte < 8) { |
| 155 plain[pos_in_byte++] = 0x00; | 156 plain[pos_in_byte++] = 0x00; |
| 156 padding++; | 157 padding++; |
| 157 } | 158 } |
| 158 if (pos_in_byte == 8) { | 159 if (pos_in_byte == 8) { |
| 175 a = ntohl(k[0]), | 176 a = ntohl(k[0]), |
| 176 b = ntohl(k[1]), | 177 b = ntohl(k[1]), |
| 177 c = ntohl(k[2]), | 178 c = ntohl(k[2]), |
| 178 d = ntohl(k[3]), | 179 d = ntohl(k[3]), |
| 179 n = 0x10, | 180 n = 0x10, |
| 180 sum = 0xE3779B90, // why this ? must be related with n value | 181 sum = 0xE3779B90, /* why this ? must be related with n value */ |
| 181 delta = 0x9E3779B9; | 182 delta = 0x9E3779B9; |
| 182 | 183 |
| 183 /* sum = delta<<5, in general sum = delta * n */ | 184 /* sum = delta<<5, in general sum = delta * n */ |
| 184 while (n-- > 0) { | 185 while (n-- > 0) { |
| 185 z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); | 186 z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); |
| 206 *pos_in_byte = 0; | 207 *pos_in_byte = 0; |
| 207 | 208 |
| 208 return 1; | 209 return 1; |
| 209 } | 210 } |
| 210 | 211 |
| 211 // return 0 if failed, 1 otherwise | 212 /* return 0 if failed, 1 otherwise */ |
| 212 static int qq_decrypt(unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_ptr) | 213 static int qq_decrypt(unsigned char *instr, int instrlen, unsigned char *key, |
| 214 unsigned char *outstr, int *outstrlen_ptr) | |
| 213 { | 215 { |
| 214 unsigned char decrypted[8], m[8], *crypt_buff, *crypt_buff_pre_8, *outp; | 216 unsigned char decrypted[8], m[8], *crypt_buff, *crypt_buff_pre_8, *outp; |
| 215 int count, context_start, pos_in_byte, padding; | 217 int count, context_start, pos_in_byte, padding; |
| 216 | 218 |
| 217 // at least 16 bytes and %8 == 0 | 219 /* at least 16 bytes and %8 == 0 */ |
| 218 if ((instrlen % 8) || (instrlen < 16)) { | 220 if ((instrlen % 8) || (instrlen < 16)) { |
| 219 gaim_debug(GAIM_DEBUG_ERROR, "QQ", | 221 gaim_debug(GAIM_DEBUG_ERROR, "QQ", |
| 220 "Packet len is either too short or not a multiple of 8 bytes, read %d bytes\n", instrlen); | 222 "Packet len is either too short or not a multiple of 8 bytes, read %d bytes\n", instrlen); |
| 221 return 0; | 223 return 0; |
| 222 } | 224 } |
| 223 // get information from header | 225 /* get information from header */ |
| 224 qq_decipher((unsigned long *) instr, (unsigned long *) key, (unsigned long *) decrypted); | 226 qq_decipher((unsigned long *) instr, (unsigned long *) key, (unsigned long *) decrypted); |
| 225 pos_in_byte = decrypted[0] & 0x7; | 227 pos_in_byte = decrypted[0] & 0x7; |
| 226 count = instrlen - pos_in_byte - 10; // this is the plaintext length | 228 count = instrlen - pos_in_byte - 10; /* this is the plaintext length */ |
| 227 // return if outstr buffer is not large enough or error plaintext length | 229 /* return if outstr buffer is not large enough or error plaintext length */ |
| 228 if (*outstrlen_ptr < count || count < 0) { | 230 if (*outstrlen_ptr < count || count < 0) { |
| 229 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Buffer len %d is less than real len %d", *outstrlen_ptr, count); | 231 gaim_debug(GAIM_DEBUG_ERROR, "QQ", "Buffer len %d is less than real len %d", *outstrlen_ptr, count); |
| 230 return 0; | 232 return 0; |
| 231 } | 233 } |
| 232 | 234 |
| 233 memset(m, 0, 8); | 235 memset(m, 0, 8); |
| 234 crypt_buff_pre_8 = m; | 236 crypt_buff_pre_8 = m; |
| 235 *outstrlen_ptr = count; // everything is ok! set return string length | 237 *outstrlen_ptr = count; /* everything is ok! set return string length */ |
| 236 | 238 |
| 237 crypt_buff = instr + 8; // address of real data start | 239 crypt_buff = instr + 8; /* address of real data start */ |
| 238 context_start = 8; // context is at the second chunk of 8 bytes | 240 context_start = 8; /* context is at the second block of 8 bytes */ |
| 239 pos_in_byte++; // start of paddng stuff | 241 pos_in_byte++; /* start of paddng stuff */ |
| 240 | 242 |
| 241 padding = 1; // at least one in header | 243 padding = 1; /* at least one in header */ |
| 242 while (padding <= 2) { // there are 2 byte padding stuff in header | 244 while (padding <= 2) { /* there are 2 byte padding stuff in header */ |
| 243 if (pos_in_byte < 8) { // bypass the padding stuff, it's nonsense data | 245 if (pos_in_byte < 8) { /* bypass the padding stuff, it's nonsense data */ |
| 244 pos_in_byte++; | 246 pos_in_byte++; |
| 245 padding++; | 247 padding++; |
| 246 } | 248 } |
| 247 if (pos_in_byte == 8) { | 249 if (pos_in_byte == 8) { |
| 248 crypt_buff_pre_8 = instr; | 250 crypt_buff_pre_8 = instr; |
| 285 } | 287 } |
| 286 } | 288 } |
| 287 return 1; | 289 return 1; |
| 288 } | 290 } |
| 289 | 291 |
| 290 /*****************************************************************************/ | |
| 291 /* This is the Public Function */ | 292 /* This is the Public Function */ |
| 292 // return 1 is succeed, otherwise return 0 | 293 /* return 1 is succeed, otherwise return 0 */ |
| 293 int qq_crypt(unsigned char flag, | 294 int qq_crypt(unsigned char flag, |
| 294 unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_ptr) | 295 unsigned char *instr, int instrlen, unsigned char *key, unsigned char *outstr, int *outstrlen_ptr) |
| 295 { | 296 { |
| 296 if (flag == DECRYPT) | 297 if (flag == DECRYPT) |
| 297 return qq_decrypt(instr, instrlen, key, outstr, outstrlen_ptr); | 298 return qq_decrypt(instr, instrlen, key, outstr, outstrlen_ptr); |
| 298 else if (flag == ENCRYPT) | 299 else if (flag == ENCRYPT) |
| 299 qq_encrypt(instr, instrlen, key, outstr, outstrlen_ptr); | 300 qq_encrypt(instr, instrlen, key, outstr, outstrlen_ptr); |
| 300 | 301 else |
| 301 return 1; // flag must be DECRYPT or ENCRYPT | 302 return 0; |
| 302 } | 303 |
| 303 | 304 return 1; |
| 304 /*****************************************************************************/ | 305 } |
| 305 // END OF FILE |
