Mercurial > pidgin
changeset 28722:1c1910b17ae5
jabber: Clean up the SCRAM code a little.
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Tue, 01 Dec 2009 02:53:29 +0000 |
parents | f10741a709a9 |
children | 7a78b609786c |
files | libpurple/protocols/jabber/auth_scram.c libpurple/protocols/jabber/auth_scram.h libpurple/tests/test_jabber_scram.c |
diffstat | 3 files changed, 49 insertions(+), 84 deletions(-) [+] |
line wrap: on
line diff
--- a/libpurple/protocols/jabber/auth_scram.c Tue Dec 01 00:30:22 2009 +0000 +++ b/libpurple/protocols/jabber/auth_scram.c Tue Dec 01 02:53:29 2009 +0000 @@ -28,59 +28,31 @@ #include "cipher.h" #include "debug.h" -static const struct { - const char *mech_substr; - const char *hash; -} mech_hashes[] = { - { "-SHA-1", "sha1" }, +static const JabberScramHash hashes[] = { + { "-SHA-1", "sha1", 20 }, }; -static const struct { - const char *hash; - guint size; -} hash_sizes[] = { - { "sha1", 20 }, -}; - -static const gchar *mech_to_hash(const char *mech) +static const JabberScramHash *mech_to_hash(const char *mech) { int i; g_return_val_if_fail(mech != NULL && *mech != '\0', NULL); - for (i = 0; i < G_N_ELEMENTS(mech_hashes); ++i) { - if (strstr(mech, mech_hashes[i].mech_substr)) - return mech_hashes[i].hash; + for (i = 0; i < G_N_ELEMENTS(hashes); ++i) { + if (strstr(mech, hashes[i].mech_substr)) + return &(hashes[i]); } purple_debug_error("jabber", "Unknown SCRAM mechanism %s\n", mech); - - return NULL; + g_return_val_if_reached(NULL); } -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; -} - -guchar *jabber_scram_hi(const gchar *hash, const GString *str, +guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str, GString *salt, guint iterations) { PurpleCipherContext *context; guchar *result; guint i; - guint hash_len; guchar *prev, *tmp; g_return_val_if_fail(hash != NULL, NULL); @@ -88,12 +60,9 @@ 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); - result = g_new0(guint8, hash_len); + prev = g_new0(guint8, hash->size); + tmp = g_new0(guint8, hash->size); + result = g_new0(guint8, hash->size); context = purple_cipher_context_new_by_name("hmac", NULL); @@ -102,25 +71,25 @@ g_string_append_len(salt, "\0\0\0\1", 4); /* Compute U0 */ - purple_cipher_context_set_option(context, "hash", (gpointer)hash); + purple_cipher_context_set_option(context, "hash", (gpointer)hash->name); 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, hash_len, result, NULL); + purple_cipher_context_digest(context, hash->size, result, NULL); - memcpy(prev, result, hash_len); + memcpy(prev, result, hash->size); /* Compute U1...Ui */ for (i = 1; i < iterations; ++i) { guint j; - purple_cipher_context_set_option(context, "hash", (gpointer)hash); + purple_cipher_context_set_option(context, "hash", (gpointer)hash->name); purple_cipher_context_set_key_with_len(context, (guchar *)str->str, str->len); - purple_cipher_context_append(context, prev, hash_len); - purple_cipher_context_digest(context, hash_len, tmp, NULL); + purple_cipher_context_append(context, prev, hash->size); + purple_cipher_context_digest(context, hash->size, tmp, NULL); - for (j = 0; j < hash_len; ++j) + for (j = 0; j < hash->size; ++j) result[j] ^= tmp[j]; - memcpy(prev, tmp, hash_len); + memcpy(prev, tmp, hash->size); } purple_cipher_context_destroy(context); @@ -131,40 +100,41 @@ /* * Helper functions for doing the SCRAM calculations. The first argument - * is the hash algorithm and the second (len) is the length of the output - * buffer and key/data (the fourth 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 gchar *hash_alg, gsize len, guchar *out, const guchar *key, const gchar *str) +hmac(const JabberScramHash *hash, guchar *out, const guchar *key, const gchar *str) { PurpleCipherContext *context; context = purple_cipher_context_new_by_name("hmac", NULL); - purple_cipher_context_set_option(context, "hash", (gpointer)hash_alg); - purple_cipher_context_set_key_with_len(context, key, len); + purple_cipher_context_set_option(context, "hash", (gpointer)hash->name); + purple_cipher_context_set_key_with_len(context, key, hash->size); purple_cipher_context_append(context, (guchar *)str, strlen(str)); - purple_cipher_context_digest(context, len, out, NULL); + purple_cipher_context_digest(context, hash->size, out, NULL); purple_cipher_context_destroy(context); } static void -hash(const gchar *hash_alg, gsize len, guchar *out, const guchar *data) +hash(const JabberScramHash *hash, guchar *out, const guchar *data) { PurpleCipherContext *context; - context = purple_cipher_context_new_by_name(hash_alg, NULL); - purple_cipher_context_append(context, data, len); - purple_cipher_context_digest(context, len, out, NULL); + context = purple_cipher_context_new_by_name(hash->name, NULL); + purple_cipher_context_append(context, data, hash->size); + purple_cipher_context_digest(context, hash->size, out, NULL); purple_cipher_context_destroy(context); } gboolean jabber_scram_calc_proofs(JabberScramData *data, GString *salt, guint iterations) { - guint hash_len = hash_to_output_len(data->hash); + guint hash_len = data->hash->size; guint i; GString *pass = g_string_new(data->password); @@ -189,18 +159,18 @@ return FALSE; /* client_key = HMAC(salted_password, "Client Key") */ - hmac(data->hash, hash_len, client_key, salted_password, "Client Key"); + hmac(data->hash, client_key, salted_password, "Client Key"); /* server_key = HMAC(salted_password, "Server Key") */ - hmac(data->hash, hash_len, server_key, salted_password, "Server Key"); + hmac(data->hash, server_key, salted_password, "Server Key"); g_free(salted_password); /* stored_key = HASH(client_key) */ - hash(data->hash, hash_len, stored_key, client_key); + hash(data->hash, stored_key, client_key); /* client_signature = HMAC(stored_key, auth_message) */ - hmac(data->hash, hash_len, client_signature, stored_key, data->auth_message->str); + hmac(data->hash, client_signature, stored_key, data->auth_message->str); /* server_signature = HMAC(server_key, auth_message) */ - hmac(data->hash, hash_len, (guchar *)data->server_signature->str, server_key, data->auth_message->str); + hmac(data->hash, (guchar *)data->server_signature->str, server_key, data->auth_message->str); /* client_proof = client_key XOR client_signature */ for (i = 0; i < hash_len; ++i) @@ -570,12 +540,6 @@ }; #endif -/* For tests */ -JabberSaslMech *jabber_scram_get_sha1(void) -{ - return &scram_sha1_mech; -} - JabberSaslMech **jabber_auth_get_scram_mechs(gint *count) { static JabberSaslMech *mechs[] = { @@ -585,8 +549,6 @@ #endif }; - g_return_val_if_fail(count != NULL, NULL); - *count = G_N_ELEMENTS(mechs); return mechs; }
--- a/libpurple/protocols/jabber/auth_scram.h Tue Dec 01 00:30:22 2009 +0000 +++ b/libpurple/protocols/jabber/auth_scram.h Tue Dec 01 02:53:29 2009 +0000 @@ -32,9 +32,14 @@ /* Per-connection state stored between messages. * This is stored in js->auth_data_mech. */ +typedef struct { + const char *mech_substr; + const char *name; + guint size; +} JabberScramHash; typedef struct { - const char *hash; + const JabberScramHash *hash; char *cnonce; GString *auth_message; @@ -48,14 +53,10 @@ #include "auth.h" -JabberSaslMech *jabber_scram_get_sha1(void); - /** * Implements the Hi() function as described in the SASL-SCRAM I-D. * - * @param hash The name of a hash function to be used with HMAC. This should - * be suitable to be passed to the libpurple cipher API. Typically - * it will be "sha1". + * @param hash The struct corresponding to the hash function to be used. * @param str The string to perform the PBKDF2 operation on. * @param salt The salt. * @param iterations The number of iterations to perform. @@ -64,7 +65,7 @@ * NOT null-terminated and its length is the length of the binary * output of the hash function in-use. */ -guchar *jabber_scram_hi(const char *hash, const GString *str, +guchar *jabber_scram_hi(const JabberScramHash *hash, const GString *str, GString *salt, guint iterations); /**
--- a/libpurple/tests/test_jabber_scram.c Tue Dec 01 00:30:22 2009 +0000 +++ b/libpurple/tests/test_jabber_scram.c Tue Dec 01 02:53:29 2009 +0000 @@ -4,10 +4,12 @@ #include "../util.h" #include "../protocols/jabber/auth_scram.h" +static JabberScramHash sha1_mech = { "-SHA-1", "sha1", 20 }; + #define assert_pbkdf2_equal(password, salt, count, expected) { \ GString *p = g_string_new(password); \ GString *s = g_string_new(salt); \ - guchar *result = jabber_scram_hi("sha1", p, s, count); \ + guchar *result = jabber_scram_hi(&sha1_mech, p, s, count); \ fail_if(result == NULL, "Hi() returned NULL"); \ fail_if(0 != memcmp(result, expected, 20), "Hi() returned invalid result"); \ g_string_free(s, TRUE); \ @@ -35,7 +37,7 @@ const char *client_proof; /* const char *server_signature; */ - data->hash = "sha1"; + data->hash = &sha1_mech; data->password = g_strdup("password"); data->auth_message = g_string_new("n=username@jabber.org,r=8jLxB5515dhFxBil5A0xSXMH," "r=8jLxB5515dhFxBil5A0xSXMHabc,s=c2FsdA==,i=1," @@ -60,7 +62,7 @@ gchar *out; data->step = 1; - data->hash = "sha1"; + data->hash = &sha1_mech; data->password = g_strdup("password"); data->cnonce = g_strdup("H7yDYKAWBCrM2Fa5SxGa4iez"); data->auth_message = g_string_new("n=paul,r=H7yDYKAWBCrM2Fa5SxGa4iez");