libpurple/protocols/mxit/cipher.c

branch
mxit
changeset 32182
fdf3af8def04
parent 32180
766c92a94b04
child 32438
dc8991868906
equal deleted inserted replaced
32181:10e10c18173a 32182:fdf3af8def04
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 }

mercurial