| 115 |
115 |
| 116 purple_debug_info( MXIT_PLUGIN_ID, "mxit_encrypt_password\n" ); |
116 purple_debug_info( MXIT_PLUGIN_ID, "mxit_encrypt_password\n" ); |
| 117 |
117 |
| 118 memset( encrypted, 0x00, sizeof( encrypted ) ); |
118 memset( encrypted, 0x00, sizeof( encrypted ) ); |
| 119 |
119 |
| 120 /* build the custom AES encryption key */ |
120 /* build the AES encryption key */ |
| 121 g_strlcpy( key, INITIAL_KEY, sizeof( key ) ); |
121 g_strlcpy( key, INITIAL_KEY, sizeof( key ) ); |
| 122 memcpy( key, session->clientkey, strlen( session->clientkey ) ); |
122 memcpy( key, session->clientkey, strlen( session->clientkey ) ); |
| 123 ExpandKey( (unsigned char*) key, (unsigned char*) exkey ); |
123 ExpandKey( (unsigned char*) key, (unsigned char*) exkey ); |
| 124 |
124 |
| 125 /* build the custom data to be encrypted */ |
125 /* build the secret data to be encrypted: SECRET_HEADER + password */ |
| 126 g_strlcpy( pass, SECRET_HEADER, sizeof( pass ) ); |
126 pass = g_string_new( SECRET_HEADER ); |
| 127 strcat( pass, session->acc->password ); |
127 g_string_append( pass, session->acc->password ); |
| 128 |
128 padding_add( pass ); /* add ISO10126 padding */ |
| 129 /* pad the secret data */ |
129 |
| 130 blocks = pad_secret_data( pass ); |
130 /* now encrypt the secret. we encrypt each block separately (ECB mode) */ |
| 131 size = blocks * 16; |
131 for ( i = 0; i < pass->len; i += 16 ) |
| 132 |
132 Encrypt( (unsigned char*) pass->str + i, (unsigned char*) exkey, (unsigned char*) encrypted + i ); |
| 133 /* now encrypt the password. we encrypt each block separately (ECB mode) */ |
|
| 134 for ( i = 0; i < size; i += 16 ) |
|
| 135 Encrypt( (unsigned char*) pass + i, (unsigned char*) exkey, (unsigned char*) encrypted + i ); |
|
| 136 |
133 |
| 137 /* now base64 encode the encrypted password */ |
134 /* now base64 encode the encrypted password */ |
| 138 base64 = purple_base64_encode( (unsigned char*) encrypted, pass->len ); |
135 base64 = purple_base64_encode( (unsigned char*) encrypted, pass->len ); |
| 139 |
136 |
| 140 g_string_free( pass, TRUE ); |
137 g_string_free( pass, TRUE ); |
| 142 return base64; |
139 return base64; |
| 143 } |
140 } |
| 144 |
141 |
| 145 |
142 |
| 146 /*------------------------------------------------------------------------ |
143 /*------------------------------------------------------------------------ |
| 147 * Decrypt a transport-layer encryptede message. |
144 * Decrypt a message using transport-layer encryption. |
| 148 * |
145 * |
| 149 * @param session The MXit session object |
146 * @param session The MXit session object |
| 150 * @param message The encrypted message data. |
147 * @param message The encrypted message data (is base64-encoded). |
| 151 * @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. |
| 152 */ |
149 */ |
| 153 char* mxit_decrypt_message( struct MXitSession* session, char* message ) |
150 char* mxit_decrypt_message( struct MXitSession* session, char* message ) |
| 154 { |
151 { |
| |
152 guchar* raw_message; |
| 155 gsize raw_len; |
153 gsize raw_len; |
| 156 guchar* raw_message; |
|
| 157 char key[64]; |
|
| 158 int pwdlen = strlen( session->acc->password ); |
|
| 159 char exkey[512]; |
154 char exkey[512]; |
| |
155 GString* decoded = NULL; |
| 160 int i; |
156 int i; |
| 161 GString* decoded = NULL; |
|
| 162 |
157 |
| 163 /* remove optional header: <mxitencrypted ver="5.2"/> */ |
158 /* remove optional header: <mxitencrypted ver="5.2"/> */ |
| 164 if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 ) |
159 if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 ) |
| 165 message += strlen( ENCRYPT_HEADER ); |
160 message += strlen( ENCRYPT_HEADER ); |
| 166 |
161 |
| 167 /* base64 decode the message */ |
162 /* base64 decode the message */ |
| 168 raw_message = purple_base64_decode( message, &raw_len ); |
163 raw_message = purple_base64_decode( message, &raw_len ); |
| 169 |
164 |
| 170 /* build the key - Client key, appended with last 8 characters of the PIN. (no padding) */ |
165 /* build the AES key */ |
| 171 memset( key, 0x00, sizeof( key ) ); |
166 ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey ); |
| 172 memcpy( key, session->clientkey, strlen( session->clientkey ) ); |
167 |
| 173 if ( pwdlen <= 8 ) |
168 /* AES decrypt each block */ |
| 174 strcat( key, session->acc->password ); |
|
| 175 else |
|
| 176 strncat( key, session->acc->password + ( pwdlen - 8 ), 8 ); |
|
| 177 ExpandKey( (unsigned char*) key, (unsigned char*) exkey ); |
|
| 178 |
|
| 179 /* decode each block */ |
|
| 180 decoded = g_string_sized_new( raw_len ); |
169 decoded = g_string_sized_new( raw_len ); |
| 181 for ( i = 0; i < raw_len; i += 16 ) { |
170 for ( i = 0; i < raw_len; i += 16 ) { |
| 182 char block[16]; |
171 char block[16]; |
| 183 |
172 |
| 184 Decrypt( (unsigned char*) raw_message + i, (unsigned char*) exkey, (unsigned char*) block ); |
173 Decrypt( (unsigned char*) raw_message + i, (unsigned char*) exkey, (unsigned char*) block ); |
| 185 g_string_append_len( decoded, block, 16 ); |
174 g_string_append_len( decoded, block, 16 ); |
| 186 } |
175 } |
| 187 |
|
| 188 g_free( raw_message ); |
176 g_free( raw_message ); |
| 189 |
|
| 190 purple_debug_info( MXIT_PLUGIN_ID, "decrypted: '%s'\n", decoded->str ); |
|
| 191 |
177 |
| 192 /* check that the decrypted message starts with header: <mxit/> */ |
178 /* check that the decrypted message starts with header: <mxit/> */ |
| 193 if ( strncmp( decoded->str, SECRET_HEADER, strlen( SECRET_HEADER ) != 0 ) ) { |
179 if ( strncmp( decoded->str, SECRET_HEADER, strlen( SECRET_HEADER ) != 0 ) ) { |
| 194 g_string_free( decoded, TRUE ); |
180 g_string_free( decoded, TRUE ); |
| 195 return NULL; /* message could not be decoded */ |
181 return NULL; /* message could not be decrypted */ |
| 196 } |
182 } |
| 197 g_string_erase( decoded, 0, strlen( SECRET_HEADER ) ); /* remove header */ |
|
| 198 |
183 |
| 199 /* remove ISO10126 padding */ |
184 /* remove ISO10126 padding */ |
| 200 // TODO |
185 padding_remove( decoded ); |
| |
186 |
| |
187 /* remove encryption header */ |
| |
188 g_string_erase( decoded, 0, strlen( SECRET_HEADER ) ); |
| 201 |
189 |
| 202 return g_string_free( decoded, FALSE ); |
190 return g_string_free( decoded, FALSE ); |
| 203 } |
191 } |
| |
192 |
| |
193 |
| |
194 /*------------------------------------------------------------------------ |
| |
195 * Encrypt a message using transport-layer encryption. |
| |
196 * |
| |
197 * @param session The MXit session object |
| |
198 * @param message The message data. |
| |
199 * @return The encrypted message. Must be g_free'd when no longer needed. |
| |
200 */ |
| |
201 char* mxit_encrypt_message( struct MXitSession* session, char* message ) |
| |
202 { |
| |
203 GString* raw_message = NULL; |
| |
204 char exkey[512]; |
| |
205 GString* encoded = NULL; |
| |
206 gchar* base64; |
| |
207 int i; |
| |
208 |
| |
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 */ |
| |
215 |
| |
216 /* build the AES key */ |
| |
217 ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey ); |
| |
218 |
| |
219 /* AES encrypt each block */ |
| |
220 encoded = g_string_sized_new( raw_message->len ); |
| |
221 for ( i = 0; i < raw_message->len; i += 16 ) { |
| |
222 char block[16]; |
| |
223 |
| |
224 Encrypt( (unsigned char*) raw_message->str + i, (unsigned char*) exkey, (unsigned char*) block ); |
| |
225 g_string_append_len( encoded, block, 16 ); |
| |
226 } |
| |
227 g_string_free( raw_message, TRUE ); |
| |
228 |
| |
229 /* base64 encode the encrypted message */ |
| |
230 base64 = purple_base64_encode( (unsigned char *) encoded->str, encoded->len ); |
| |
231 g_string_free( encoded, TRUE ); |
| |
232 |
| |
233 purple_debug_info( MXIT_PLUGIN_ID, "encrypted message: '%s'\n", base64 ); |
| |
234 |
| |
235 return base64; |
| |
236 } |