|
在这个程序中,resp_6与resp_96的值是如何得来的?这是yahoo 即时通软件里的验证程序,其中name是用户名,pass是密码,SEED是一组随机的字符串,谢谢大家,
[code:1]
static void yahoo_process_auth_new(GaimConnection *gc, const char *seed)
{
struct yahoo_packet *pack = NULL;
GaimAccount *account = gaim_connection_get_account(gc);
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";
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];
const 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);
memset(&crypt_hash_xor2, 0, 64);
memset(&digest1, 0, 20);
memset(&digest2, 0, 20);
memset(&magic, 0, 64);
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_ptr = seed;
while (*magic_ptr != (int)NULL) {
char *loc;
/* Ignore parentheses.
*/
if (*magic_ptr == '(' || *magic_ptr == ')') {
magic_ptr++;
continue;
}
/* Characters and digits verify against the challenge lookup.
*/
if (isalpha(*magic_ptr) || isdigit(*magic_ptr)) {
loc = strchr(challenge_lookup, *magic_ptr);
if (!loc) {
/* SME XXX Error - disconnect here */
}
/* Get offset into lookup table and shl 3.
*/
magic_work = loc - challenge_lookup;
magic_work <<= 3;
magic_ptr++;
continue;
} else {
unsigned int local_store;
loc = strchr(operand_lookup, *magic_ptr);
if (!loc) {
/* SME XXX Disconnect */
}
local_store = loc - operand_lookup;
/* 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.
*/
for (magic_cnt = magic_len-2; magic_cnt >= 0; magic_cnt--) {
unsigned char byte1;
unsigned char byte2;
/* Bad. Abort.
*/
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);
magic_4 = magic_key_char[0] | (magic_key_char[1]<<8) | (magic_key_char[2]<<16) | (magic_key_char[3]<<24);
/*
* 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;
}
/* If y != 0, we need some help.
*/
if (y != 0) {
unsigned int updated_key;
/* Update magic stuff. Call it twice because Yahoo's encryption is super bad ass.
*/
updated_key = yahoo_auth_finalCountdown(magic_4, 0x60, y, x);
updated_key = yahoo_auth_finalCountdown(updated_key, 0x60, y, x);
magic_key_char[0] = updated_key & 0xff;
magic_key_char[1] = (updated_key >> 8) & 0xff;
magic_key_char[2] = (updated_key >> 16) & 0xff;
magic_key_char[3] = (updated_key >> 24) & 0xff;
}
/* Get password and crypt hashes as per usual.
*/
md5_init(&ctx);
md5_append(&ctx, pass, strlen(pass));
md5_finish(&ctx, result);
to_y64(password_hash, result, 16);
md5_init(&ctx);
crypt_result = yahoo_crypt(pass, "$1$_2S43d5f$");
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.
*/
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++)
pass_hash_xor2[cnt++] = password_hash[x] ^ 0x5c;
if (cnt < 64)
memset(&(pass_hash_xor2[cnt]), 0x5c, 64-cnt);
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.
*/
shaUpdate(&ctx1, pass_hash_xor1, 64);
if (y >= 3)
ctx1.sizeLo = 0x1ff;
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.
*/
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.
*/
for (x = 0; x < 20; x += 2) {
unsigned int val = 0;
unsigned int lookup = 0;
char byte[6];
memset(&byte, 0, 6);
/* 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))
break;
sprintf(byte, "%c", alphabet1[lookup]);
strcat(resp_6, byte);
strcat(resp_6, "=");
lookup = (val >> 0x06);
lookup &= 0x1f;
if (lookup >= strlen(alphabet2))
break;
sprintf(byte, "%c", alphabet2[lookup]);
strcat(resp_6, byte);
lookup = (val >> 0x01);
lookup &= 0x1f;
if (lookup >= strlen(alphabet2))
break;
sprintf(byte, "%c", alphabet2[lookup]);
strcat(resp_6, byte);
lookup = (val & 0x01);
if (lookup >= strlen(delimit_lookup))
break;
sprintf(byte, "%c", delimit_lookup[lookup]);
strcat(resp_6, byte);
}
/* Our second authentication response is based off of the crypto hash.
*/
cnt = 0;
memset(&digest1, 0, 20);
memset(&digest2, 0, 20);
for (x = 0; x < (int)strlen(crypt_hash); x++)
crypt_hash_xor1[cnt++] = crypt_hash[x] ^ 0x36;
if (cnt < 64)
memset(&(crypt_hash_xor1[cnt]), 0x36, 64-cnt);
cnt = 0;
for (x = 0; x < (int)strlen(crypt_hash); x++)
crypt_hash_xor2[cnt++] = crypt_hash[x] ^ 0x5c;
if (cnt < 64)
memset(&(crypt_hash_xor2[cnt]), 0x5c, 64-cnt);
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.
*/
shaUpdate(&ctx1, crypt_hash_xor1, 64);
if (y >= 3)
ctx1.sizeLo = 0x1ff;
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.
*/
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.
*/
for (x = 0; x < 20; x += 2) {
unsigned int val = 0;
unsigned int lookup = 0;
char byte[6];
memset(&byte, 0, 6);
/* 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))
break;
sprintf(byte, "%c", alphabet1[lookup]);
strcat(resp_96, byte);
strcat(resp_96, "=");
lookup = (val >> 0x06);
lookup &= 0x1f;
if (lookup >= strlen(alphabet2))
break;
sprintf(byte, "%c", alphabet2[lookup]);
strcat(resp_96, byte);
lookup = (val >> 0x01);
lookup &= 0x1f;
if (lookup >= strlen(alphabet2))
break;
sprintf(byte, "%c", alphabet2[lookup]);
strcat(resp_96, byte);
lookup = (val & 0x01);
if (lookup >= strlen(delimit_lookup))
break;
sprintf(byte, "%c", delimit_lookup[lookup]);
strcat(resp_96, byte);
}
pack = yahoo_packet_new(YAHOO_SERVICE_AUTHRESP, YAHOO_STATUS_AVAILABLE, 0);
yahoo_packet_hash(pack, 0, name);
yahoo_packet_hash(pack, 6, resp_6);
yahoo_packet_hash(pack, 96, resp_96);
yahoo_packet_hash(pack, 1, name);
yahoo_packet_hash(pack, 135, "6,0,0,1710");
if (yd->picture_checksum) {
char *cksum = g_strdup_printf("%d", yd->picture_checksum);
yahoo_packet_hash(pack, 192, cksum);
g_free(cksum);
}
yahoo_send_packet(yd, pack);
yahoo_packet_free(pack);
g_free(password_hash);
g_free(crypt_hash);
}[/code:1] |
|