libpurple/cipher.c

Thu, 01 Jun 2017 21:35:39 -0500

author
Mike Ruprecht <cmaiku@gmail.com>
date
Thu, 01 Jun 2017 21:35:39 -0500
changeset 38365
2ee19fb5fb0d
parent 36257
c5445f25f90f
permissions
-rw-r--r--

libpurple: Use default marshaller for GObject signals

Since 2.30 it's been possible to use a default c_marshaller by
passing NULL to g_signal_new(). It has since become the recommended
way of creating signals.
https://developer.gnome.org/gobject/stable/howto-signals.html

This patch ports libpurple to use this method instead of generating
its own marshallers with glib-genmarshal.

/* purple
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
 */
#include "internal.h"
#include "cipher.h"
#include "debug.h"

/******************************************************************************
 * PurpleCipher API
 *****************************************************************************/
GType
purple_cipher_get_type(void) {
	static GType type = 0;

	if(type == 0) {
		static const GTypeInfo info = {
			sizeof(PurpleCipherClass),
			NULL,
			NULL,
			NULL,
			NULL,
			NULL,
			sizeof(PurpleCipher),
			0,
			NULL,
			NULL
		};

		type = g_type_register_static(G_TYPE_OBJECT,
									  "PurpleCipher",
									  &info, G_TYPE_FLAG_ABSTRACT);
	}

	return type;
}

static const gchar *
purple_cipher_get_name(PurpleCipher *cipher)
{
	PurpleCipherClass *klass;
	const gchar *name;

	if (!PURPLE_IS_CIPHER(cipher))
		return "(error: not a cipher)";

	klass = PURPLE_CIPHER_GET_CLASS(cipher);
	if (!klass)
		return "(error: unknown cipher class)";

	name = g_type_name(G_TYPE_FROM_CLASS(klass));
	if (!name)
		return "(error: unknown cipher name)";

	return name;
}

static const gchar *
purple_hash_get_name(PurpleHash *hash)
{
	PurpleHashClass *klass;
	const gchar *name;

	if (!PURPLE_IS_HASH(hash))
		return "(error: not a hash)";

	klass = PURPLE_HASH_GET_CLASS(hash);
	if (!klass)
		return "(error: unknown hash class)";

	name = g_type_name(G_TYPE_FROM_CLASS(klass));
	if (!name)
		return "(error: unknown hash name)";

	return name;
}

void
purple_cipher_reset(PurpleCipher *cipher) {
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->reset)
		klass->reset(cipher);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the reset method",
			purple_cipher_get_name(cipher));
	}
}

void
purple_cipher_reset_state(PurpleCipher *cipher) {
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->reset_state)
		klass->reset_state(cipher);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the reset_state method",
			purple_cipher_get_name(cipher));
	}
}

void
purple_cipher_set_iv(PurpleCipher *cipher, guchar *iv, size_t len)
{
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));
	g_return_if_fail(iv);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->set_iv)
		klass->set_iv(cipher, iv, len);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the set_iv method",
			purple_cipher_get_name(cipher));
	}
}

void
purple_cipher_append(PurpleCipher *cipher, const guchar *data,
								size_t len)
{
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->append)
		klass->append(cipher, data, len);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the append method",
			purple_cipher_get_name(cipher));
	}
}

gboolean
purple_cipher_digest(PurpleCipher *cipher, guchar digest[], size_t len)
{
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->digest)
		return klass->digest(cipher, digest, len);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the digest method",
			purple_cipher_get_name(cipher));
	}

	return FALSE;
}

gboolean
purple_cipher_digest_to_str(PurpleCipher *cipher, gchar digest_s[], size_t len)
{
	/* 8k is a bit excessive, will tweak later. */
	guchar digest[BUF_LEN * 4];
	size_t digest_size, n;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);
	g_return_val_if_fail(digest_s, FALSE);

	digest_size = purple_cipher_get_digest_size(cipher);

	g_return_val_if_fail(digest_size <= BUF_LEN * 4, FALSE);

	if(!purple_cipher_digest(cipher, digest, sizeof(digest)))
		return FALSE;

	/* Every digest byte occupies 2 chars + the NUL at the end. */
	g_return_val_if_fail(digest_size * 2 + 1 <= len, FALSE);

	for(n = 0; n < digest_size; n++)
		sprintf(digest_s + (n * 2), "%02x", digest[n]);

	digest_s[n * 2] = '\0';

	return TRUE;
}

size_t
purple_cipher_get_digest_size(PurpleCipher *cipher)
{
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), FALSE);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->get_digest_size)
		return klass->get_digest_size(cipher);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the get_digest_size method",
			purple_cipher_get_name(cipher));
	}

	return FALSE;
}

ssize_t
purple_cipher_encrypt(PurpleCipher *cipher, const guchar input[],
							size_t in_len, guchar output[], size_t out_size)
{
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
	g_return_val_if_fail(input != NULL, -1);
	g_return_val_if_fail(output != NULL, -1);
	g_return_val_if_fail(out_size >= in_len, -1);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->encrypt)
		return klass->encrypt(cipher, input, in_len, output, out_size);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the encrypt method",
			purple_cipher_get_name(cipher));
	}

	return -1;
}

ssize_t
purple_cipher_decrypt(PurpleCipher *cipher, const guchar input[],
							size_t in_len, guchar output[], size_t out_size)
{
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);
	g_return_val_if_fail(input != NULL, -1);
	g_return_val_if_fail(output != NULL, -1);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->decrypt)
		return klass->decrypt(cipher, input, in_len, output, out_size);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the decrypt method",
			purple_cipher_get_name(cipher));
	}

	return -1;
}

void
purple_cipher_set_salt(PurpleCipher *cipher, const guchar *salt, size_t len) {
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->set_salt)
		klass->set_salt(cipher, salt, len);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the set_salt method",
			purple_cipher_get_name(cipher));
	}
}

