/pidgin/main: 4074275c1007: MXit: Backport the password and tran...

Andrew Victor andrew.victor at mxit.com
Sat Jan 26 05:24:44 EST 2013


Changeset: 4074275c10071deee42228a8405be3ed0dfe2a80
Author:	 Andrew Victor <andrew.victor at mxit.com>
Date:	 2013-01-26 12:24 +0200
Branch:	 release-2.x.y
URL: http://hg.pidgin.im/pidgin/main/rev/4074275c1007

Description:

MXit: Backport the password and transport-layer encryption code from 3.0.0.

diffstat:

 libpurple/protocols/mxit/cipher.c   |  201 +++++++++++++++++++++++++++++------
 libpurple/protocols/mxit/cipher.h   |    4 +-
 libpurple/protocols/mxit/protocol.c |   33 ++++-
 libpurple/protocols/mxit/protocol.h |    5 +-
 4 files changed, 198 insertions(+), 45 deletions(-)

diffs (truncated from 381 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
@@ -458,7 +458,7 @@ static void mxit_queue_packet( struct MX
 	packet->headerlen = 0;
 
 	/* create generic packet header */
-	hlen = snprintf( header, sizeof( header ), "id=%s%c", session->acc->username, CP_REC_TERM );			/* client msisdn */
+	hlen = snprintf( header, sizeof( header ), "id=%s%c", purple_account_get_username( session->acc ), CP_REC_TERM );			/* client msisdn */
 
 	if ( session->http ) {
 		/* http connection only */
@@ -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 );
 



More information about the Commits mailing list