static char * rps_create_key(const char *key, int key_len, const char *data, size_t data_len) { const guchar magic[] = "WS-SecureConversation"; const int magic_len = sizeof(magic) - 1; PurpleCipherContext *hmac; guchar hash1[20], hash2[20], hash3[20], hash4[20]; char *result; hmac = purple_cipher_context_new_by_name("hmac", NULL); purple_cipher_context_set_option(hmac, "hash", "sha1"); purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); purple_cipher_context_append(hmac, magic, magic_len); purple_cipher_context_append(hmac, (guchar *)data, data_len); purple_cipher_context_digest(hmac, sizeof(hash1), hash1, NULL); purple_cipher_context_reset(hmac, NULL); purple_cipher_context_set_option(hmac, "hash", "sha1"); purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); purple_cipher_context_append(hmac, hash1, 20); purple_cipher_context_append(hmac, magic, magic_len); purple_cipher_context_append(hmac, (guchar *)data, data_len); purple_cipher_context_digest(hmac, sizeof(hash2), hash2, NULL); purple_cipher_context_reset(hmac, NULL); purple_cipher_context_set_option(hmac, "hash", "sha1"); purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); purple_cipher_context_append(hmac, hash1, 20); purple_cipher_context_digest(hmac, sizeof(hash3), hash3, NULL); purple_cipher_context_reset(hmac, NULL); purple_cipher_context_set_option(hmac, "hash", "sha1"); purple_cipher_context_set_key_with_len(hmac, (guchar *)key, key_len); purple_cipher_context_append(hmac, hash3, sizeof(hash3)); purple_cipher_context_append(hmac, magic, magic_len); purple_cipher_context_append(hmac, (guchar *)data, data_len); purple_cipher_context_digest(hmac, sizeof(hash4), hash4, NULL); purple_cipher_context_destroy(hmac); result = g_malloc(24); memcpy(result, hash2, sizeof(hash2)); memcpy(result + sizeof(hash2), hash4, 4); return result; }
gboolean purple_cipher_context_digest_to_str(PurpleCipherContext *context, size_t in_len, gchar digest_s[], size_t *out_len) { /* 8k is a bit excessive, will tweak later. */ guchar digest[BUF_LEN * 4]; size_t n, dlen = 0; g_return_val_if_fail(context, FALSE); g_return_val_if_fail(digest_s, FALSE); if(!purple_cipher_context_digest(context, sizeof(digest), digest, &dlen)) return FALSE; /* in_len must be greater than dlen * 2 so we have room for the NUL. */ if(in_len <= dlen * 2) return FALSE; for(n = 0; n < dlen; n++) sprintf(digest_s + (n * 2), "%02x", digest[n]); digest_s[n * 2] = '\0'; if(out_len) *out_len = dlen * 2; return TRUE; }
static gchar *twitter_oauth_sign(const gchar * txt, const gchar * key) { PurpleCipher *cipher; PurpleCipherContext *ctx; static guchar output[20]; size_t output_size; cipher = purple_ciphers_find_cipher("hmac"); if (!cipher) { purple_debug_error(GENERIC_PROTOCOL_ID, "%s: Could not find cipher\n", G_STRFUNC); return NULL; } ctx = purple_cipher_context_new(cipher, NULL); if (!ctx) { purple_debug_error(GENERIC_PROTOCOL_ID, "%s: Could not create cipher context\n", G_STRFUNC); return NULL; } purple_cipher_context_set_option(ctx, "hash", "sha1"); purple_cipher_context_set_key(ctx, (guchar *) key); purple_cipher_context_append(ctx, (guchar *) txt, strlen(txt)); if (!purple_cipher_context_digest(ctx, 20, output, &output_size)) { purple_debug_error(GENERIC_PROTOCOL_ID, "%s: Could not sign text\n", G_STRFUNC); purple_cipher_context_destroy(ctx); return NULL; } purple_cipher_context_destroy(ctx); return purple_base64_encode(output, output_size); }
gboolean purple_cipher_digest_region(const gchar *name, const guchar *data, size_t data_len, size_t in_len, guchar digest[], size_t *out_len) { PurpleCipher *cipher; PurpleCipherContext *context; gboolean ret = FALSE; g_return_val_if_fail(name, FALSE); g_return_val_if_fail(data, FALSE); cipher = purple_ciphers_find_cipher(name); g_return_val_if_fail(cipher, FALSE); if(!cipher->ops->append || !cipher->ops->digest) { purple_debug_warning("cipher", "purple_cipher_region failed: " "the %s cipher does not support appending and or " "digesting.", cipher->name); return FALSE; } context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, data, data_len); ret = purple_cipher_context_digest(context, in_len, digest, out_len); purple_cipher_context_destroy(context); return ret; }
static int aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest) { PurpleCipher *cipher; PurpleCipherContext *context; guchar passdigest[16]; cipher = purple_ciphers_find_cipher("md5"); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, (const guchar *)password, password_len); purple_cipher_context_digest(context, 16, passdigest, NULL); purple_cipher_context_destroy(context); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, (const guchar *)key, strlen(key)); purple_cipher_context_append(context, passdigest, 16); purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING)); purple_cipher_context_digest(context, 16, digest, NULL); purple_cipher_context_destroy(context); return 0; }
/** * @return A null-terminated base64 encoded version of the HMAC * calculated using the given key and data. */ static gchar *hmac_sha256(const char *key, const char *message) { PurpleCipherContext *context; guchar digest[32]; context = purple_cipher_context_new_by_name("hmac", NULL); purple_cipher_context_set_option(context, "hash", "sha256"); purple_cipher_context_set_key(context, (guchar *)key); purple_cipher_context_append(context, (guchar *)message, strlen(message)); purple_cipher_context_digest(context, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context); return purple_base64_encode(digest, sizeof(digest)); }
static int aim_encode_password_md5(const char *password, size_t password_len, const char *key, guint8 *digest) { PurpleCipherContext *context; context = purple_cipher_context_new_by_name("md5", NULL); purple_cipher_context_append(context, (const guchar *)key, strlen(key)); purple_cipher_context_append(context, (const guchar *)password, password_len); purple_cipher_context_append(context, (const guchar *)AIM_MD5_STRING, strlen(AIM_MD5_STRING)); purple_cipher_context_digest(context, 16, digest, NULL); purple_cipher_context_destroy(context); return 0; }
static void msn_dc_calculate_nonce_hash(MsnDirectConnNonceType type, const guchar *nonce, gsize nonce_len, gchar nonce_hash[37]) { guchar digest[20]; if (type == DC_NONCE_SHA1) { PurpleCipher *cipher = purple_ciphers_find_cipher("sha1"); PurpleCipherContext *context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, nonce, nonce_len); purple_cipher_context_digest(context, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context); } else if (type == DC_NONCE_PLAIN) { memcpy(digest, nonce, nonce_len); } else { nonce_hash[0] = '\0'; g_return_if_reached(); } g_sprintf(nonce_hash, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", digest[3], digest[2], digest[1], digest[0], digest[5], digest[4], digest[7], digest[6], digest[8], digest[9], digest[10], digest[11], digest[12], digest[13], digest[14], digest[15] ); }
char *crypt_pass(char *password) { unsigned char pass[16]; char *out; size_t len; PurpleCipher *md5; PurpleCipherContext *context; md5 = purple_ciphers_find_cipher ("md5"); context = purple_cipher_context_new (md5, NULL); purple_cipher_context_append (context, (const guchar *)password, strlen (password)); purple_cipher_context_digest (context, strlen (password), pass, &len); purple_cipher_context_destroy (context); out = g_strdup_printf("%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", pass[0],pass[1],pass[2],pass[3],pass[4],pass[5],pass[6],pass[7],pass[8], pass[9],pass[10],pass[11],pass[12],pass[13],pass[14],pass[15]); return (out); }
static void chl_cmd(MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnTransaction *trans; gchar buf[32]; #if 0 PurpleCipher *cipher; PurpleCipherContext *context; guchar digest[16]; const char *challenge_resp; int i; cipher = purple_ciphers_find_cipher("md5"); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, (const guchar *)cmd->params[1], strlen(cmd->params[1])); challenge_resp = "VT6PX?UQTM4WM%YR"; purple_cipher_context_append(context, (const guchar *)challenge_resp, strlen(challenge_resp)); purple_cipher_context_digest(context, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context); for (i = 0; i < 16; i++) g_snprintf(buf + (i*2), 3, "%02x", digest[i]); #else pecan_handle_challenge (cmd->params[1], "PROD0101{0RM?UBW", buf); #endif /* trans = msn_transaction_new(cmdproc, "QRY", "%s 32", "PROD0038W!61ZTF9"); */ trans = msn_transaction_new (cmdproc, "QRY", "%s 32", "PROD0101{0RM?UBW"); msn_transaction_set_payload (trans, buf, 32); msn_cmdproc_send_trans (cmdproc, trans); }
MsnObject * msn_object_new_from_image (PecanBuffer *image, const char *location, const char *creator, MsnObjectType type) { MsnObject *msnobj; PurpleCipherContext *ctx; char *buf; char *base64; unsigned char digest[20]; msnobj = NULL; if (!image) return msnobj; /* New object */ msnobj = msn_object_new (); msn_object_set_local (msnobj); msn_object_set_type (msnobj, type); msn_object_set_location (msnobj, location); msn_object_set_creator (msnobj, creator); msn_object_set_image (msnobj, image); /* Compute the SHA1D field. */ memset (digest, 0, sizeof (digest)); ctx = purple_cipher_context_new_by_name ("sha1", NULL); purple_cipher_context_append (ctx, (const gpointer) image->data, image->len); purple_cipher_context_digest (ctx, sizeof (digest), digest, NULL); base64 = purple_base64_encode (digest, sizeof (digest)); msn_object_set_sha1d (msnobj, base64); g_free (base64); msn_object_set_size (msnobj, image->len); /* Compute the SHA1C field. */ buf = g_strdup_printf ("Creator%sSize%dType%dLocation%sFriendly%sSHA1D%s", msn_object_get_creator (msnobj), msn_object_get_size (msnobj), msn_object_get_type (msnobj), msn_object_get_location (msnobj), msn_object_get_friendly (msnobj), msn_object_get_sha1d (msnobj)); memset (digest, 0, sizeof (digest)); purple_cipher_context_reset (ctx, NULL); purple_cipher_context_append (ctx, (const guchar *) buf, strlen (buf)); purple_cipher_context_digest (ctx, sizeof (digest), digest, NULL); purple_cipher_context_destroy (ctx); g_free (buf); base64 = purple_base64_encode (digest, sizeof (digest)); msn_object_set_sha1c (msnobj, base64); g_free (base64); return msnobj; }
gchar *fetion_cipher_digest_calculate_response( const gchar *sid, const gchar *domain, const gchar *password, const gchar *nonce, const gchar *cnonce) { PurpleCipher *cipher; PurpleCipherContext *context; gchar *hash1; /* We only support MD5. */ gchar *hash2; /* We only support MD5. */ gchar temp[33]; gchar *response; /* We only support MD5. */ guchar digest[16]; g_return_val_if_fail(sid != NULL, NULL); g_return_val_if_fail(domain != NULL, NULL); g_return_val_if_fail(password != NULL, NULL); g_return_val_if_fail(nonce != NULL, NULL); g_return_val_if_fail(cnonce != NULL, NULL); cipher = purple_ciphers_find_cipher("md5"); g_return_val_if_fail(cipher != NULL, NULL); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, (guchar *)sid, strlen(sid)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)domain, strlen(domain)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)password, strlen(password)); purple_cipher_context_digest(context, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, digest, 16); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)cnonce, strlen(cnonce)); purple_cipher_context_digest_to_str(context, sizeof(temp), temp, NULL); purple_cipher_context_destroy(context); hash1=g_ascii_strup(temp,32); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context,(guchar *)"REGISTER",8 ); purple_cipher_context_append(context,(guchar *)":",1 ); purple_cipher_context_append(context,(guchar *)sid, strlen(sid) ); purple_cipher_context_digest_to_str(context, sizeof(temp), temp, NULL); hash2=g_ascii_strup(temp,32); purple_cipher_context_destroy(context); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context,(guchar *)hash1,strlen(hash1) ); purple_cipher_context_append(context,(guchar *)":",1 ); purple_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); purple_cipher_context_append(context,(guchar *)":",1 ); purple_cipher_context_append(context,(guchar *)hash2,strlen(hash2) ); purple_cipher_context_digest_to_str(context, sizeof(temp), temp, NULL); purple_cipher_context_destroy(context); response=g_ascii_strup(temp,32); return g_strdup(response); }
static void url_cmd (MsnCmdProc *cmdproc, MsnCommand *cmd) { MsnSession *session; PurpleConnection *connection; const gchar *rru; const gchar *url; gchar creds[64]; glong tmp_timestamp; session = cmdproc->session; connection = purple_account_get_connection (session->account); rru = cmd->params[1]; url = cmd->params[2]; session->passport_info.mail_url_timestamp = time (NULL); tmp_timestamp = session->passport_info.mail_url_timestamp - session->passport_info.sl; { PurpleCipher *cipher; PurpleCipherContext *context; guchar digest[16]; gchar *buf; buf = pecan_strdup_printf ("%s%ld%s", session->passport_info.mspauth ? session->passport_info.mspauth : "BOGUS", tmp_timestamp, purple_connection_get_password (connection)); cipher = purple_ciphers_find_cipher ("md5"); context = purple_cipher_context_new (cipher, NULL); purple_cipher_context_append (context, (const guchar *) buf, strlen (buf)); purple_cipher_context_digest (context, sizeof (digest), digest, NULL); purple_cipher_context_destroy (context); g_free (buf); memset (creds, 0, sizeof (creds)); { gchar buf2[3]; gint i; for (i = 0; i < 16; i++) { g_snprintf (buf2, sizeof (buf2), "%02x", digest[i]); strcat (creds, buf2); } } } g_free (session->passport_info.mail_url); session->passport_info.mail_url = g_strdup_printf ("%s&auth=%s&creds=%s&sl=%ld&username=%s&mode=ttl&sid=%s&id=2&rru=%ssvc_mail&js=yes", url, session->passport_info.mspauth, creds, tmp_timestamp, msn_session_get_username (session), session->passport_info.sid, rru); /* The user wants to check his email */ if (cmd->trans && cmd->trans->data) { purple_notify_uri (connection, session->passport_info.mail_url); return; } if (purple_account_get_check_mail (session->account)) { static gboolean is_initial = TRUE; if (!is_initial) return; if (session->inbox_unread_count > 0) { const gchar *passport; const gchar *main_url; passport = msn_session_get_username (session); main_url = session->passport_info.mail_url; purple_notify_emails (connection, session->inbox_unread_count, FALSE, NULL, NULL, &passport, &main_url, NULL, NULL); } is_initial = FALSE; } }
gchar *purple_cipher_http_digest_calculate_session_key( const gchar *algorithm, const gchar *username, const gchar *realm, const gchar *password, const gchar *nonce, const gchar *client_nonce) { PurpleCipher *cipher; PurpleCipherContext *context; gchar hash[33]; /* We only support MD5. */ g_return_val_if_fail(username != NULL, NULL); g_return_val_if_fail(realm != NULL, NULL); g_return_val_if_fail(password != NULL, NULL); g_return_val_if_fail(nonce != NULL, NULL); /* Check for a supported algorithm. */ g_return_val_if_fail(algorithm == NULL || *algorithm == '\0' || g_ascii_strcasecmp(algorithm, "MD5") || g_ascii_strcasecmp(algorithm, "MD5-sess"), NULL); cipher = purple_ciphers_find_cipher("md5"); g_return_val_if_fail(cipher != NULL, NULL); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, (guchar *)username, strlen(username)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)realm, strlen(realm)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)password, strlen(password)); if (algorithm != NULL && !g_ascii_strcasecmp(algorithm, "MD5-sess")) { guchar digest[16]; if (client_nonce == NULL) { purple_cipher_context_destroy(context); purple_debug_error("cipher", "Required client_nonce missing for MD5-sess digest calculation.\n"); return NULL; } purple_cipher_context_digest(context, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, digest, sizeof(digest)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)nonce, strlen(nonce)); purple_cipher_context_append(context, (guchar *)":", 1); purple_cipher_context_append(context, (guchar *)client_nonce, strlen(client_nonce)); } purple_cipher_context_digest_to_str(context, sizeof(hash), hash, NULL); purple_cipher_context_destroy(context); return g_strdup(hash); }
void msn_nexus_update_token(MsnNexus *nexus, int id, GSourceFunc cb, gpointer data) { MsnSession *session = nexus->session; MsnNexusUpdateData *ud; MsnNexusUpdateCallback *update; PurpleCipherContext *sha1; PurpleCipherContext *hmac; char *key; guchar digest[20]; struct tm *tm; time_t now; char *now_str; char *timestamp; char *timestamp_b64; char *domain; char *domain_b64; char *signedinfo; gint32 nonce[6]; int i; char *nonce_b64; char *signature_b64; guchar signature[20]; char *request; MsnSoapMessage *soap; update = g_new0(MsnNexusUpdateCallback, 1); update->cb = cb; update->data = data; if (nexus->tokens[id].updates != NULL) { /* Update already in progress. Just add to list and return. */ purple_debug_info("msn", "Ticket update for user '%s' on domain '%s' in progress. Adding request to queue.\n", purple_account_get_username(session->account), ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); nexus->tokens[id].updates = g_slist_prepend(nexus->tokens[id].updates, update); return; } else { purple_debug_info("msn", "Updating ticket for user '%s' on domain '%s'\n", purple_account_get_username(session->account), ticket_domains[id][SSO_VALID_TICKET_DOMAIN]); nexus->tokens[id].updates = g_slist_prepend(nexus->tokens[id].updates, update); } ud = g_new0(MsnNexusUpdateData, 1); ud->nexus = nexus; ud->id = id; sha1 = purple_cipher_context_new_by_name("sha1", NULL); domain = g_strdup_printf(MSN_SSO_RST_TEMPLATE, id, ticket_domains[id][SSO_VALID_TICKET_DOMAIN], ticket_domains[id][SSO_VALID_TICKET_POLICY] != NULL ? ticket_domains[id][SSO_VALID_TICKET_POLICY] : nexus->policy); purple_cipher_context_append(sha1, (guchar *)domain, strlen(domain)); purple_cipher_context_digest(sha1, 20, digest, NULL); domain_b64 = purple_base64_encode(digest, 20); now = time(NULL); tm = gmtime(&now); now_str = g_strdup(purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm)); now += 5*60; tm = gmtime(&now); timestamp = g_strdup_printf(MSN_SSO_TIMESTAMP_TEMPLATE, now_str, purple_utf8_strftime("%Y-%m-%dT%H:%M:%SZ", tm)); purple_cipher_context_reset(sha1, NULL); purple_cipher_context_append(sha1, (guchar *)timestamp, strlen(timestamp)); purple_cipher_context_digest(sha1, 20, digest, NULL); timestamp_b64 = purple_base64_encode(digest, 20); g_free(now_str); purple_cipher_context_destroy(sha1); signedinfo = g_strdup_printf(MSN_SSO_SIGNEDINFO_TEMPLATE, id, domain_b64, timestamp_b64); for (i = 0; i < 6; i++) nonce[i] = rand(); nonce_b64 = purple_base64_encode((guchar *)&nonce, sizeof(nonce)); key = rps_create_key(nexus->secret, 24, (char *)nonce, sizeof(nonce)); hmac = purple_cipher_context_new_by_name("hmac", NULL); purple_cipher_context_set_option(hmac, "hash", "sha1"); purple_cipher_context_set_key_with_len(hmac, (guchar *)key, 24); purple_cipher_context_append(hmac, (guchar *)signedinfo, strlen(signedinfo)); purple_cipher_context_digest(hmac, 20, signature, NULL); purple_cipher_context_destroy(hmac); signature_b64 = purple_base64_encode(signature, 20); request = g_strdup_printf(MSN_SSO_TOKEN_UPDATE_TEMPLATE, nexus->cipher, nonce_b64, timestamp, signedinfo, signature_b64, domain); g_free(nonce_b64); g_free(domain_b64); g_free(timestamp_b64); g_free(timestamp); g_free(key); g_free(signature_b64); g_free(signedinfo); g_free(domain); soap = msn_soap_message_new(NULL, xmlnode_from_str(request, -1)); g_free(request); msn_soap_message_send(session, soap, MSN_SSO_SERVER, SSO_POST_URL, TRUE, nexus_got_update_cb, ud); }
static char * msn_rps_encrypt(MsnNexus *nexus) { char usr_key_base[MSN_USER_KEY_SIZE], *usr_key; const char magic1[] = "SESSION KEY HASH"; const char magic2[] = "SESSION KEY ENCRYPTION"; PurpleCipherContext *hmac; size_t len; guchar *hash; char *key1, *key2, *key3; gsize key1_len; const char *iv; char *nonce_fixed; char *cipher; char *response; usr_key = &usr_key_base[0]; /* Header */ msn_push32le(usr_key, 28); /* Header size */ msn_push32le(usr_key, CRYPT_MODE_CBC); /* Crypt mode */ msn_push32le(usr_key, CIPHER_TRIPLE_DES); /* Cipher type */ msn_push32le(usr_key, HASH_SHA1); /* Hash type */ msn_push32le(usr_key, 8); /* IV size */ msn_push32le(usr_key, 20); /* Hash size */ msn_push32le(usr_key, 72); /* Cipher size */ /* Data */ iv = usr_key; msn_push32le(usr_key, rand()); msn_push32le(usr_key, rand()); hash = (guchar *)usr_key; usr_key += 20; /* Remaining is cipher data */ key1 = (char *)purple_base64_decode((const char *)nexus->tokens[MSN_AUTH_MESSENGER].secret, &key1_len); key2 = rps_create_key(key1, key1_len, magic1, sizeof(magic1) - 1); key3 = rps_create_key(key1, key1_len, magic2, sizeof(magic2) - 1); len = strlen(nexus->nonce); hmac = purple_cipher_context_new_by_name("hmac", NULL); purple_cipher_context_set_option(hmac, "hash", "sha1"); purple_cipher_context_set_key_with_len(hmac, (guchar *)key2, 24); purple_cipher_context_append(hmac, (guchar *)nexus->nonce, len); purple_cipher_context_digest(hmac, 20, hash, NULL); purple_cipher_context_destroy(hmac); /* We need to pad this to 72 bytes, apparently */ nonce_fixed = g_malloc(len + 8); memcpy(nonce_fixed, nexus->nonce, len); memset(nonce_fixed + len, 0x08, 8); cipher = des3_cbc(key3, iv, nonce_fixed, len + 8, FALSE); g_free(nonce_fixed); memcpy(usr_key, cipher, 72); g_free(key1); g_free(key2); g_free(key3); g_free(cipher); response = purple_base64_encode((guchar *)usr_key_base, MSN_USER_KEY_SIZE); return response; }
void msn_handle_chl(char *input, char *output) { PurpleCipher *cipher; PurpleCipherContext *context; const guchar productKey[] = MSNP15_WLM_PRODUCT_KEY; const guchar productID[] = MSNP15_WLM_PRODUCT_ID; const char hexChars[] = "0123456789abcdef"; char buf[BUFSIZE]; unsigned char md5Hash[16]; unsigned char *newHash; unsigned int *md5Parts; unsigned int *chlStringParts; unsigned int newHashParts[5]; long long nHigh = 0, nLow = 0; int len; int i; /* Create the MD5 hash by using Purple MD5 algorithm */ cipher = purple_ciphers_find_cipher("md5"); context = purple_cipher_context_new(cipher, NULL); purple_cipher_context_append(context, (guchar *)input, strlen(input)); purple_cipher_context_append(context, productKey, sizeof(productKey) - 1); purple_cipher_context_digest(context, sizeof(md5Hash), md5Hash, NULL); purple_cipher_context_destroy(context); /* Split it into four integers */ md5Parts = (unsigned int *)md5Hash; for (i = 0; i < 4; i++) { /* adjust endianess */ md5Parts[i] = GUINT_TO_LE(md5Parts[i]); /* & each integer with 0x7FFFFFFF */ /* and save one unmodified array for later */ newHashParts[i] = md5Parts[i]; md5Parts[i] &= 0x7FFFFFFF; } /* make a new string and pad with '0' to length that's a multiple of 8 */ snprintf(buf, BUFSIZE - 5, "%s%s", input, productID); len = strlen(buf); if ((len % 8) != 0) { int fix = 8 - (len % 8); memset(&buf[len], '0', fix); buf[len + fix] = '\0'; len += fix; } /* split into integers */ chlStringParts = (unsigned int *)buf; /* this is magic */ for (i = 0; i < (len / 4); i += 2) { long long temp; chlStringParts[i] = GUINT_TO_LE(chlStringParts[i]); chlStringParts[i + 1] = GUINT_TO_LE(chlStringParts[i + 1]); temp = (0x0E79A9C1 * (long long)chlStringParts[i]) % 0x7FFFFFFF; temp = (md5Parts[0] * (temp + nLow) + md5Parts[1]) % 0x7FFFFFFF; nHigh += temp; temp = ((long long)chlStringParts[i + 1] + temp) % 0x7FFFFFFF; nLow = (md5Parts[2] * temp + md5Parts[3]) % 0x7FFFFFFF; nHigh += nLow; } nLow = (nLow + md5Parts[1]) % 0x7FFFFFFF; nHigh = (nHigh + md5Parts[3]) % 0x7FFFFFFF; newHashParts[0] ^= nLow; newHashParts[1] ^= nHigh; newHashParts[2] ^= nLow; newHashParts[3] ^= nHigh; /* adjust endianness */ for(i = 0; i < 4; i++) newHashParts[i] = GUINT_TO_LE(newHashParts[i]); /* make a string of the parts */ newHash = (unsigned char *)newHashParts; /* convert to hexadecimal */ for (i = 0; i < 16; i++) { output[i * 2] = hexChars[(newHash[i] >> 4) & 0xF]; output[(i * 2) + 1] = hexChars[newHash[i] & 0xF]; } output[32] = '\0'; }
static char * generate_response_value(JabberID *jid, const char *passwd, const char *nonce, const char *cnonce, const char *a2, const char *realm) { PurpleCipher *cipher; PurpleCipherContext *context; guchar result[16]; size_t a1len; gchar *a1, *convnode=NULL, *convpasswd = NULL, *ha1, *ha2, *kd, *x, *z; if((convnode = g_convert(jid->node, -1, "iso-8859-1", "utf-8", NULL, NULL, NULL)) == NULL) { convnode = g_strdup(jid->node); } if(passwd && ((convpasswd = g_convert(passwd, -1, "iso-8859-1", "utf-8", NULL, NULL, NULL)) == NULL)) { convpasswd = g_strdup(passwd); } cipher = purple_ciphers_find_cipher("md5"); context = purple_cipher_context_new(cipher, NULL); x = g_strdup_printf("%s:%s:%s", convnode, realm, convpasswd ? convpasswd : ""); purple_cipher_context_append(context, (const guchar *)x, strlen(x)); purple_cipher_context_digest(context, sizeof(result), result, NULL); a1 = g_strdup_printf("xxxxxxxxxxxxxxxx:%s:%s", nonce, cnonce); a1len = strlen(a1); g_memmove(a1, result, 16); purple_cipher_context_reset(context, NULL); purple_cipher_context_append(context, (const guchar *)a1, a1len); purple_cipher_context_digest(context, sizeof(result), result, NULL); ha1 = purple_base16_encode(result, 16); purple_cipher_context_reset(context, NULL); purple_cipher_context_append(context, (const guchar *)a2, strlen(a2)); purple_cipher_context_digest(context, sizeof(result), result, NULL); ha2 = purple_base16_encode(result, 16); kd = g_strdup_printf("%s:%s:00000001:%s:auth:%s", ha1, nonce, cnonce, ha2); purple_cipher_context_reset(context, NULL); purple_cipher_context_append(context, (const guchar *)kd, strlen(kd)); purple_cipher_context_digest(context, sizeof(result), result, NULL); purple_cipher_context_destroy(context); z = purple_base16_encode(result, 16); g_free(convnode); g_free(convpasswd); g_free(x); g_free(a1); g_free(ha1); g_free(ha2); g_free(kd); return z; }
char *yahoo_crypt(const char *key, const char *salt) { PurpleCipher *cipher; PurpleCipherContext *context1, *context2; guchar digest[16]; static char *buffer = NULL; static int buflen = 0; int needed = 3 + strlen (salt) + 1 + 26 + 1; size_t salt_len; size_t key_len; size_t cnt; char *cp; if (buflen < needed) { buflen = needed; if ((buffer = g_realloc(buffer, buflen)) == NULL) return NULL; } cipher = purple_ciphers_find_cipher("md5"); context1 = purple_cipher_context_new(cipher, NULL); context2 = purple_cipher_context_new(cipher, NULL); /* Find beginning of salt string. The prefix should normally always * be present. Just in case it is not. */ if (strncmp (md5_salt_prefix, salt, sizeof (md5_salt_prefix) - 1) == 0) /* Skip salt prefix. */ salt += sizeof (md5_salt_prefix) - 1; salt_len = MIN (strcspn (salt, "$"), 8); key_len = strlen (key); /* Add the key string. */ purple_cipher_context_append(context1, (const guchar *)key, key_len); /* Because the SALT argument need not always have the salt prefix we * add it separately. */ purple_cipher_context_append(context1, (const guchar *)md5_salt_prefix, sizeof(md5_salt_prefix) - 1); /* The last part is the salt string. This must be at most 8 * characters and it ends at the first `$' character (for * compatibility which existing solutions). */ purple_cipher_context_append(context1, (const guchar *)salt, salt_len); /* Compute alternate MD5 sum with input KEY, SALT, and KEY. The * final result will be added to the first context. */ /* Add key. */ purple_cipher_context_append(context2, (const guchar *)key, key_len); /* Add salt. */ purple_cipher_context_append(context2, (const guchar *)salt, salt_len); /* Add key again. */ purple_cipher_context_append(context2, (const guchar *)key, key_len); /* Now get result of this (16 bytes) and add it to the other context. */ purple_cipher_context_digest(context2, sizeof(digest), digest, NULL); /* Add for any character in the key one byte of the alternate sum. */ for (cnt = key_len; cnt > 16; cnt -= 16) purple_cipher_context_append(context1, digest, 16); purple_cipher_context_append(context1, digest, cnt); /* For the following code we need a NUL byte. */ digest[0] = '\0'; /* The original implementation now does something weird: for every 1 * bit in the key the first 0 is added to the buffer, for every 0 * bit the first character of the key. This does not seem to be * what was intended but we have to follow this to be compatible. */ for (cnt = key_len; cnt > 0; cnt >>= 1) purple_cipher_context_append(context1, (cnt & 1) != 0 ? digest : (guchar *)key, 1); /* Create intermediate result. */ purple_cipher_context_digest(context1, sizeof(digest), digest, NULL); /* Now comes another weirdness. In fear of password crackers here * comes a quite long loop which just processes the output of the * previous round again. We cannot ignore this here. */ for (cnt = 0; cnt < 1000; ++cnt) { /* New context. */ purple_cipher_context_reset(context2, NULL); /* Add key or last result. */ if ((cnt & 1) != 0) purple_cipher_context_append(context2, (const guchar *)key, key_len); else purple_cipher_context_append(context2, digest, 16); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) purple_cipher_context_append(context2, (const guchar *)salt, salt_len); /* Add key for numbers not divisible by 7. */ if (cnt % 7 != 0) purple_cipher_context_append(context2, (const guchar *)key, key_len); /* Add key or last result. */ if ((cnt & 1) != 0) purple_cipher_context_append(context2, digest, 16); else purple_cipher_context_append(context2, (const guchar *)key, key_len); /* Create intermediate result. */ purple_cipher_context_digest(context2, sizeof(digest), digest, NULL); } /* Now we can construct the result string. It consists of three parts. */ strncpy(buffer, md5_salt_prefix, MAX (0, buflen)); cp = buffer + strlen(buffer); buflen -= sizeof (md5_salt_prefix); strncpy(cp, salt, MIN ((size_t) buflen, salt_len)); cp = cp + strlen(cp); buflen -= MIN ((size_t) buflen, salt_len); if (buflen > 0) { *cp++ = '$'; --buflen; } #define b64_from_24bit(B2, B1, B0, N) \ do { \ unsigned int w = ((B2) << 16) | ((B1) << 8) | (B0); \ int n = (N); \ while (n-- > 0 && buflen > 0) { \ *cp++ = b64t[w & 0x3f]; \ --buflen; \ w >>= 6; \ }\ } while (0) b64_from_24bit (digest[0], digest[6], digest[12], 4); b64_from_24bit (digest[1], digest[7], digest[13], 4); b64_from_24bit (digest[2], digest[8], digest[14], 4); b64_from_24bit (digest[3], digest[9], digest[15], 4); b64_from_24bit (digest[4], digest[10], digest[5], 4); b64_from_24bit (0, 0, digest[11], 2); if (buflen <= 0) { g_free(buffer); buffer = NULL; } else *cp = '\0'; /* Terminate the string. */ /* Clear the buffer for the intermediate result so that people * attaching to processes or reading core dumps cannot get any * information. We do it in this way to clear correct_words[] * inside the MD5 implementation as well. */ purple_cipher_context_reset(context1, NULL); purple_cipher_context_digest(context1, sizeof(digest), digest, NULL); purple_cipher_context_destroy(context1); purple_cipher_context_destroy(context2); return buffer; }