| 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 ); |