Exemple #1
0
guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str,
                        GString *salt, guint iterations)
{
	PurpleHash *hasher;
	PurpleCipher *cipher;
	guchar *result;
	guint i;
	guchar *prev, *tmp;

	g_return_val_if_fail(hash != NULL, NULL);
	g_return_val_if_fail(str != NULL && str->len > 0, NULL);
	g_return_val_if_fail(salt != NULL && salt->len > 0, NULL);
	g_return_val_if_fail(iterations > 0, NULL);

	prev   = g_new0(guint8, hash->size);
	tmp    = g_new0(guint8, hash->size);
	result = g_new0(guint8, hash->size);

	hasher = hash->new_cipher();
	cipher = purple_hmac_cipher_new(hasher);
	g_object_unref(G_OBJECT(hasher));

	/* Append INT(1), a four-octet encoding of the integer 1, most significant
	 * octet first. */
	g_string_append_len(salt, "\0\0\0\1", 4);

	/* Compute U0 */
	purple_cipher_set_key(cipher, (guchar *)str->str, str->len);
	purple_cipher_append(cipher, (guchar *)salt->str, salt->len);
	purple_cipher_digest(cipher, result, hash->size);

	memcpy(prev, result, hash->size);

	/* Compute U1...Ui */
	for (i = 1; i < iterations; ++i) {
		guint j;
		purple_cipher_reset(cipher);
		purple_cipher_set_key(cipher, (guchar *)str->str, str->len);
		purple_cipher_append(cipher, prev, hash->size);
		purple_cipher_digest(cipher, tmp, hash->size);

		for (j = 0; j < hash->size; ++j)
			result[j] ^= tmp[j];

		memcpy(prev, tmp, hash->size);
	}

	g_object_unref(G_OBJECT(cipher));
	g_free(tmp);
	g_free(prev);
	return result;
}
Exemple #2
0
static void
purple_aes_cipher_set_property(GObject *obj, guint param_id,
								const GValue *value, GParamSpec *pspec)
{
	PurpleCipher *cipher = PURPLE_CIPHER(obj);

	switch(param_id) {
		case PROP_BATCH_MODE:
			purple_cipher_set_batch_mode(cipher,
										 g_value_get_enum(value));
			break;
		case PROP_IV:
			{
				guchar *iv = (guchar *)g_value_get_string(value);
				purple_cipher_set_iv(cipher, iv, strlen((gchar*)iv));
			}
			break;
		case PROP_KEY:
			purple_cipher_set_key(cipher, (guchar *)g_value_get_string(value),
				purple_aes_cipher_get_key_size(cipher));
			break;
		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID(obj, param_id, pspec);
			break;
	}
}
Exemple #3
0
/*
 * Helper functions for doing the SCRAM calculations. The first argument
 * is the hash algorithm.  All buffers must be of the appropriate size
 * according to the JabberScramHash.
 *
 * "str" is a NULL-terminated string for hmac().
 *
 * Needless to say, these are fragile.
 */
