changeset 29087:ec843b380a1d

How is it that there's no programmatic way to get the output size of the hash functions without resorting to a hardcoded table? Or did I miss something?
author Paul Aurich <paul@darkrain42.org>
date Sun, 08 Nov 2009 18:38:30 +0000
parents 398ff52e7d62
children 2b4465db73f1
files libpurple/protocols/jabber/auth_scram.c
diffstat 1 files changed, 42 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/jabber/auth_scram.c	Sun Nov 08 06:06:54 2009 +0000
+++ b/libpurple/protocols/jabber/auth_scram.c	Sun Nov 08 18:38:30 2009 +0000
@@ -28,47 +28,81 @@
 #include "cipher.h"
 #include "debug.h"
 
+static const struct {
+	const char *hash;
+	guint size;
+} hash_sizes[] = {
+	{ "sha1", 20 },
+	{ "sha224", 28 },
+	{ "sha256", 32 },
+	{ "sha384", 48 },
+	{ "sha512", 64 }
+};
+
+static guint hash_to_output_len(const gchar *hash)
+{
+	int i;
+
+	g_return_val_if_fail(hash != NULL && *hash != '\0', 0);
+
+	for (i = 0; i < G_N_ELEMENTS(hash_sizes); ++i) {
+		if (g_str_equal(hash, hash_sizes[i].hash))
+			return hash_sizes[i].size;
+	}
+
+	purple_debug_error("jabber", "Unknown SCRAM hash function %s\n", hash);
+
+	return 0;
+}
+
 GString *jabber_auth_scram_hi(const gchar *hash, const GString *str,
                               GString *salt, guint iterations)
 {
 	PurpleCipherContext *context;
 	GString *result;
 	guint i;
-	guchar prev[20], tmp[20]; /* FIXME: Hardcoded 20 */
+	guint hash_len;
+	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);
 
+	hash_len = hash_to_output_len(hash);
+	g_return_val_if_fail(hash_len > 0, NULL);
+
+	prev = g_new0(guint8, hash_len);
+	tmp = g_new0(guint8, hash_len);
+
 	context = purple_cipher_context_new_by_name("hmac", NULL);
 
 	/* 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);
 
-	result = g_string_sized_new(20); /* FIXME: Hardcoded 20 */
+	result = g_string_sized_new(hash_len);
 
 	/* Compute U0 */
 	purple_cipher_context_set_option(context, "hash", (gpointer)hash);
 	purple_cipher_context_set_key_with_len(context, (guchar *)str->str, str->len);
 	purple_cipher_context_append(context, (guchar *)salt->str, salt->len);
-	purple_cipher_context_digest(context, result->allocated_len, (guchar *)result->str, &(result->len));
+	purple_cipher_context_digest(context, hash_len, (guchar *)result->str, &(result->len));
 
-	memcpy(prev, result->str, result->len);
+	memcpy(prev, result->str, hash_len);
 
 	/* Compute U1...Ui */
 	for (i = 1; i < iterations; ++i) {
 		guint j;
 		purple_cipher_context_set_option(context, "hash", (gpointer)hash);
 		purple_cipher_context_set_key_with_len(context, (guchar *)str->str, str->len);
-		purple_cipher_context_append(context, prev, result->len);
-		purple_cipher_context_digest(context, sizeof(tmp), tmp, NULL);
+		purple_cipher_context_append(context, prev, hash_len);
+		purple_cipher_context_digest(context, hash_len, tmp, NULL);
 
-		for (j = 0; j < 20; ++j)
+		for (j = 0; j < hash_len; ++j)
 			result->str[j] ^= tmp[j];
 
-		memcpy(prev, tmp, result->len);
+		memcpy(prev, tmp, hash_len);
 	}
 
 	purple_cipher_context_destroy(context);