diff src/protocols/yahoo/yahoo.c @ 8349:f1ca7e06e8de

[gaim-migrate @ 9073] Thanks again, Trillian. committer: Tailor Script <tailor@pidgin.im>
author Sean Egan <seanegan@gmail.com>
date Fri, 27 Feb 2004 00:24:21 +0000
parents 217643616a74
children 1f56ea865926
line wrap: on
line diff
--- a/src/protocols/yahoo/yahoo.c	Thu Feb 26 17:54:40 2004 +0000
+++ b/src/protocols/yahoo/yahoo.c	Fri Feb 27 00:24:21 2004 +0000
@@ -38,6 +38,7 @@
 #include "sha.h"
 #include "yahoo.h"
 #include "yahoochat.h"
+#include "yahoo_auth.h"
 #include "yahoo_filexfer.h"
 #include "md5.h"
 
@@ -1105,44 +1106,49 @@
 	const char *name = gaim_normalize(account, gaim_account_get_username(account));
 	const char *pass = gaim_account_get_password(account);
 	struct yahoo_data *yd = gc->proto_data;
-
-	md5_byte_t         result[16];
-	md5_state_t        ctx;
 	
-	SHA_CTX            ctx1;
-	SHA_CTX            ctx2;
-
-	char *alphabet1 = "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
-	char *alphabet2 = "F0E1D2C3B4A59687abcdefghijklmnop";
+	md5_byte_t			result[16];
+	md5_state_t			ctx;
 	
-	char *challenge_lookup = "qzec2tb3um1olpar8whx4dfgijknsvy5";
-	char *operand_lookup = "+|&%/*^-";
-	char *delimit_lookup = ",;";
+	SHA_CTX				ctx1;
+	SHA_CTX				ctx2;
 	
-	char *password_hash = g_malloc0(25);
-	char *crypt_hash = g_malloc0(25);
-	char *crypt_result = NULL;
-	char pass_hash_xor1[64];
-	char pass_hash_xor2[64];
-	char crypt_hash_xor1[64];
-	char crypt_hash_xor2[64];
-	char resp_6[100];
-	char resp_96[100];
-
-	unsigned char digest1[20];
-	unsigned char digest2[20];
-	unsigned char magic_key_char[4];
-	const unsigned char *magic_ptr;
-
-	unsigned int  magic[64];
-	unsigned int  magic_work = 0;
-
-	char comparison_src[20]; 
-	int x;
-	int cnt = 0;
-	int magic_cnt = 0;
-	int magic_len;
-	
+	char				*alphabet1			= "FBZDWAGHrJTLMNOPpRSKUVEXYChImkwQ";
+	char				*alphabet2			= "F0E1D2C3B4A59687abcdefghijklmnop";
+
+	char				*challenge_lookup	= "qzec2tb3um1olpar8whx4dfgijknsvy5";
+	char				*operand_lookup		= "+|&%/*^-";
+	char				*delimit_lookup		= ",;";
+
+	char				*password_hash		= (char *)g_malloc(25);
+	char				*crypt_hash		= (char *)g_malloc(25);
+	char				*crypt_result		= NULL;
+
+	char				pass_hash_xor1[64];
+	char				pass_hash_xor2[64];
+	char				crypt_hash_xor1[64];
+	char				crypt_hash_xor2[64];
+	char				resp_6[100];
+	char				resp_96[100];
+
+	unsigned char		digest1[20];
+	unsigned char		digest2[20];
+	unsigned char		comparison_src[20]; 
+	unsigned char		magic_key_char[4];
+	unsigned char		*magic_ptr;
+
+	unsigned int		magic[64];
+	unsigned int		magic_work = 0;
+	unsigned int		magic_4 = 0;
+
+	int					x;
+	int					y;
+	int					cnt = 0;
+	int					magic_cnt = 0;
+	int					magic_len;
+
+	memset(password_hash, 0, 25);
+	memset(crypt_hash, 0, 25);
 	memset(&pass_hash_xor1, 0, 64);
 	memset(&pass_hash_xor2, 0, 64);
 	memset(&crypt_hash_xor1, 0, 64);
@@ -1153,37 +1159,37 @@
 	memset(&resp_6, 0, 100);
 	memset(&resp_96, 0, 100);
 	memset(&magic_key_char, 0, 4);
