libpurple/protocols/mxit/cipher.c

branch
mxit
changeset 32177
b4729e4322f3
parent 32176
b9ede4a1435b
child 32180
766c92a94b04
equal deleted inserted replaced
32176:b9ede4a1435b 32177:b4729e4322f3
1 /* 1 /*
2 * MXit Protocol libPurple Plugin 2 * MXit Protocol libPurple Plugin
3 * 3 *
4 * -- user password encryption -- 4 * -- encryption --
5 * 5 *
6 * Pieter Loubser <libpurple@mxit.com> 6 * Pieter Loubser <libpurple@mxit.com>
7 * 7 *
8 * (C) Copyright 2009 MXit Lifestyle (Pty) Ltd. 8 * (C) Copyright 2009 MXit Lifestyle (Pty) Ltd.
9 * <http://www.mxitlifestyle.com> 9 * <http://www.mxitlifestyle.com>
29 #include "mxit.h" 29 #include "mxit.h"
30 #include "cipher.h" 30 #include "cipher.h"
31 #include "aes.h" 31 #include "aes.h"
32 32
33 33
34 /* password encryption */ 34 /* encryption */
35 #define INITIAL_KEY "6170383452343567" 35 #define INITIAL_KEY "6170383452343567"
36 #define SECRET_HEADER "<mxit/>" 36 #define SECRET_HEADER "<mxit/>"
37 #define ENCRYPT_HEADER "<mxitencrypted ver=\"5.2\"/>" 37 #define ENCRYPT_HEADER "<mxitencrypted ver=\"5.2\"/>"
38 38
39 39
40 /*------------------------------------------------------------------------ 40 /*------------------------------------------------------------------------
41 * Pad the secret data using ISO10126 Padding.
42 *
43 * @param secret The data to pad (caller must ensure buffer has enough space for padding)
44 * @return The total number of 128-bit blocks used
45 */
46 static int pad_secret_data( char* secret )
47 {
48 int blocks = 0;
49 int passlen;
50 int padding;
51
52 passlen = strlen( secret );
53 blocks = ( passlen / 16 ) + 1;
54 padding = ( blocks * 16 ) - passlen;
55 secret[passlen] = 0x50;
56 secret[(blocks * 16) - 1] = padding;
57
58 return blocks;
59 }
60
61
62 /*------------------------------------------------------------------------
63 * Add ISO10126 Padding to the data. 41 * Add ISO10126 Padding to the data.
64 * 42 *
65 * @param data The data to pad. 43 * @param data The data to pad.
66 */ 44 */
67 static void padding_add( GString* data ) 45 static void padding_add( GString* data )
99 * @return The transport-layer crypto key. 77 * @return The transport-layer crypto key.
100 */ 78 */
101 static char* transport_layer_key( struct MXitSession* session ) 79 static char* transport_layer_key( struct MXitSession* session )
102 { 80 {
103 static char key[16 + 1]; 81 static char key[16 + 1];
104 int pwdlen = strlen( session->acc->password ); 82 int passlen = strlen( session->acc->password );
105 83
106 /* initialize with initial key */ 84 /* initialize with initial key */
107 g_strlcpy( key, INITIAL_KEY, sizeof( key ) ); 85 g_strlcpy( key, INITIAL_KEY, sizeof( key ) );
108 86
109 /* client key (8 bytes) */ 87 /* client key (8 bytes) */
110 memcpy( key, session->clientkey, strlen( session->clientkey ) ); 88 memcpy( key, session->clientkey, strlen( session->clientkey ) );
111 89
112 /* add last 8 characters of the PIN (no padding if less characters) */ 90 /* add last 8 characters of the PIN (no padding if less characters) */
113 if ( pwdlen <= 8 ) 91 if ( passlen <= 8 )
114 memcpy( key + 8, session->acc->password, pwdlen ); 92 memcpy( key + 8, session->acc->password, passlen );
115 else 93 else
116 memcpy( key + 8, session->acc->password + ( pwdlen - 8 ), 8 ); 94 memcpy( key + 8, session->acc->password + ( passlen - 8 ), 8 );
117 95
118 return key; 96 return key;
119 } 97 }
120 98
121 99
126 * @param session The MXit session object 104 * @param session The MXit session object
127 * @return The encrypted & encoded password. Must be g_free'd when no longer needed. 105 * @return The encrypted & encoded password. Must be g_free'd when no longer needed.
128 */ 106 */
129 char* mxit_encrypt_password( struct MXitSession* session ) 107 char* mxit_encrypt_password( struct MXitSession* session )
130 { 108 {
131 char key[64]; 109 char key[16 + 1];
132 char exkey[512]; 110 char exkey[512];
133 char pass[64]; 111 GString* pass = NULL;
134 char encrypted[64]; 112 char encrypted[64];
135 char* base64; 113 char* base64;
136 int blocks;
137 int size;
138 int i; 114 int i;
139 115
140 purple_debug_info( MXIT_PLUGIN_ID, "mxit_encrypt_password\n" ); 116 purple_debug_info( MXIT_PLUGIN_ID, "mxit_encrypt_password\n" );
141 117
142 memset( encrypted, 0x00, sizeof( encrypted ) ); 118 memset( encrypted, 0x00, sizeof( encrypted ) );
143 memset( exkey, 0x00, sizeof( exkey ) ); 119
144 memset( pass, 0x58, sizeof( pass ) ); 120 /* build the AES encryption key */
145 pass[sizeof( pass ) - 1] = '\0';
146
147 /* build the custom AES encryption key */
148 g_strlcpy( key, INITIAL_KEY, sizeof( key ) ); 121 g_strlcpy( key, INITIAL_KEY, sizeof( key ) );
149 memcpy( key, session->clientkey, strlen( session->clientkey ) ); 122 memcpy( key, session->clientkey, strlen( session->clientkey ) );
150 ExpandKey( (unsigned char*) key, (unsigned char*) exkey ); 123 ExpandKey( (unsigned char*) key, (unsigned char*) exkey );
151 124
152 /* build the custom data to be encrypted */ 125 /* build the secret data to be encrypted: SECRET_HEADER + password */
153 g_strlcpy( pass, SECRET_HEADER, sizeof( pass ) ); 126 pass = g_string_new( SECRET_HEADER );
154 strcat( pass, session->acc->password ); 127 g_string_append( pass, session->acc->password );
155 128 padding_add( pass ); /* add ISO10126 padding */
156 /* pad the secret data */ 129
157 blocks = pad_secret_data( pass ); 130 /* now encrypt the secret. we encrypt each block separately (ECB mode) */
158 size = blocks * 16; 131 for ( i = 0; i < pass->len; i += 16 )
159 132 Encrypt( (unsigned char*) pass->str + i, (unsigned char*) exkey, (unsigned char*) encrypted + i );
160 /* now encrypt the password. we encrypt each block separately (ECB mode) */
161 for ( i = 0; i < size; i += 16 )
162 Encrypt( (unsigned char*) pass + i, (unsigned char*) exkey, (unsigned char*) encrypted + i );
163 133
164 /* now base64 encode the encrypted password */ 134 /* now base64 encode the encrypted password */
165 base64 = purple_base64_encode( (unsigned char*) encrypted, size ); 135 base64 = purple_base64_encode( (unsigned char*) encrypted, pass->len );
136
137 g_string_free( pass, TRUE );
166 138
167 return base64; 139 return base64;
168 } 140 }
169 141
170 142
175 * @param message The encrypted message data (is base64-encoded). 147 * @param message The encrypted message data (is base64-encoded).
176 * @return The decrypted message. Must be g_free'd when no longer needed. 148 * @return The decrypted message. Must be g_free'd when no longer needed.
177 */ 149 */
178 char* mxit_decrypt_message( struct MXitSession* session, char* message ) 150 char* mxit_decrypt_message( struct MXitSession* session, char* message )
179 { 151 {
152 guchar* raw_message;
180 gsize raw_len; 153 gsize raw_len;
181 guchar* raw_message;
182 char exkey[512]; 154 char exkey[512];
155 GString* decoded = NULL;
183 int i; 156 int i;
184 GString* decoded = NULL;
185 157
186 /* remove optional header: <mxitencrypted ver="5.2"/> */ 158 /* remove optional header: <mxitencrypted ver="5.2"/> */
187 if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 ) 159 if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 )
188 message += strlen( ENCRYPT_HEADER ); 160 message += strlen( ENCRYPT_HEADER );
189 161
226 * @param message The message data. 198 * @param message The message data.
227 * @return The encrypted message. Must be g_free'd when no longer needed. 199 * @return The encrypted message. Must be g_free'd when no longer needed.
228 */ 200 */
229 char* mxit_encrypt_message( struct MXitSession* session, char* message ) 201 char* mxit_encrypt_message( struct MXitSession* session, char* message )
230 { 202 {
203 GString* raw_message = NULL;
231 char exkey[512]; 204 char exkey[512];
232 int i;
233 GString* raw_message = NULL;
234 GString* encoded = NULL; 205 GString* encoded = NULL;
235 gchar* base64; 206 gchar* base64;
207 int i;
236 208
237 purple_debug_info( MXIT_PLUGIN_ID, "encrypt message: '%s'\n", message ); 209 purple_debug_info( MXIT_PLUGIN_ID, "encrypt message: '%s'\n", message );
210
211 /* append encryption header to message data */
212 raw_message = g_string_new( SECRET_HEADER );
213 g_string_append( raw_message, message );
214 padding_add( raw_message ); /* add ISO10126 padding */
238 215
239 /* build the AES key */ 216 /* build the AES key */
240 ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey ); 217 ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey );
241 218
242 /* append encryption header to message data */ 219 /* AES encrypt each block */
243 raw_message = g_string_sized_new( strlen( SECRET_HEADER ) + strlen( message ) );
244 g_string_append( raw_message, SECRET_HEADER );
245 g_string_append( raw_message, message );
246
247 /* add ISO10126 padding */
248 padding_add( raw_message );
249
250 /* encrypt each block */
251 encoded = g_string_sized_new( raw_message->len ); 220 encoded = g_string_sized_new( raw_message->len );
252 for ( i = 0; i < raw_message->len; i += 16 ) { 221 for ( i = 0; i < raw_message->len; i += 16 ) {
253 char block[16]; 222 char block[16];
254 223
255 Encrypt( (unsigned char*) raw_message->str + i, (unsigned char*) exkey, (unsigned char*) block ); 224 Encrypt( (unsigned char*) raw_message->str + i, (unsigned char*) exkey, (unsigned char*) block );

mercurial