# HG changeset patch # User Paul Aurich # Date 1257705510 0 # Node ID ec843b380a1d45c3ed69a52cec4e4ca25870b6d7 # Parent 398ff52e7d62ba88b318d08d28224fb5c749c815 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? diff -r 398ff52e7d62 -r ec843b380a1d libpurple/protocols/jabber/auth_scram.c --- 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);