void
purple_cipher_set_key(PurpleCipher *cipher, const guchar *key, size_t len) {
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->set_key)
		klass->set_key(cipher, key, len);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the set_key method",
			purple_cipher_get_name(cipher));
	}
}

size_t
purple_cipher_get_key_size(PurpleCipher *cipher) {
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->get_key_size)
		return klass->get_key_size(cipher);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the get_key_size method",
			purple_cipher_get_name(cipher));
	}

	return -1;
}

void
purple_cipher_set_batch_mode(PurpleCipher *cipher,
                                     PurpleCipherBatchMode mode)
{
	PurpleCipherClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_CIPHER(cipher));

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->set_batch_mode)
		klass->set_batch_mode(cipher, mode);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the set_batch_mode method",
			purple_cipher_get_name(cipher));
	}
}

PurpleCipherBatchMode
purple_cipher_get_batch_mode(PurpleCipher *cipher)
{
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->get_batch_mode)
		return klass->get_batch_mode(cipher);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the get_batch_mode method",
			purple_cipher_get_name(cipher));
	}

	return -1;
}

size_t
purple_cipher_get_block_size(PurpleCipher *cipher)
{
	PurpleCipherClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_CIPHER(cipher), -1);

	klass = PURPLE_CIPHER_GET_CLASS(cipher);

	if (klass && klass->get_block_size)
		return klass->get_block_size(cipher);
	else {
		purple_debug_warning("cipher", "the %s cipher does not "
			"implement the get_block_size method",
			purple_cipher_get_name(cipher));
	}

	return -1;
}

/******************************************************************************
 * PurpleHash API
 *****************************************************************************/
GType
purple_hash_get_type(void) {
	static GType type = 0;

	if(type == 0) {
		static const GTypeInfo info = {
			sizeof(PurpleHashClass),
			NULL,
			NULL,
			NULL,
			NULL,
			NULL,
			sizeof(PurpleHash),
			0,
			NULL,
			NULL
		};

		type = g_type_register_static(G_TYPE_OBJECT,
									  "PurpleHash",
									  &info, G_TYPE_FLAG_ABSTRACT);
	}

	return type;
}

void
purple_hash_reset(PurpleHash *hash) {
	PurpleHashClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_HASH(hash));

	klass = PURPLE_HASH_GET_CLASS(hash);

	if (klass && klass->reset)
		klass->reset(hash);
	else {
		purple_debug_warning("hash", "the %s hash does not implement "
			"the reset method", purple_hash_get_name(hash));
	}
}

void
purple_hash_reset_state(PurpleHash *hash) {
	PurpleHashClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_HASH(hash));

	klass = PURPLE_HASH_GET_CLASS(hash);

	if (klass && klass->reset_state)
		klass->reset_state(hash);
	else {
		purple_debug_warning("hash", "the %s hash does not implement "
			"the reset_state method", purple_hash_get_name(hash));
	}
}

void
purple_hash_append(PurpleHash *hash, const guchar *data,
								size_t len)
{
	PurpleHashClass *klass = NULL;

	g_return_if_fail(PURPLE_IS_HASH(hash));

	klass = PURPLE_HASH_GET_CLASS(hash);

	if (klass && klass->append)
		klass->append(hash, data, len);
	else {
		purple_debug_warning("hash", "the %s hash does not implement "
			"the append method", purple_hash_get_name(hash));
	}
}

gboolean
purple_hash_digest(PurpleHash *hash, guchar digest[], size_t len)
{
	PurpleHashClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);

	klass = PURPLE_HASH_GET_CLASS(hash);

	if (klass && klass->digest)
		return klass->digest(hash, digest, len);
	else {
		purple_debug_warning("hash", "the %s hash does not implement "
			"the digest method", purple_hash_get_name(hash));
	}

	return FALSE;
}

gboolean
purple_hash_digest_to_str(PurpleHash *hash, gchar digest_s[], size_t len)
{
	/* 8k is a bit excessive, will tweak later. */
	guchar digest[BUF_LEN * 4];
	size_t digest_size, n;

	g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);
	g_return_val_if_fail(digest_s, FALSE);

	digest_size = purple_hash_get_digest_size(hash);

	g_return_val_if_fail(digest_size <= BUF_LEN * 4, FALSE);

	if(!purple_hash_digest(hash, digest, sizeof(digest)))
		return FALSE;

	/* Every digest byte occupies 2 chars + the NUL at the end. */
	g_return_val_if_fail(digest_size * 2 + 1 <= len, FALSE);

	for(n = 0; n < digest_size; n++)
		sprintf(digest_s + (n * 2), "%02x", digest[n]);

	digest_s[n * 2] = '\0';

	return TRUE;
}

size_t
purple_hash_get_digest_size(PurpleHash *hash)
{
	PurpleHashClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_HASH(hash), FALSE);

	klass = PURPLE_HASH_GET_CLASS(hash);

	if (klass && klass->get_digest_size)
		return klass->get_digest_size(hash);
	else {
		purple_debug_warning("hash", "the %s hash does not implement "
			"the get_digest_size method", purple_hash_get_name(hash));
	}

	return FALSE;
}

size_t
purple_hash_get_block_size(PurpleHash *hash)
{
	PurpleHashClass *klass = NULL;

	g_return_val_if_fail(PURPLE_IS_HASH(hash), -1);

	klass = PURPLE_HASH_GET_CLASS(hash);

	if (klass && klass->get_block_size)
		return klass->get_block_size(hash);
	else {
		purple_debug_warning("hash", "the %s hash does not implement "
			"the get_block_size method", purple_hash_get_name(hash));
	}

	return -1;
}

mercurial