예제 #1
0
파일: nexus.c 프로젝트: Lilitana/Pidgin
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;
}
예제 #2
0
파일: nexus.c 프로젝트: Lilitana/Pidgin
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);
}
예제 #3
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;
}
예제 #4
0
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;
}
예제 #5
0
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;
}