+	memset(&comparison_src, 0, 20);
 
 	/* 
-	 * Magic: Phase 1.  Generate what seems to be a 30 
-	 * byte value (could change if base64
-	 * ends up differently?  I don't remember and I'm 
-	 * tired, so use a 64 byte buffer.
+	 * Magic: Phase 1.  Generate what seems to be a 30 byte value (could change if base64
+	 * ends up differently?  I don't remember and I'm tired, so use a 64 byte buffer.
 	 */
-
+	
 	magic_ptr = seed;
 	
 	while (*magic_ptr != (int)NULL) {
-		char *loc;
+		char   *loc;
 		
-		/* Ignore parentheses.  */
+		/* Ignore parentheses.
+		 */
 		
 		if (*magic_ptr == '(' || *magic_ptr == ')') {
 			magic_ptr++;
 			continue;
 		}
 		
-		/* Characters and digits verify against 
-		   the challenge lookup.
-		*/
+		/* Characters and digits verify against the challenge lookup.
+		 */
 		
 		if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
 			loc = strchr(challenge_lookup, *magic_ptr);
 			if (!loc) {
-				/* This isn't good */
+			  /* SME XXX Error - disconnect here */
 			}
 			
-			/* Get offset into lookup table and lsh 3. */
+			/* Get offset into lookup table and shl 3.
+			 */
 			
 			magic_work = loc - challenge_lookup;
 			magic_work <<= 3;
@@ -1191,94 +1197,154 @@
 			magic_ptr++;
 			continue;
 		} else {
-			unsigned int local_store;
+			unsigned int	local_store;
 			
 			loc = strchr(operand_lookup, *magic_ptr);
 			if (!loc) {
-				/* Also not good. */
+				/* SME XXX Disconnect */
 			}
 			
 			local_store = loc - operand_lookup;
-					
-			/* Oops; how did this happen? */
+			
+			/* Oops; how did this happen?
+			 */
+			
 			if (magic_cnt >= 64) 
 				break;
-					
+			
 			magic[magic_cnt++] = magic_work | local_store;
 			magic_ptr++;
 			continue;
 		}
-	}
+			}
 	
 	magic_len = magic_cnt;
 	magic_cnt = 0;
 	
-	/* Magic: Phase 2.  Take generated magic value and 
-	 * sprinkle fairy dust on the values. */
-	
+	/* Magic: Phase 2.  Take generated magic value and sprinkle fairy dust on the values.
+	 */
+
 	for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
-		unsigned char byte1;
-		unsigned char byte2;
+		unsigned char	byte1;
+		unsigned char	byte2;
 		
 		/* Bad.  Abort.
 		 */
-		if ((magic_cnt + 1 > magic_len) || 
-		    (magic_cnt > magic_len))
+		
+		if ((magic_cnt + 1 > magic_len) || (magic_cnt > magic_len))
 			break;
 		
 		byte1 = magic[magic_cnt];
 		byte2 = magic[magic_cnt+1];
-
+		
 		byte1 *= 0xcd;
 		byte1 ^= byte2;
 		
 		magic[magic_cnt+1] = byte1;
+			}
+	
+	/* 
+	 * Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic
+	 * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key
+	 * plus 3 bytes.  The 3 bytes are found by looping, and they represent the offsets
+	 * into particular functions we'll later call to potentially alter the magic key.
+	 *
+	 * %-)
+	 */
+	
+	magic_cnt = 1;
+	x = 0;
+	
+	do {
+		unsigned int	bl = 0; 
+		unsigned int	cl = magic[magic_cnt++];
+		
+		if (magic_cnt >= magic_len)
+			break;
+		
+		if (cl > 0x7F) {
+			if (cl < 0xe0) 
+				bl = cl = (cl & 0x1f) << 6; 
+			else {
+				bl = magic[magic_cnt++]; 
+				cl = (cl & 0x0f) << 6; 
+				bl = ((bl & 0x3f) + cl) << 6; 
+			} 
+			
+			cl = magic[magic_cnt++]; 
+			bl = (cl & 0x3f) + bl; 
+		} else
+			bl = cl; 
+		
+		comparison_src[x++] = (bl & 0xff00) >> 8; 
+		comparison_src[x++] = bl & 0xff; 
+	} while (x < 20);
+	
+	/* First four bytes are magic key.
+	 */
+	
+	memcpy(&magic_key_char[0], comparison_src, 4);
+	memcpy(&magic_4, comparison_src, 4);
+	
+	/* 
+	 * Magic: Phase 4.  Determine what function to use later by getting outside/inside
+	 * loop values until we match our previous buffer.
+	 */
+	
+	for (x = 0; x < 65535; x++) {
+		int			leave = 0;
+
+		for (y = 0; y < 5; y++) {
+			md5_byte_t		result[16];
+			md5_state_t		ctx;
+			
+			unsigned char	test[3];
+			
+			memset(&result, 0, 16);
+			memset(&test, 0, 3);
+			
+			/* Calculate buffer.
+			 */
+
+			test[0] = x;
+			test[1] = x >> 8;
+			test[2] = y;
+			
+			md5_init(&ctx);
+			md5_append(&ctx, magic_key_char, 4);
+			md5_append(&ctx, test, 3);
+			md5_finish(&ctx, result);
+			
+			if (!memcmp(result, comparison_src+4, 16)) {
+				leave = 1;
+				break;
+			}
+		}
+		
+		if (leave == 1)
+			break;
 	}
 	
