Mercurial > pidgin
comparison libpurple/protocols/qq/qq_crypt.c @ 23695:5f454b975a99
2008.08.10 - csyfek <csyfek(at)gmail.com>
* Commit to Pidgin
2008.08.06 - ccpaging <ecc_hy(at)hotmail.com>
* Rename names of variables, Group, to Room
* Functions of group_network merged into qq_network and qq_process
* Canceled managing glist of group packet, add sub_cmdd and room_id to transaction
* Fixed error of demo group:
If 'room list' and 'room infor' are not setup, response received from server will emits
'room_id = 0' packet.
2008.08.04 - ccpaging <ecc_hy(at)hotmail.com>
* Use new crypt/decrypt functions
* Rename crypt.c/h to qq_crypt.c/h
* Clean code of decrypt functions
* Fixed decryption failure
2008.08.04 - csyfek <csyfek(at)gmail.com>
* Update AUTHORS
author | SHiNE CsyFeK <csyfek@gmail.com> |
---|---|
date | Sun, 10 Aug 2008 04:32:14 +0000 |
parents | |
children | c18f78b2db6b |
comparison
equal
deleted
inserted
replaced
23690:107166bb2a64 | 23695:5f454b975a99 |
---|---|
1 /** | |
2 * @file qq_crypt.c | |
3 * | |
4 * purple | |
5 * | |
6 * Purple is the legal property of its developers, whose names are too numerous | |
7 * to list here. Please refer to the COPYRIGHT file distributed with this | |
8 * source distribution. | |
9 * | |
10 * This program is free software; you can redistribute it and/or modify | |
11 * it under the terms of the GNU General Public License as published by | |
12 * the Free Software Foundation; either version 2 of the License, or | |
13 * (at your option) any later version. | |
14 * | |
15 * This program is distributed in the hope that it will be useful, | |
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
18 * GNU General Public License for more details. | |
19 * | |
20 * You should have received a copy of the GNU General Public License | |
21 * along with this program; if not, write to the Free Software | |
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
23 * | |
24 * | |
25 * QQ encryption algorithm | |
26 * Convert from ASM code provided by PerlOICQ | |
27 * | |
28 * Puzzlebird, Nov-Dec 2002 | |
29 */ | |
30 | |
31 /* Notes: (QQ uses 16 rounds, and modified something...) | |
32 | |
33 IN : 64 bits of data in v[0] - v[1]. | |
34 OUT: 64 bits of data in w[0] - w[1]. | |
35 KEY: 128 bits of key in k[0] - k[3]. | |
36 | |
37 delta is chosen to be the real part of | |
38 the golden ratio: Sqrt(5/4) - 1/2 ~ 0.618034 multiplied by 2^32. | |
39 | |
40 0x61C88647 is what we can track on the ASM codes.!! | |
41 */ | |
42 | |
43 #include <string.h> | |
44 | |
45 #include "debug.h" | |
46 #include "qq_crypt.h" | |
47 | |
48 #if 0 | |
49 void show_binary(char *psztitle, const guint8 *const buffer, gint bytes) | |
50 { | |
51 printf("== %s %d ==\r\n", psztitle, bytes); | |
52 gint i, j, ch; | |
53 for (i = 0; i < bytes; i += 16) { | |
54 /* length label */ | |
55 printf("%07x: ", i); | |
56 | |
57 /* dump hex value */ | |
58 for (j = 0; j < 16; j++) { | |
59 if (j == 8) { | |
60 printf(" -"); | |
61 } | |
62 if ((i + j) < bytes) | |
63 printf(" %02x", buffer[i + j]); | |
64 else | |
65 printf(" "); | |
66 } | |
67 | |
68 printf(" "); | |
69 | |
70 | |
71 /* dump ascii value */ | |
72 for (j = 0; j < 16 && (i + j) < bytes; j++) { | |
73 ch = buffer[i + j] & 127; | |
74 if (ch < ' ' || ch == 127) | |
75 printf("."); | |
76 else | |
77 printf("%c", ch); | |
78 } | |
79 printf("\r\n"); | |
80 } | |
81 printf("========\r\n"); | |
82 } | |
83 #else | |
84 | |
85 #define show_binary(args... ) /* nothing */ | |
86 | |
87 #endif | |
88 | |
89 /******************************************************************** | |
90 * encryption | |
91 *******************************************************************/ | |
92 | |
93 /* Tiny Encryption Algorithm (TEA) */ | |
94 static inline void qq_encipher(guint32 *const v, const guint32 *const k, guint32 *const w) | |
95 { | |
96 register guint32 | |
97 y = g_ntohl(v[0]), | |
98 z = g_ntohl(v[1]), | |
99 a = g_ntohl(k[0]), | |
100 b = g_ntohl(k[1]), | |
101 c = g_ntohl(k[2]), | |
102 d = g_ntohl(k[3]), | |
103 n = 0x10, | |
104 sum = 0, | |
105 delta = 0x9E3779B9; /* 0x9E3779B9 - 0x100000000 = -0x61C88647 */ | |
106 | |
107 while (n-- > 0) { | |
108 sum += delta; | |
109 y += ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); | |
110 z += ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); | |
111 } | |
112 | |
113 w[0] = g_htonl(y); | |
114 w[1] = g_htonl(z); | |
115 } | |
116 | |
117 /* it can be the real random seed function */ | |
118 /* override with number, convenient for debug */ | |
119 #ifdef DEBUG | |
120 static gint crypt_rand(void) { | |
121 return 0xdead; | |
122 } | |
123 #else | |
124 #include <stdlib.h> | |
125 #define crypt_rand() rand() | |
126 #endif | |
127 | |
128 /* 64-bit blocks and some kind of feedback mode of operation */ | |
129 static inline void encrypt_out(guint8 *crypted, const gint crypted_len, const guint8 *key) | |
130 { | |
131 /* ships in encipher */ | |
132 guint32 plain32[2]; | |
133 guint32 p32_prev[2]; | |
134 guint32 key32[4]; | |
135 guint32 crypted32[2]; | |
136 guint32 c32_prev[2]; | |
137 | |
138 guint8 *crypted_ptr; | |
139 gint count64; | |
140 | |
141 /* prepare at first */ | |
142 crypted_ptr = crypted; | |
143 | |
144 memcpy(crypted32, crypted_ptr, sizeof(crypted32)); | |
145 c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; | |
146 | |
147 p32_prev[0] = 0; p32_prev[1] = 0; | |
148 plain32[0] = crypted32[0] ^ p32_prev[0]; plain32[1] = crypted32[1] ^ p32_prev[1]; | |
149 | |
150 g_memmove(key32, key, 16); | |
151 count64 = crypted_len / 8; | |
152 while (count64-- > 0){ | |
153 /* encrypt it */ | |
154 qq_encipher(plain32, key32, crypted32); | |
155 | |
156 crypted32[0] ^= p32_prev[0]; crypted32[1] ^= p32_prev[1]; | |
157 | |
158 /* store curr 64 bits crypted */ | |
159 g_memmove(crypted_ptr, crypted32, sizeof(crypted32)); | |
160 | |
161 /* set prev */ | |
162 p32_prev[0] = plain32[0]; p32_prev[1] = plain32[1]; | |
163 c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; | |
164 | |
165 /* set next 64 bits want to crypt*/ | |
166 crypted_ptr += 8; | |
167 memcpy(crypted32, crypted_ptr, sizeof(crypted32)); | |
168 plain32[0] = crypted32[0] ^ c32_prev[0]; plain32[1] = crypted32[1] ^ c32_prev[1]; | |
169 } | |
170 } | |
171 | |
172 /* length of crypted buffer must be plain_len + 16*/ | |
173 gint qq_encrypt(guint8* crypted, const guint8* const plain, const gint plain_len, const guint8* const key) | |
174 { | |
175 guint8 *crypted_ptr = crypted; /* current position of dest */ | |
176 gint pos, padding; | |
177 | |
178 padding = (plain_len + 10) % 8; | |
179 if (padding) { | |
180 padding = 8 - padding; | |
181 } | |
182 | |
183 pos = 0; | |
184 | |
185 /* set first byte as padding len */ | |
186 crypted_ptr[pos] = (rand() & 0xf8) | padding; | |
187 pos++; | |
188 | |
189 /* extra 2 bytes */ | |
190 padding += 2; | |
191 | |
192 /* faster a little | |
193 memset(crypted_ptr + pos, rand() & 0xff, padding); | |
194 pos += padding; | |
195 */ | |
196 | |
197 /* more random */ | |
198 while (padding--) { | |
199 crypted_ptr[pos++] = rand() & 0xff; | |
200 } | |
201 | |
202 g_memmove(crypted_ptr + pos, plain, plain_len); | |
203 pos += plain_len; | |
204 | |
205 /* header padding len + plain len must be multiple of 8 | |
206 * tail pading len is always 8 - (1st byte) | |
207 */ | |
208 memset(crypted_ptr + pos, 0x00, 7); | |
209 pos += 7; | |
210 | |
211 show_binary("After padding", crypted, pos); | |
212 | |
213 encrypt_out(crypted, pos, key); | |
214 | |
215 show_binary("Encrypted", crypted, pos); | |
216 return pos; | |
217 } | |
218 | |
219 /******************************************************************** | |
220 * decryption | |
221 ********************************************************************/ | |
222 | |
223 static inline void qq_decipher(guint32 *const v, const guint32 *const k, guint32 *const w) | |
224 { | |
225 register guint32 | |
226 y = g_ntohl(v[0]), | |
227 z = g_ntohl(v[1]), | |
228 a = g_ntohl(k[0]), | |
229 b = g_ntohl(k[1]), | |
230 c = g_ntohl(k[2]), | |
231 d = g_ntohl(k[3]), | |
232 n = 0x10, | |
233 sum = 0xE3779B90, /* why this ? must be related with n value */ | |
234 delta = 0x9E3779B9; | |
235 | |
236 /* sum = delta<<5, in general sum = delta * n */ | |
237 while (n-- > 0) { | |
238 z -= ((y << 4) + c) ^ (y + sum) ^ ((y >> 5) + d); | |
239 y -= ((z << 4) + a) ^ (z + sum) ^ ((z >> 5) + b); | |
240 sum -= delta; | |
241 } | |
242 | |
243 w[0] = g_htonl(y); | |
244 w[1] = g_htonl(z); | |
245 } | |
246 | |
247 static inline gint decrypt_out(guint8 *dest, gint crypted_len, const guint8* const key) | |
248 { | |
249 gint plain_len; | |
250 guint32 key32[4]; | |
251 guint32 crypted32[2]; | |
252 guint32 c32_prev[2]; | |
253 guint32 plain32[2]; | |
254 guint32 p32_prev[2]; | |
255 gint count64; | |
256 gint padding; | |
257 guint8 *crypted_ptr = dest; | |
258 | |
259 /* decrypt first 64 bit */ | |
260 memcpy(key32, key, sizeof(key32)); | |
261 memcpy(crypted32, crypted_ptr, sizeof(crypted32)); | |
262 c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; | |
263 | |
264 qq_decipher(crypted32, key32, p32_prev); | |
265 memcpy(crypted_ptr, p32_prev, sizeof(p32_prev)); | |
266 | |
267 /* check padding len */ | |
268 padding = 2 + (crypted_ptr[0] & 0x7); | |
269 if (padding < 2) { | |
270 padding += 8; | |
271 } | |
272 plain_len = crypted_len - 1 - padding - 7; | |
273 if( plain_len < 0 ) { | |
274 return -2; | |
275 } | |
276 | |
277 count64 = crypted_len / 8; | |
278 while (count64-- > 0){ | |
279 c32_prev[0] = crypted32[0]; c32_prev[1] = crypted32[1]; | |
280 crypted_ptr += 8; | |
281 | |
282 memcpy(crypted32, crypted_ptr, sizeof(crypted32)); | |
283 p32_prev[0] ^= crypted32[0]; p32_prev[1] ^= crypted32[1]; | |
284 | |
285 qq_decipher(p32_prev, key32, p32_prev); | |
286 | |
287 plain32[0] = p32_prev[0] ^ c32_prev[0]; plain32[1] = p32_prev[1] ^ c32_prev[1]; | |
288 memcpy(crypted_ptr, plain32, sizeof(plain32)); | |
289 } | |
290 | |
291 return plain_len; | |
292 } | |
293 | |
294 /* length of plain buffer must be equal to crypted_len */ | |
295 gint qq_decrypt(guint8 *plain, const guint8* const crypted, const gint crypted_len, const guint8* const key) | |
296 { | |
297 gint plain_len = 0; | |
298 gint hdr_padding; | |
299 gint pos; | |
300 | |
301 /* at least 16 bytes and %8 == 0 */ | |
302 if ((crypted_len % 8) || (crypted_len < 16)) { | |
303 return -1; | |
304 } | |
305 | |
306 memcpy(plain, crypted, crypted_len); | |
307 | |
308 plain_len = decrypt_out(plain, crypted_len, key); | |
309 if (plain_len < 0) { | |
310 return plain_len; /* invalid first 64 bits */ | |
311 } | |
312 | |
313 show_binary("Decrypted with padding", plain, crypted_len); | |
314 | |
315 /* check last 7 bytes is zero or not? */ | |
316 for (pos = crypted_len - 1; pos > crypted_len - 8; pos--) { | |
317 if (plain[pos] != 0) { | |
318 return -3; | |
319 } | |
320 } | |
321 if (plain_len == 0) { | |
322 return plain_len; | |
323 } | |
324 | |
325 hdr_padding = crypted_len - plain_len - 7; | |
326 g_memmove(plain, plain + hdr_padding, plain_len); | |
327 | |
328 return plain_len; | |
329 } | |
330 |