diff options
Diffstat (limited to 'src/msnp11chl.c')
-rw-r--r-- | src/msnp11chl.c | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/src/msnp11chl.c b/src/msnp11chl.c new file mode 100644 index 0000000..774de76 --- /dev/null +++ b/src/msnp11chl.c @@ -0,0 +1,175 @@ +/* + * msnp11.c + * + * New-style challenge + * + * (c) 2002-2005 Thomas White <taw27@srcf.ucam.org> + * Part of TuxMessenger - GTK+-based MSN Messenger client + * + * This package is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 dated June, 1991. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this package; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * + * Special Notice for the MSNP11 Challenge Module + * ---------------------------------------------- + * The author(s) of this software performed no + * reverse-engineering of any Microsoft software + * in order to create this module. Information + * on the MSNP11-style challenge can be freely + * found on the Web. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdint.h> +#include <openssl/md5.h> +#include <stdlib.h> +#include <stdio.h> +#include <glib.h> + +#include "msnp11chl.h" + +#undef MSNP11CHL_DEBUG + +uint32_t msnp11chl_tolittle(uint32_t val) { + return GINT32_TO_LE(val); +} + +char *msnp11chl_response(const char *challenge) { + + char *flobbadob; + unsigned char *md5; + uint64_t words_1[4]; + uint64_t words_1_orig[4]; + uint32_t *words_2; + int nw2; + int i; + uint64_t low = 0; + uint64_t high = 0; + uint64_t key; + uint64_t hash1; + uint64_t hash2; + char *response; + + md5 = malloc(MD5_DIGEST_LENGTH); /* =16 */ + flobbadob = malloc(strlen(challenge)+strlen(CLIENT_CODE)+1); + strcpy(flobbadob, challenge); + strcat(flobbadob, CLIENT_CODE); + MD5(flobbadob, strlen(flobbadob), md5); + free(flobbadob); + + /* Split into four-byte words. */ + words_1_orig[0] = msnp11chl_tolittle((uint32_t)*(uint32_t *)(md5)); + words_1_orig[1] = msnp11chl_tolittle((uint32_t)*(uint32_t *)(md5+4)); + words_1_orig[2] = msnp11chl_tolittle((uint32_t)*(uint32_t *)(md5+8)); + words_1_orig[3] = msnp11chl_tolittle((uint32_t)*(uint32_t *)(md5+12)); + free(md5); + + for (i=0; i<4; i++) { + words_1[i] = words_1_orig[i] & 0x7FFFFFFF; + } + +#ifdef MSNP11CHL_DEBUG + printf("words_1[0] = 0x%08lx\n", words_1[0]); + printf("words_1[1] = 0x%08lx\n", words_1[1]); + printf("words_1[2] = 0x%08lx\n", words_1[2]); + printf("words_1[3] = 0x%08lx\n", words_1[3]); +#endif /* MSNP11CHL_DEBUG */ + + flobbadob = malloc(strlen(challenge)+strlen(CLIENT_ID)+9); + strcpy(flobbadob, challenge); + strcat(flobbadob, CLIENT_ID); + while ( strlen(flobbadob) % 8 != 0 ) { + strcat(flobbadob, "0"); + } + + /* Split into four-byte words. */ + words_2 = malloc(strlen(flobbadob)); + memcpy(words_2, flobbadob, strlen(flobbadob)); /* Not including terminator. */ + nw2 = strlen(flobbadob)/4; /* = number of members in words_2[] */ + free(flobbadob); + for (i=0; i<nw2; i++) { + words_2[i] = GINT32_TO_LE(words_2[i]); +#ifdef MSNP11CHL_DEBUG + printf("words_2[%i] = 0x%08lx\n", i, words_2[i]); +#endif /* MSNP11CHL_DEBUG */ + } + + for (i = 0; i<nw2; i+=2) { + + uint64_t temp = words_2[i]; + temp = (0x0E79A9C1 * temp); + temp = temp % 0x7FFFFFFF; + temp += high; + temp = words_1[0] * temp + words_1[1]; + temp = temp % 0x7FFFFFFF; + +#ifdef MSNP11CHL_DEBUG + printf("1: temp = 0x%08lx", temp); + printf(" high = 0x%08lx", high); + printf(" low = 0x%08lx\n", low); +#endif /* MSNP11CHL_DEBUG */ + + high = words_2[i+1]; + high = (high + temp) % 0x7FFFFFFF; + high = words_1[2] * high + words_1[3]; + high = high % 0x7FFFFFFF; + + low = low + high + temp; + +#ifdef MSNP11CHL_DEBUG + printf("2: temp = 0x%08lx", temp); + printf(" high = 0x%08lx", high); + printf(" low = 0x%08lx\n", low); +#endif /* MSNP11CHL_DEBUG */ + + } + + free(words_2); + + high = (high + words_1[1]) % 0x7FFFFFFF; + low = (low + words_1[3]) % 0x7FFFFFFF; +#ifdef MSNP11CHL_DEBUG + printf("high = 0x%08lx", high); + printf(" low = 0x%08lx\n", low); +#endif /* MSNP11CHL_DEBUG */ + + /* "high" is a 32-bit integer in a 64-bit type, so swapping it automatically shifts it by 32 bits */ + key = (low<<32) + high; +#ifdef MSNP11CHL_DEBUG + printf("key = %llx\n", key); +#endif /* MSNP11CHL_DEBUG */ + + hash1 = words_1_orig[0] + (words_1_orig[1]<<32); + hash2 = words_1_orig[2] + (words_1_orig[3]<<32); +#ifdef MSNP11CHL_DEBUG + printf("hash1 = 0x%016llx, hash2 = 0x%016llx\n", hash1, hash2); +#endif /* MSNP11CHL_DEBUG */ + + response = malloc(33); + sprintf(response, "%.16llx%.16llx", GUINT64_SWAP_LE_BE(key^hash1), GUINT64_SWAP_LE_BE(key^hash2)); + + for ( i=0; i<strlen(response); i++ ) { + if ( response[i]==' ' ) { + response[i]='0'; + } + } + + return response; + +} |