libpurple/hash.c

branch
soc.2013.gobjectification
changeset 34566
e0f887dee077
child 34567
ea5103f66b0e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libpurple/hash.c	Sun Jun 16 03:46:10 2013 +0530
@@ -0,0 +1,297 @@
+/* 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 "hash.h"
+#include "debug.h"
+
+/******************************************************************************
+ * Object Stuff
+ *****************************************************************************/
+static void
+purple_hash_class_init(PurpleHashClass *klass) {
+	klass->reset = NULL;
+	klass->reset_state = NULL;
+	klass->set_iv = NULL;
+	klass->append = NULL;
+	klass->digest = NULL;
+	klass->get_digest_size = NULL;
+	klass->get_block_size = NULL;
+	klass->get_name = NULL;
+}
+
+/******************************************************************************
+ * PurpleHash API
+ *****************************************************************************/
+const gchar *
+purple_hash_get_name(PurpleHash *hash) {
+	PurpleHashClass *klass = NULL;
+
+	g_return_val_if_fail(hash, NULL);
+	g_return_val_if_fail(PURPLE_IS_HASH(hash), NULL);
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+	g_return_val_if_fail(klass->get_name, NULL);
+
+	return klass->get_name(hash);
+}
+
+GType
+purple_hash_get_type(void) {
+	static GType type = 0;
+
+	if(type == 0) {
+		static const GTypeInfo info = {
+			sizeof(PurpleHashClass),
+			NULL,
+			NULL,
+			(GClassInitFunc)purple_hash_class_init,
+			NULL,
+			NULL,
+			sizeof(PurpleHash),
+			0,
+			NULL,
+			NULL
+		};
+
+		type = g_type_register_static(G_TYPE_OBJECT,
+									  "PurpleHash",
+									  &info, G_TYPE_FLAG_ABSTRACT);
+	}
+
+	return type;
+}
+
+/**
+ * purple_hash_reset:
+ * @hash: The hash to reset
+ *
+ * Resets a hash to it's default value
+ *
+ * @note If you have set an IV you will have to set it after resetting
+ */
+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\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * Resets a hash state to it's default value, but doesn't touch stateless
+ * configuration.
+ *
+ * That means, IV and digest context will be wiped out, but keys, ops or salt
+ * will remain untouched.
+ */
+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\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * purple_hash_set_iv:
+ * @hash: The hash to set the IV to
+ * @iv: The initialization vector to set
+ * @len: The len of the IV
+ *
+ * @note This should only be called right after a hash is created or reset
+ *
+ * Sets the initialization vector for a hash
+ */
+void
+purple_hash_set_iv(PurpleHash *hash, guchar *iv, size_t len)
+{
+	PurpleHashClass *klass = NULL;
+
+	g_return_if_fail(PURPLE_IS_HASH(hash));
+	g_return_if_fail(iv);
+
+	klass = PURPLE_HASH_GET_CLASS(hash);
+
+	if(klass && klass->set_iv)
+		klass->set_iv(hash, iv, len);
+	else
+		purple_debug_warning("hash", "the %s hash does not implement the "
+						"set_iv method\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * purple_hash_append:
+ * @hash: The hash to append data to
+ * @data: The data to append
+ * @len: The length of the data
+ *
+ * Appends data to the 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\n",
+						klass->get_name ? klass->get_name(hash) : "");
+}
+
+/**
+ * purple_hash_digest:
+ * @hash: The hash to digest
+ * @in_len: The length of the buffer
+ * @digest: The return buffer for the digest
+ * @out_len: The length of the returned value
+ *
+ * Digests a hash
+ *
+ * Return Value: TRUE if the digest was successful, FALSE otherwise.
+ */
+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\n",
+						klass->get_name ? klass->get_name(hash) : "");
+
+	return FALSE;
+}
+
+/**
+ * purple_hash_digest_to_str:
+ * @hash: The hash to get a digest from
+ * @in_len: The length of the buffer
+ * @digest_s: The return buffer for the string digest
+ * @out_len: The length of the returned value
+ *
+ * Converts a guchar digest into a hex string
+ *
+ * Return Value: TRUE if the digest was successful, FALSE otherwise.
+ */
+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];
+	gint n = 0;
+	size_t digest_size;
+
+	g_return_val_if_fail(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\n",
+						klass->get_name ? klass->get_name(hash) : "");
+
+	return FALSE;
+}
+
+/**
+ * purple_hash_get_block_size:
+ * @hash: The hash whose block size to get
+ *
+ * Gets the block size of a hash
+ *
+ * Return Value: The block size of the hash
+ */
+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\n",
+						klass->get_name ? klass->get_name(hash) : "");
+
+	return -1;
+}

mercurial