-	/* Magic: Phase 3.  This computes 20 bytes.  The first 4 bytes are used as our magic 
-	 * key (and may be changed later); the next 16 bytes are an MD5 sum of the magic key 
-	 * plus 3 bytes.  The 3 bytes are found by looping, and they represent the offsets 
-	 * into particular functions we'll later call to potentially alter the magic key. 
-	 * 
-	 * %-) 
-	 */ 
+	/* If y != 0, we need some help.
+	 */
 	
-	magic_cnt = 1; 
-	x = 0; 
-	
-	do { 
-		unsigned int     bl = 0;  
-		unsigned int     cl = magic[magic_cnt++]; 
+	if (y != 0) {
+		unsigned int	updated_key;
 		
-		if (magic_cnt >= magic_len) 
-			break; 
+		/* Update magic stuff.   Call it twice because Yahoo's encryption is super bad ass.
+		 */
 		
-		if (cl > 0x7F) { 
-			if (cl < 0xe0)  
-				bl = cl = (cl & 0x1f) << 6;  
-			else { 
-				bl = magic[magic_cnt++];  
-                              cl = (cl & 0x0f) << 6;  
-                              bl = ((bl & 0x3f) + cl) << 6;  
-			}  
-			
-			cl = magic[magic_cnt++];  
-			bl = (cl & 0x3f) + bl;  
-		} else 
-			bl = cl;  
+		updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x);
+		updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x);
 		
-		comparison_src[x++] = (bl & 0xff00) >> 8;  
-		comparison_src[x++] = bl & 0xff;  
-	} while (x < 20); 
+		memcpy(&magic_key_char[0], &updated_key, 4);
+	} 
 	
-	/* First four bytes are magic key. */
-	for (x = 0; x < 4; x++) 
-		magic_key_char[x] = comparison_src[x];
-
-
-	/* Get password and crypt hashes as per usual. */
+/* Get password and crypt hashes as per usual.
+	 */
+	
 	md5_init(&ctx);
-	md5_append(&ctx, pass,  strlen(pass));
+	md5_append(&ctx, pass, strlen(pass));
 	md5_finish(&ctx, result);
 	to_y64(password_hash, result, 16);
 	
@@ -1287,16 +1353,16 @@
 	md5_append(&ctx, crypt_result, strlen(crypt_result));
 	md5_finish(&ctx, result);
 	to_y64(crypt_hash, result, 16);
-	
-	/* Our first authentication response is based off 
-	 * of the password hash. */
+
+	/* Our first authentication response is based off of the password hash.
+	 */
 	
 	for (x = 0; x < (int)strlen(password_hash); x++) 
 		pass_hash_xor1[cnt++] = password_hash[x] ^ 0x36;
 	
 	if (cnt < 64) 
 		memset(&(pass_hash_xor1[cnt]), 0x36, 64-cnt);
-	
+
 	cnt = 0;
 	
 	for (x = 0; x < (int)strlen(password_hash); x++) 
@@ -1308,36 +1374,38 @@
 	shaInit(&ctx1);
 	shaInit(&ctx2);
 	
-	/* The first context gets the password hash XORed 
-	 * with 0x36 plus a magic value
-	 * which we previously extrapolated from our 
-	 * challenge. */
+	/* 
+	 * The first context gets the password hash XORed with 0x36 plus a magic value
+	 * which we previously extrapolated from our challenge.
+	 */
 	
 	shaUpdate(&ctx1, pass_hash_xor1, 64);
 	shaUpdate(&ctx1, magic_key_char, 4);
 	shaFinal(&ctx1, digest1);
 	
