[epiphany/wip/ephy-sync] Implement function for computing the hawk header
- From: Gabriel - Cristian Ivascu <gabrielivascu src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [epiphany/wip/ephy-sync] Implement function for computing the hawk header
- Date: Sun, 26 Jun 2016 15:51:20 +0000 (UTC)
commit cb9a69800d315fcce8674c5ea9543fb54148ba3b
Author: Gabriel Ivascu <ivascu gabriel59 gmail com>
Date: Sun Jun 26 18:50:40 2016 +0300
Implement function for computing the hawk header
src/ephy-sync-crypto.c | 408 ++++++++++++++++++++++++++++++++++++++++++++++++
src/ephy-sync-crypto.h | 80 ++++++++--
2 files changed, 473 insertions(+), 15 deletions(-)
---
diff --git a/src/ephy-sync-crypto.c b/src/ephy-sync-crypto.c
index 00480cf..7dc05b1 100644
--- a/src/ephy-sync-crypto.c
+++ b/src/ephy-sync-crypto.c
@@ -18,10 +18,315 @@
#include "ephy-sync-crypto.h"
+#include <libsoup/soup.h>
#include <nettle/hmac.h>
#include <nettle/pbkdf2.h>
+#include <nettle/sha2.h>
#include <string.h>
+#define HAWK_VERSION 1
+
+static EphySyncCryptoHawkHeader *
+ephy_sync_crypto_hawk_header_new (gchar *header,
+ EphySyncCryptoHawkArtifacts *artifacts)
+{
+ EphySyncCryptoHawkHeader *hawk_header;
+
+ hawk_header = g_slice_new (EphySyncCryptoHawkHeader);
+ hawk_header->header = header;
+ hawk_header->artifacts = artifacts;
+
+ return hawk_header;
+}
+
+static EphySyncCryptoHawkArtifacts *
+ephy_sync_crypto_hawk_artifacts_new (gchar *app,
+ gchar *dlg,
+ gchar *ext,
+ gchar *hash,
+ gchar *host,
+ gchar *method,
+ gchar *nonce,
+ gchar *port,
+ gchar *resource,
+ gchar *ts)
+{
+ EphySyncCryptoHawkArtifacts *hawk_artifacts;
+
+ hawk_artifacts = g_slice_new (EphySyncCryptoHawkArtifacts);
+ hawk_artifacts->app = app;
+ hawk_artifacts->dlg = dlg;
+ hawk_artifacts->ext = ext;
+ hawk_artifacts->hash = hash;
+ hawk_artifacts->host = host;
+ hawk_artifacts->method = method;
+ hawk_artifacts->nonce = nonce;
+ hawk_artifacts->port = port;
+ hawk_artifacts->resource = resource;
+ hawk_artifacts->ts = ts;
+
+ return hawk_artifacts;
+}
+
+static void
+ephy_sync_crypto_hawk_artifacts_free (EphySyncCryptoHawkArtifacts *hawk_artifacts)
+{
+ g_free (hawk_artifacts->app);
+ g_free (hawk_artifacts->dlg);
+ g_free (hawk_artifacts->ext);
+ g_free (hawk_artifacts->hash);
+ g_free (hawk_artifacts->host);
+ g_free (hawk_artifacts->method);
+ g_free (hawk_artifacts->nonce);
+ g_free (hawk_artifacts->port);
+ g_free (hawk_artifacts->resource);
+ g_free (hawk_artifacts->ts);
+
+ g_slice_free (EphySyncCryptoHawkArtifacts, hawk_artifacts);
+}
+
+static gchar *
+generate_random_string (gsize length)
+{
+ guchar *bytes;
+ gchar *base64_string;
+ gchar *string;
+
+ bytes = g_malloc (length);
+ for (gsize i = 0; i < length; i++)
+ bytes[i] = g_random_int ();
+
+ base64_string = g_base64_encode (bytes, length);
+ string = g_strndup (base64_string, length);
+
+ g_free (bytes);
+ g_free (base64_string);
+
+ return string;
+}
+
+static gchar *
+find_and_replace_string (const gchar *src,
+ const gchar *find,
+ const gchar *repl)
+{
+ const gchar *haystack = src;
+ const gchar *needle = NULL;
+ gsize haystack_length = strlen (src);
+ gsize find_length = strlen (find);
+ gsize repl_length = strlen (repl);
+ gsize new_length = 0;
+ gsize skip_length = 0;
+ gchar *new = g_malloc (haystack_length + 1);
+
+ while ((needle = g_strstr_len (haystack, -1, find)) != NULL) {
+ haystack_length += find_length - repl_length;
+ new = g_realloc (new, haystack_length + 1);
+ skip_length = needle - haystack;
+ memcpy (new + new_length, haystack, skip_length);
+ memcpy (new + new_length + skip_length, repl, repl_length);
+ new_length += skip_length + repl_length;
+ haystack = needle + find_length;
+ }
+ strcpy (new + new_length, haystack);
+
+ return new;
+}
+
+static gchar *
+normalize_string (const gchar *mac_type,
+ EphySyncCryptoHawkArtifacts *artifacts)
+{
+ gchar *host;
+ gchar *info;
+ gchar *method;
+ gchar *n_ext = NULL;
+ gchar *normalized;
+ gchar *tmp;
+
+ g_return_val_if_fail (mac_type, NULL);
+ g_return_val_if_fail (artifacts, NULL);
+
+ info = g_strdup_printf ("hawk.%d.%s", HAWK_VERSION, mac_type);
+ method = g_ascii_strup (artifacts->method, -1);
+ host = g_ascii_strdown (artifacts->host, -1);
+
+ normalized = g_strjoin ("\n",
+ info,
+ artifacts->ts,
+ method,
+ artifacts->resource,
+ host,
+ artifacts->port,
+ artifacts->hash ? artifacts->hash : "",
+ NULL);
+
+ if (artifacts->ext && strlen (artifacts->ext) > 0) {
+ tmp = find_and_replace_string (artifacts->ext, "\\", "\\\\");
+ n_ext = find_and_replace_string (tmp, "\n", "\\n");
+ g_free (tmp);
+ }
+
+ tmp = normalized;
+ normalized = g_strconcat (normalized, "\n",
+ n_ext ? n_ext : "", "\n",
+ artifacts->app ? artifacts->app : "", "\n",
+ artifacts->app && artifacts->dlg ? artifacts->dlg : "",
+ artifacts->app && artifacts->dlg ? "\n" : "",
+ NULL);
+
+ g_free (host);
+ g_free (info);
+ g_free (method);
+ g_free (n_ext);
+ g_free (tmp);
+
+ return normalized;
+}
+
+static gchar *
+parse_content_type (const gchar *content_type)
+{
+ gchar **tokens;
+ gchar *retval;
+
+ tokens = g_strsplit (content_type, ";", -1);
+ retval = g_ascii_strdown (g_strstrip (tokens[0]), -1);
+ g_strfreev (tokens);
+
+ return retval;
+}
+
+static gchar *
+calculate_payload_hash (const gchar *payload,
+ const gchar *content_type)
+{
+ struct sha256_ctx ctx;
+ guint8 *digest;
+ gchar *content;
+ gchar *update;
+ gchar *retval;
+
+ g_return_val_if_fail (payload, NULL);
+ g_return_val_if_fail (content_type, NULL);
+
+ content = parse_content_type (content_type);
+ update = g_strdup_printf ("hawk.%d.payload\n%s\n%s\n",
+ HAWK_VERSION,
+ content,
+ payload);
+ digest = g_malloc (SHA256_DIGEST_SIZE);
+
+ sha256_init (&ctx);
+ sha256_update (&ctx, strlen (update), (guint8 *) update);
+ sha256_digest (&ctx, SHA256_DIGEST_SIZE, digest);
+ retval = g_base64_encode (digest, SHA256_DIGEST_SIZE);
+
+ g_free (content);
+ g_free (update);
+ g_free (digest);
+
+ return retval;
+}
+
+static gchar *
+calculate_mac (const gchar *mac_type,
+ const gchar *key,
+ EphySyncCryptoHawkArtifacts *artifacts)
+{
+ struct hmac_sha256_ctx ctx;
+ guint8 *digest;
+ gchar *normalized;
+ gchar *mac;
+
+ g_return_val_if_fail (mac_type, NULL);
+ g_return_val_if_fail (key, NULL);
+ g_return_val_if_fail (artifacts, NULL);
+
+ normalized = normalize_string (mac_type, artifacts);
+ digest = g_malloc (SHA256_DIGEST_SIZE);
+
+ hmac_sha256_set_key (&ctx, strlen (key), (guint8 *) key);
+ hmac_sha256_update (&ctx, strlen (normalized), (guint8 *) normalized);
+ hmac_sha256_digest (&ctx, SHA256_DIGEST_SIZE, digest);
+ mac = g_base64_encode (digest, SHA256_DIGEST_SIZE);
+
+ g_free (normalized);
+ g_free (digest);
+
+ return mac;
+}
+
+static gchar *
+append_token_to_header (gchar *header,
+ const gchar *token_name,
+ gchar *token_value)
+{
+ gchar *new_header;
+ gchar *tmp;
+
+ tmp = header;
+ new_header = g_strconcat (header, ", ",
+ token_name, "=\"",
+ token_value, "\"",
+ NULL);
+ g_free (tmp);
+
+ return new_header;
+}
+
+EphySyncCryptoHawkOptions *
+ephy_sync_crypto_hawk_options_new (gchar *app,
+ gchar *dlg,
+ gchar *ext,
+ gchar *content_type,
+ gchar *hash,
+ gchar *local_time_offset,
+ gchar *nonce,
+ gchar *payload,
+ gchar *timestamp)
+{
+ EphySyncCryptoHawkOptions *hawk_options;
+
+ hawk_options = g_slice_new (EphySyncCryptoHawkOptions);
+ hawk_options->app = app;
+ hawk_options->dlg = dlg;
+ hawk_options->ext = ext;
+ hawk_options->content_type = content_type;
+ hawk_options->hash = hash;
+ hawk_options->local_time_offset = local_time_offset;
+ hawk_options->nonce = nonce;
+ hawk_options->payload = payload;
+ hawk_options->timestamp = timestamp;
+
+ return hawk_options;
+}
+
+void
+ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions *hawk_options)
+{
+ g_free (hawk_options->app);
+ g_free (hawk_options->dlg);
+ g_free (hawk_options->ext);
+ g_free (hawk_options->content_type);
+ g_free (hawk_options->hash);
+ g_free (hawk_options->local_time_offset);
+ g_free (hawk_options->nonce);
+ g_free (hawk_options->payload);
+ g_free (hawk_options->timestamp);
+
+ g_slice_free (EphySyncCryptoHawkOptions, hawk_options);
+}
+
+void
+ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header)
+{
+ g_free (hawk_header->header);
+ ephy_sync_crypto_hawk_artifacts_free (hawk_header->artifacts);
+
+ g_slice_free (EphySyncCryptoHawkHeader, hawk_header);
+}
+
/*
* Runs 1000 iterations of PBKDF2.
* Uses sha256 as hash function.
@@ -94,3 +399,106 @@ ephy_sync_crypto_hkdf (guint8 *in,
g_free (tmp);
g_free (prk);
}
+
+EphySyncCryptoHawkHeader *
+ephy_sync_crypto_compute_hawk_header (const gchar *url,
+ const gchar *method,
+ const gchar *id,
+ const gchar *key,
+ EphySyncCryptoHawkOptions *options)
+{
+ EphySyncCryptoHawkArtifacts *artifacts;
+ SoupURI *uri;
+ gboolean has_options;
+ const gchar *hostname;
+ const gchar *resource;
+ gchar *hash;
+ gchar *header;
+ gchar *mac;
+ gchar *nonce;
+ gchar *payload;
+ gchar *timestamp;
+ gint64 ts;
+ guint port;
+
+ g_return_val_if_fail (url && strlen (url) > 0, NULL);
+ g_return_val_if_fail (method && strlen (method) > 0, NULL);
+ g_return_val_if_fail (id && strlen (id) > 0, NULL);
+ g_return_val_if_fail (key && strlen (key) > 0, NULL);
+
+ has_options = options != NULL;
+ ts = g_get_real_time () / 1000000;
+
+ timestamp = has_options ? options->timestamp : NULL;
+ if (timestamp) {
+ gchar *local_time_offset;
+ gint64 offset;
+
+ local_time_offset = has_options ? options->local_time_offset : NULL;
+ offset = local_time_offset ? g_ascii_strtoll (local_time_offset, NULL, 10) : 0;
+
+ ts = g_ascii_strtoll (timestamp, NULL, 10) + offset;
+ }
+
+ nonce = has_options ? options->nonce : NULL;
+ nonce = nonce ? nonce : generate_random_string (6);
+ hash = has_options ? options->hash : NULL;
+ payload = has_options ? options->payload : NULL;
+
+ uri = soup_uri_new (url);
+ g_return_val_if_fail (uri, NULL);
+ hostname = soup_uri_get_host (uri);
+ port = soup_uri_get_port (uri);
+ resource = soup_uri_get_path (uri);
+
+ if (!hash && payload) {
+ const gchar *content_type;
+
+ content_type = has_options ? options->content_type : "text/plain";
+ hash = calculate_payload_hash (payload, content_type);
+ }
+
+ artifacts = ephy_sync_crypto_hawk_artifacts_new (has_options ? options->app : NULL,
+ has_options ? options->dlg : NULL,
+ has_options ? options->ext : NULL,
+ hash,
+ g_strdup (hostname),
+ g_strdup (method),
+ nonce,
+ g_strdup_printf ("%u", port),
+ g_strdup (resource),
+ g_strdup_printf ("%ld", ts));
+
+ mac = calculate_mac ("header", key, artifacts);
+
+ header = g_strconcat ("Hawk id=\"", id, "\"",
+ ", ts=\"", artifacts->ts, "\"",
+ ", nonce=\"", artifacts->nonce, "\"",
+ NULL);
+
+ if (artifacts->hash && strlen (artifacts->hash) > 0)
+ header = append_token_to_header (header, "hash", artifacts->hash);
+
+ if (artifacts->ext && strlen (artifacts->ext) > 0) {
+ gchar *h_ext;
+ gchar *tmp_ext;
+
+ tmp_ext = find_and_replace_string (artifacts->ext, "\\", "\\\\");
+ h_ext = find_and_replace_string (tmp_ext, "\n", "\\n");
+ header = append_token_to_header (header, "ext", h_ext);
+
+ g_free (h_ext);
+ g_free (tmp_ext);
+ }
+
+ header = append_token_to_header (header, "mac", mac);
+
+ if (artifacts->app) {
+ header = append_token_to_header (header, "app", artifacts->app);
+
+ if (artifacts->dlg)
+ header = append_token_to_header (header, "dlg", artifacts->dlg);
+ }
+
+ return ephy_sync_crypto_hawk_header_new (header, artifacts);
+}
diff --git a/src/ephy-sync-crypto.h b/src/ephy-sync-crypto.h
index ec4cd3a..e870b3f 100644
--- a/src/ephy-sync-crypto.h
+++ b/src/ephy-sync-crypto.h
@@ -23,21 +23,71 @@
G_BEGIN_DECLS
-void ephy_sync_crypto_pbkdf2_1k (guint8 *key,
- gsize key_length,
- guint8 *salt,
- gsize salt_length,
- guint8 *out,
- gsize out_length);
-
-void ephy_sync_crypto_hkdf (guint8 *in,
- gsize in_length,
- guint8 *salt,
- gsize salt_length,
- guint8 *info,
- gsize info_length,
- guint8 *out,
- gsize out_length);
+typedef struct {
+ gchar *app;
+ gchar *dlg;
+ gchar *ext;
+ gchar *content_type;
+ gchar *hash;
+ gchar *local_time_offset;
+ gchar *nonce;
+ gchar *payload;
+ gchar *timestamp;
+} EphySyncCryptoHawkOptions;
+
+typedef struct {
+ gchar *app;
+ gchar *dlg;
+ gchar *ext;
+ gchar *hash;
+ gchar *host;
+ gchar *method;
+ gchar *nonce;
+ gchar *port;
+ gchar *resource;
+ gchar *ts;
+} EphySyncCryptoHawkArtifacts;
+
+typedef struct {
+ gchar *header;
+ EphySyncCryptoHawkArtifacts *artifacts;
+} EphySyncCryptoHawkHeader;
+
+void ephy_sync_crypto_pbkdf2_1k (guint8 *key,
+ gsize key_length,
+ guint8 *salt,
+ gsize salt_length,
+ guint8 *out,
+ gsize out_length);
+
+void ephy_sync_crypto_hkdf (guint8 *in,
+ gsize in_length,
+ guint8 *salt,
+ gsize salt_length,
+ guint8 *info,
+ gsize info_length,
+ guint8 *out,
+ gsize out_length);
+
+EphySyncCryptoHawkHeader *ephy_sync_crypto_compute_hawk_header (const gchar *url,
+ const gchar *method,
+ const gchar *id,
+ const gchar *key,
+ EphySyncCryptoHawkOptions *options);
+
+EphySyncCryptoHawkOptions *ephy_sync_crypto_hawk_options_new (gchar *app,
+ gchar *dlg,
+ gchar *ext,
+ gchar *content_type,
+ gchar *hash,
+ gchar *local_time_offset,
+ gchar *nonce,
+ gchar *payload,
+ gchar *timestamp);
+
+void ephy_sync_crypto_hawk_options_free (EphySyncCryptoHawkOptions *hawk_options);
+
+void ephy_sync_crypto_hawk_header_free (EphySyncCryptoHawkHeader *hawk_header);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]