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