-	 /* The second context gets the password hash XORed 
-	  * with 0x5c plus the SHA-1 digest
-	  * of the first context. */
+	/* 
+	 * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest
+	 * of the first context.
+	 */
 	
 	shaUpdate(&ctx2, pass_hash_xor2, 64);
 	shaUpdate(&ctx2, digest1, 20);
 	shaFinal(&ctx2, digest2);
 	
-	/* Now that we have digest2, use it to fetch 
-	 * characters from an alphabet to construct
-	 * our first authentication response. */
-	
+	/* 
+	 * Now that we have digest2, use it to fetch characters from an alphabet to construct
+	 * our first authentication response.
+	 */
+
 	for (x = 0; x < 20; x += 2) {
-		unsigned int    val = 0;
-		unsigned int    lookup = 0;
-		char            byte[6];
+		unsigned int	val = 0;
+		unsigned int	lookup = 0;
 		
+		char			byte[6];
+				
 		memset(&byte, 0, 6);
-		
-		/* First two bytes of digest stuffed 
-		 *  together.
+
+		/* First two bytes of digest stuffed together.
 		 */
 		
 		val = digest2[x];
@@ -1351,7 +1419,7 @@
 		sprintf(byte, "%c", alphabet1[lookup]);
 		strcat(resp_6, byte);
 		strcat(resp_6, "=");
-		
+
 		lookup = (val >> 0x06);
 		lookup &= 0x1f;
 		if (lookup >= strlen(alphabet2))
@@ -1365,7 +1433,7 @@
 			break;
 		sprintf(byte, "%c", alphabet2[lookup]);
 		strcat(resp_6, byte);
-		
+
 		lookup = (val & 0x01);
 		if (lookup >= strlen(delimit_lookup))
 			break;
@@ -1373,8 +1441,8 @@
 		strcat(resp_6, byte);
 	}
 	
-	/* Our second authentication response is based off 
-	 * of the crypto hash. */
+	/* Our second authentication response is based off of the crypto hash.
+	 */
 	
 	cnt = 0;
 	memset(&digest1, 0, 20);
@@ -1385,7 +1453,7 @@
 	
 	if (cnt < 64) 
 		memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
-	
+
 	cnt = 0;
 	
 	for (x = 0; x < (int)strlen(crypt_hash); x++) 
@@ -1397,42 +1465,44 @@
 	shaInit(&ctx1);
 	shaInit(&ctx2);
 	
-	/* The first context gets the password hash XORed 
-	 * with 0x36 plus a magic value
-	 * which we previously extrapolated from our 
-	 * challenge. */
+	/* 
+	 * The first context gets the password hash XORed with 0x36 plus a magic value
+	 * which we previously extrapolated from our challenge.
+	 */
 	
 	shaUpdate(&ctx1, crypt_hash_xor1, 64);
 	shaUpdate(&ctx1, magic_key_char, 4);
 	shaFinal(&ctx1, digest1);
 	
-	/* The second context gets the password hash XORed 
-	 * with 0x5c plus the SHA-1 digest
-	 * of the first context. */
+	/* 
+	 * The second context gets the password hash XORed with 0x5c plus the SHA-1 digest
+	 * of the first context.
+	 */
 	
 	shaUpdate(&ctx2, crypt_hash_xor2, 64);
 	shaUpdate(&ctx2, digest1, 20);
 	shaFinal(&ctx2, digest2);
 	
-	/* Now that we have digest2, use it to fetch 
-	 * characters from an alphabet to construct
-	 * our first authentication response.  */
+	/* 
+	 * Now that we have digest2, use it to fetch characters from an alphabet to construct
+	 * our first authentication response.
+	 */
 	
 	for (x = 0; x < 20; x += 2) {
-		unsigned int val = 0;
-		unsigned int lookup = 0;
+		unsigned int	val = 0;
+		unsigned int	lookup = 0;
 		
-		char byte[6];
+		char			byte[6];
 		
 		memset(&byte, 0, 6);
 		
-		/* First two bytes of digest stuffed 
-		 *  together. */
+		/* First two bytes of digest stuffed together.
+		 */
 		
 		val = digest2[x];
 		val <<= 8;
 		val += digest2[x+1];
-		
+
 		lookup = (val >> 0x0b);
 		lookup &= 0x1f;
 		if (lookup >= strlen(alphabet1))