static void
hmac(const JabberScramHash *hash, guchar *out, const guchar *key, const gchar *str)
{
	PurpleHash *hasher;
	PurpleCipher *cipher;

	hasher = hash->new_cipher();
	cipher = purple_hmac_cipher_new(hasher);
	g_object_unref(G_OBJECT(hasher));
	purple_cipher_set_key(cipher, key, hash->size);
	purple_cipher_append(cipher, (guchar *)str, strlen(str));
	purple_cipher_digest(cipher, out, hash->size);
	g_object_unref(G_OBJECT(cipher));
}
Exemple #4
0
static void auth_old_cb(JabberStream *js, const char *from,
                        JabberIqType type, const char *id,
                        PurpleXmlNode *packet, gpointer data)
{
	JabberIq *iq;
	PurpleXmlNode *query, *x;
	const char *pw = purple_connection_get_password(js->gc);

	if (type == JABBER_IQ_ERROR) {
		PurpleConnectionError reason = PURPLE_CONNECTION_ERROR_NETWORK_ERROR;
		char *msg = jabber_parse_error(js, packet, &reason);
		purple_connection_error(js->gc, reason, msg);
		g_free(msg);
	} else if (type == JABBER_IQ_RESULT) {
		query = purple_xmlnode_get_child(packet, "query");
		if (js->stream_id && *js->stream_id &&
				purple_xmlnode_get_child(query, "digest")) {
			char *s, *hash;

			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
			query = purple_xmlnode_get_child(iq->node, "query");
			x = purple_xmlnode_new_child(query, "username");
			purple_xmlnode_insert_data(x, js->user->node, -1);
			x = purple_xmlnode_new_child(query, "resource");
			purple_xmlnode_insert_data(x, js->user->resource, -1);

			x = purple_xmlnode_new_child(query, "digest");
			s = g_strdup_printf("%s%s", js->stream_id, pw);
			hash = jabber_calculate_data_hash(s, strlen(s), "sha1");
			purple_xmlnode_insert_data(x, hash, -1);
			g_free(hash);
			g_free(s);
			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
			jabber_iq_send(iq);
		} else if ((x = purple_xmlnode_get_child(query, "crammd5"))) {
			/* For future reference, this appears to be a custom OS X extension
			 * to non-SASL authentication.
			 */
			const char *challenge;
			gchar digest[33];
			PurpleCipher *hmac;
			PurpleHash *md5;
			gssize diglen;

			/* Calculate the MHAC-MD5 digest */
			md5 = purple_md5_hash_new();
			hmac = purple_hmac_cipher_new(md5);
			challenge = purple_xmlnode_get_attrib(x, "challenge");
			purple_cipher_set_key(hmac, (guchar *)pw, strlen(pw));
			purple_cipher_append(hmac, (guchar *)challenge, strlen(challenge));
			diglen = purple_cipher_digest_to_str(hmac, digest, 33);
			g_object_unref(hmac);
			g_object_unref(md5);

			g_return_if_fail(diglen > 0);

			/* Create the response query */
			iq = jabber_iq_new_query(js, JABBER_IQ_SET, "jabber:iq:auth");
			query = purple_xmlnode_get_child(iq->node, "query");

			x = purple_xmlnode_new_child(query, "username");
			purple_xmlnode_insert_data(x, js->user->node, -1);
			x = purple_xmlnode_new_child(query, "resource");
			purple_xmlnode_insert_data(x, js->user->resource, -1);

			x = purple_xmlnode_new_child(query, "crammd5");

			purple_xmlnode_insert_data(x, digest, 32);

			jabber_iq_set_callback(iq, auth_old_result_cb, NULL);
			jabber_iq_send(iq);

		} else if(purple_xmlnode_get_child(query, "password")) {
			PurpleAccount *account = purple_connection_get_account(js->gc);
			if(!jabber_stream_is_ssl(js) && !purple_account_get_bool(account,
						"auth_plain_in_clear", FALSE)) {
				char *msg = g_strdup_printf(_("%s requires plaintext authentication over an unencrypted connection.  Allow this and continue authentication?"),
											purple_account_get_username(account));
				purple_request_yes_no(js->gc, _("Plaintext Authentication"),
						_("Plaintext Authentication"),
						msg,
						1,
						purple_request_cpar_from_account(account),
						account, allow_plaintext_auth,
						disallow_plaintext_auth);
				g_free(msg);
				return;
			}
			finish_plaintext_authentication(js);
		} else {
			purple_connection_error(js->gc,
				PURPLE_CONNECTION_ERROR_AUTHENTICATION_IMPOSSIBLE,
				_("Server does not use any supported authentication method"));
			return;
		}
	}
}
Exemple #5
0
static void
cipher_test_aes(void)
{
	PurpleCipher *cipher;
	int i = 0;
	gboolean fail = FALSE;

	purple_debug_info("cipher-test", "Running AES tests\n");

	cipher = purple_aes_cipher_new();
	if (cipher == NULL) {
		purple_debug_error("cipher-test", "AES cipher not found\n");
		fail = TRUE;
	}

	while (!fail && aes_tests[i].cipher) {
		aes_test *test = &aes_tests[i];
		gsize key_size;
		guchar *key;
		guchar cipher_s[1024], decipher_s[1024];
		ssize_t cipher_len, decipher_len;
		gchar *cipher_b16, *deciphered;

		purple_debug_info("cipher-test", "Test %02d:\n", i);
		purple_debug_info("cipher-test", "\tTesting '%s' (%" G_GSIZE_FORMAT "bit) \n",
			test->plaintext ? test->plaintext : "(null)",
			strlen(test->key) * 8 / 2);

		i++;

		purple_cipher_reset(cipher);

		if (test->iv) {
			gsize iv_size;
			guchar *iv = purple_base16_decode(test->iv, &iv_size);
			g_assert(iv != NULL);
			purple_cipher_set_iv(cipher, iv, iv_size);
			g_free(iv);
		}

		key = purple_base16_decode(test->key, &key_size);
		g_assert(key != NULL);
		purple_cipher_set_key(cipher, key, key_size);
		g_free(key);

		if (purple_cipher_get_key_size(cipher) != key_size) {
			purple_debug_info("cipher-test", "\tinvalid key size\n");
			fail = TRUE;
			continue;
		}

		cipher_len = purple_cipher_encrypt(cipher,
			(const guchar*)(test->plaintext ? test->plaintext : ""),
			test->plaintext ? (strlen(test->plaintext) + 1) : 0,
			cipher_s, sizeof(cipher_s));
		if (cipher_len < 0) {
			purple_debug_info("cipher-test", "\tencryption failed\n");
			fail = TRUE;
			continue;
		}

		cipher_b16 = purple_base16_encode(cipher_s, cipher_len);

		purple_debug_info("cipher-test", "\tGot:          %s\n", cipher_b16);
		purple_debug_info("cipher-test", "\tWanted:       %s\n", test->cipher);

		if (g_strcmp0(cipher_b16, test->cipher) != 0) {
			purple_debug_info("cipher-test",
				"\tencrypted data doesn't match\n");
			g_free(cipher_b16);
			fail = TRUE;
			continue;
		}
		g_free(cipher_b16);

		decipher_len = purple_cipher_decrypt(cipher,
			cipher_s, cipher_len, decipher_s, sizeof(decipher_s));
		if (decipher_len < 0) {
			purple_debug_info("cipher-test", "\tdecryption failed\n");
			fail = TRUE;
			continue;
		}

		deciphered = (decipher_len > 0) ? (gchar*)decipher_s : NULL;

		if (g_strcmp0(deciphered, test->plaintext) != 0) {
			purple_debug_info("cipher-test",
				"\tdecrypted data doesn't match\n");
			fail = TRUE;
			continue;
		}

		purple_debug_info("cipher-test", "\tTest OK\n");
	}

	if (cipher != NULL)
		g_object_unref(cipher);

	if (fail)
		purple_debug_info("cipher-test", "AES tests FAILED\n\n");
	else
		purple_debug_info("cipher-test", "AES tests completed successfully\n\n");
}
Exemple #6
0
static void
cipher_test_pbkdf2(void)
{
	PurpleCipher *cipher;
	PurpleHash *hash;
	int i = 0;
	gboolean fail = FALSE;

	purple_debug_info("cipher-test", "Running PBKDF2 tests\n");

	while (!fail && pbkdf2_tests[i].answer) {
		pbkdf2_test *test = &pbkdf2_tests[i];
		gchar digest[2 * 32 + 1 + 10];
		gchar *digest_nss = NULL;
		gboolean ret, skip_nss = FALSE;

		i++;

		purple_debug_info("cipher-test", "Test %02d:\n", i);
		purple_debug_info("cipher-test",
			"\tTesting '%s' with salt:'%s' hash:%s iter_count:%d \n",
			test->passphrase, test->salt, test->hash,
			test->iter_count);

		if (!strcmp(test->hash, "sha1"))
			hash = purple_sha1_hash_new();
		else if (!strcmp(test->hash, "sha256"))
			hash = purple_sha256_hash_new();
		else
			hash = NULL;

		cipher = purple_pbkdf2_cipher_new(hash);

		g_object_set(G_OBJECT(cipher), "iter_count", GUINT_TO_POINTER(test->iter_count), NULL);
		g_object_set(G_OBJECT(cipher), "out_len", GUINT_TO_POINTER(test->out_len), NULL);
		purple_cipher_set_salt(cipher, (const guchar*)test->salt, test->salt ? strlen(test->salt): 0);
		purple_cipher_set_key(cipher, (const guchar*)test->passphrase, strlen(test->passphrase));

		ret = purple_cipher_digest_to_str(cipher, digest, sizeof(digest));
		purple_cipher_reset(cipher);

		if (!ret) {
			purple_debug_info("cipher-test", "\tfailed\n");
			fail = TRUE;
			g_object_unref(cipher);
			g_object_unref(hash);
			continue;
		}

		if (g_strcmp0(test->hash, "sha1") != 0)
			skip_nss = TRUE;
		if (test->out_len != 16 && test->out_len != 32)
			skip_nss = TRUE;

#ifdef HAVE_NSS
		if (!skip_nss) {
			digest_nss = cipher_pbkdf2_nss_sha1(test->passphrase,
				test->salt, test->iter_count, test->out_len);
		}
#else
		skip_nss = TRUE;
#endif

		purple_debug_info("cipher-test", "\tGot:          %s\n", digest);
		if (digest_nss)
			purple_debug_info("cipher-test", "\tGot from NSS: %s\n", digest_nss);
		purple_debug_info("cipher-test", "\tWanted:       %s\n", test->answer);

		if (g_strcmp0(digest, test->answer) == 0 &&
			(skip_nss || g_strcmp0(digest, digest_nss) == 0)) {
			purple_debug_info("cipher-test", "\tTest OK\n");
		}
		else {
			purple_debug_info("cipher-test", "\twrong answer\n");
			fail = TRUE;
		}

		g_object_unref(cipher);
		g_object_unref(hash);
	}

	if (fail)
		purple_debug_info("cipher-test", "PBKDF2 tests FAILED\n\n");
	else
		purple_debug_info("cipher-test", "PBKDF2 tests completed successfully\n\n");
}