/pidgin/main: 94a95ba03c78: Copy the encryption code from the 3....
Andrew Victor
andrew.victor at mxit.com
Tue Dec 18 10:51:13 EST 2012
Changeset: 94a95ba03c7839ab29f808b7f35d3ed59be0efc1
Author: Andrew Victor <andrew.victor at mxit.com>
Date: 2012-12-18 17:50 +0200
Branch: mxit-2.x.y
URL: http://hg.pidgin.im/pidgin/main/rev/94a95ba03c78
Description:
Copy the encryption code from the 3.0.0-dev tree.
diffstat:
libpurple/protocols/mxit/cipher.c | 201 +++++++++++++++++++++++++++++------
libpurple/protocols/mxit/cipher.h | 4 +-
libpurple/protocols/mxit/protocol.c | 31 ++++-
libpurple/protocols/mxit/protocol.h | 5 +-
4 files changed, 197 insertions(+), 44 deletions(-)
diffs (truncated from 372 to 300 lines):
diff --git a/libpurple/protocols/mxit/cipher.c b/libpurple/protocols/mxit/cipher.c
--- a/libpurple/protocols/mxit/cipher.c
+++ b/libpurple/protocols/mxit/cipher.c
@@ -1,7 +1,7 @@
/*
* MXit Protocol libPurple Plugin
*
- * -- user password encryption --
+ * -- encryption --
*
* Pieter Loubser <libpurple at mxit.com>
*
@@ -31,30 +31,70 @@
#include "aes.h"
-/* password encryption */
+/* encryption */
#define INITIAL_KEY "6170383452343567"
#define SECRET_HEADER "<mxit/>"
+#define ENCRYPT_HEADER "<mxitencrypted ver=\"5.2\"/>"
/*------------------------------------------------------------------------
- * Pad the secret data using ISO10126 Padding.
+ * Add ISO10126 Padding to the data.
*
- * @param secret The data to pad (caller must ensure buffer has enough space for padding)
- * @return The total number of 128-bit blocks used
+ * @param data The data to pad.
*/
-static int pad_secret_data( char* secret )
+static void padding_add( GString* data )
{
- int blocks = 0;
- int passlen;
- int padding;
+ unsigned int blocks = ( data->len / 16 ) + 1;
+ unsigned int padding = ( blocks * 16 ) - data->len;
- passlen = strlen( secret );
- blocks = ( passlen / 16 ) + 1;
- padding = ( blocks * 16 ) - passlen;
- secret[passlen] = 0x50;
- secret[(blocks * 16) - 1] = padding;
+ g_string_set_size( data, blocks * 16 );
+ data->str[data->len - 1] = padding;
+}
- return blocks;
+
+/*------------------------------------------------------------------------
+ * Remove ISO10126 Padding from the data.
+ *
+ * @param data The data from which to remove padding.
+ */
+static void padding_remove( GString* data )
+{
+ unsigned int padding;
+
+ if ( data->len == 0 )
+ return;
+
+ padding = data->str[data->len - 1];
+ g_string_truncate( data, data->len - padding );
+}
+
+
+/*------------------------------------------------------------------------
+ * Generate the Transport-Layer crypto key.
+ * (Note: this function is not-thread safe)
+ *
+ * @param session The MXit Session object
+ * @return The transport-layer crypto key.
+ */
+static char* transport_layer_key( struct MXitSession* session )
+{
+ static char key[16 + 1];
+ const char* password = purple_account_get_password( session->acc );
+ int passlen = strlen( password );
+
+ /* initialize with initial key */
+ g_strlcpy( key, INITIAL_KEY, sizeof( key ) );
+
+ /* client key (8 bytes) */
+ memcpy( key, session->clientkey, strlen( session->clientkey ) );
+
+ /* add last 8 characters of the PIN (no padding if less characters) */
+ if ( passlen <= 8 )
+ memcpy( key + 8, password, passlen );
+ else
+ memcpy( key + 8, password + ( passlen - 8 ), 8 );
+
+ return key;
}
@@ -67,42 +107,135 @@ static int pad_secret_data( char* secret
*/
char* mxit_encrypt_password( struct MXitSession* session )
{
- char key[64];
+ char key[16 + 1];
char exkey[512];
- char pass[64];
+ GString* pass = NULL;
char encrypted[64];
char* base64;
- int blocks;
- int size;
int i;
purple_debug_info( MXIT_PLUGIN_ID, "mxit_encrypt_password\n" );
memset( encrypted, 0x00, sizeof( encrypted ) );
- memset( exkey, 0x00, sizeof( exkey ) );
- memset( pass, 0x58, sizeof( pass ) );
- pass[sizeof( pass ) - 1] = '\0';
- /* build the custom AES encryption key */
+ /* build the AES encryption key */
g_strlcpy( key, INITIAL_KEY, sizeof( key ) );
memcpy( key, session->clientkey, strlen( session->clientkey ) );
ExpandKey( (unsigned char*) key, (unsigned char*) exkey );
- /* build the custom data to be encrypted */
- g_strlcpy( pass, SECRET_HEADER, sizeof( pass ) );
- strcat( pass, session->acc->password );
+ /* build the secret data to be encrypted: SECRET_HEADER + password */
+ pass = g_string_new( SECRET_HEADER );
+ g_string_append( pass, purple_account_get_password( session->acc) );
+ padding_add( pass ); /* add ISO10126 padding */
- /* pad the secret data */
- blocks = pad_secret_data( pass );
- size = blocks * 16;
-
- /* now encrypt the password. we encrypt each block separately (ECB mode) */
- for ( i = 0; i < size; i += 16 )
- Encrypt( (unsigned char*) pass + i, (unsigned char*) exkey, (unsigned char*) encrypted + i );
+ /* now encrypt the secret. we encrypt each block separately (ECB mode) */
+ for ( i = 0; i < pass->len; i += 16 )
+ Encrypt( (unsigned char*) pass->str + i, (unsigned char*) exkey, (unsigned char*) encrypted + i );
/* now base64 encode the encrypted password */
- base64 = purple_base64_encode( (unsigned char*) encrypted, size );
+ base64 = purple_base64_encode( (unsigned char*) encrypted, pass->len );
+
+ g_string_free( pass, TRUE );
return base64;
}
+
+/*------------------------------------------------------------------------
+ * Decrypt a message using transport-layer encryption.
+ *
+ * @param session The MXit session object
+ * @param message The encrypted message data (is base64-encoded).
+ * @return The decrypted message. Must be g_free'd when no longer needed.
+ */
+char* mxit_decrypt_message( struct MXitSession* session, char* message )
+{
+ guchar* raw_message;
+ gsize raw_len;
+ char exkey[512];
+ GString* decoded = NULL;
+ int i;
+
+ /* remove optional header: <mxitencrypted ver="5.2"/> */
+ if ( strncmp( message, ENCRYPT_HEADER, strlen( ENCRYPT_HEADER ) ) == 0 )
+ message += strlen( ENCRYPT_HEADER );
+
+ /* base64 decode the message */
+ raw_message = purple_base64_decode( message, &raw_len );
+
+ /* AES-encrypted data is always blocks of 16 bytes */
+ if ( ( raw_len == 0 ) || ( raw_len % 16 != 0 ) )
+ return NULL;
+
+ /* build the AES key */
+ ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey );
+
+ /* AES decrypt each block */
+ decoded = g_string_sized_new( raw_len );
+ for ( i = 0; i < raw_len; i += 16 ) {
+ char block[16];
+
+ Decrypt( (unsigned char*) raw_message + i, (unsigned char*) exkey, (unsigned char*) block );
+ g_string_append_len( decoded, block, 16 );
+ }
+ g_free( raw_message );
+
+ /* check that the decrypted message starts with header: <mxit/> */
+ if ( strncmp( decoded->str, SECRET_HEADER, strlen( SECRET_HEADER ) != 0 ) ) {
+ g_string_free( decoded, TRUE );
+ return NULL; /* message could not be decrypted */
+ }
+
+ /* remove ISO10126 padding */
+ padding_remove( decoded );
+
+ /* remove encryption header */
+ g_string_erase( decoded, 0, strlen( SECRET_HEADER ) );
+
+ return g_string_free( decoded, FALSE );
+}
+
+
+/*------------------------------------------------------------------------
+ * Encrypt a message using transport-layer encryption.
+ *
+ * @param session The MXit session object
+ * @param message The message data.
+ * @return The encrypted message. Must be g_free'd when no longer needed.
+ */
+char* mxit_encrypt_message( struct MXitSession* session, char* message )
+{
+ GString* raw_message = NULL;
+ char exkey[512];
+ GString* encoded = NULL;
+ gchar* base64;
+ int i;
+
+ purple_debug_info( MXIT_PLUGIN_ID, "encrypt message: '%s'\n", message );
+
+ /* append encryption header to message data */
+ raw_message = g_string_new( SECRET_HEADER );
+ g_string_append( raw_message, message );
+ padding_add( raw_message ); /* add ISO10126 padding */
+
+ /* build the AES key */
+ ExpandKey( (unsigned char*) transport_layer_key( session ), (unsigned char*) exkey );
+
+ /* AES encrypt each block */
+ encoded = g_string_sized_new( raw_message->len );
+ for ( i = 0; i < raw_message->len; i += 16 ) {
+ char block[16];
+
+ Encrypt( (unsigned char*) raw_message->str + i, (unsigned char*) exkey, (unsigned char*) block );
+ g_string_append_len( encoded, block, 16 );
+ }
+ g_string_free( raw_message, TRUE );
+
+ /* base64 encode the encrypted message */
+ base64 = purple_base64_encode( (unsigned char *) encoded->str, encoded->len );
+ g_string_free( encoded, TRUE );
+
+ purple_debug_info( MXIT_PLUGIN_ID, "encrypted message: '%s'\n", base64 );
+
+ return base64;
+}
diff --git a/libpurple/protocols/mxit/cipher.h b/libpurple/protocols/mxit/cipher.h
--- a/libpurple/protocols/mxit/cipher.h
+++ b/libpurple/protocols/mxit/cipher.h
@@ -1,7 +1,7 @@
/*
* MXit Protocol libPurple Plugin
*
- * -- user password encryption --
+ * -- encryption --
*
* Pieter Loubser <libpurple at mxit.com>
*
@@ -32,5 +32,7 @@ struct MXitSession;
char* mxit_encrypt_password( struct MXitSession* session );
+char* mxit_decrypt_message( struct MXitSession* session, char* message );
+char* mxit_encrypt_message( struct MXitSession* session, char* message );
#endif /* _MXIT_CIPHER_H_ */
diff --git a/libpurple/protocols/mxit/protocol.c b/libpurple/protocols/mxit/protocol.c
--- a/libpurple/protocols/mxit/protocol.c
+++ b/libpurple/protocols/mxit/protocol.c
@@ -1516,6 +1516,7 @@ static void mxit_parse_cmd_message( stru
{
struct RXMsgData* mx = NULL;
char* message = NULL;
+ char* sender = NULL;
int msglen = 0;
int msgflags = 0;
int msgtype = 0;
@@ -1529,10 +1530,11 @@ static void mxit_parse_cmd_message( stru
msglen = strlen( message );
/* strip off dummy domain */
- mxit_strip_domain( records[0]->fields[0]->data );
+ sender = records[0]->fields[0]->data;
+ mxit_strip_domain( sender );
#ifdef DEBUG_PROTOCOL
- purple_debug_info( MXIT_PLUGIN_ID, "Message received from '%s'\n", records[0]->fields[0]->data );
+ purple_debug_info( MXIT_PLUGIN_ID, "Message received from '%s'\n", sender );
#endif
/* decode message flags (if any) */
@@ -1540,33 +1542,42 @@ static void mxit_parse_cmd_message( stru
msgflags = atoi( records[0]->fields[4]->data );
msgtype = atoi( records[0]->fields[2]->data );
More information about the Commits
mailing list