|
|
@@ -25,36 +25,10 @@
|
|
|
#include <nettle/sha2.h>
|
|
|
#include <nettle/hmac.h>
|
|
|
#include <nettle/pbkdf2.h>
|
|
|
+#include "iridium-crypto.h"
|
|
|
#include "iridium-standard-file.h"
|
|
|
#include "iridium-note.h"
|
|
|
|
|
|
-typedef enum {
|
|
|
- SF_VERSION_001,
|
|
|
- SF_VERSION_002,
|
|
|
-} StandardFileVersion;
|
|
|
-
|
|
|
-typedef enum {
|
|
|
- SF_FUNC_PBKDF2,
|
|
|
-} StandardFileFunc;
|
|
|
-
|
|
|
-typedef enum {
|
|
|
- SF_HASH_SHA512,
|
|
|
-} StandardFileHash;
|
|
|
-
|
|
|
-typedef struct {
|
|
|
- guint cost;
|
|
|
- guint key_size;
|
|
|
- gchar *salt;
|
|
|
- StandardFileFunc func;
|
|
|
- StandardFileFunc hash;
|
|
|
- StandardFileVersion version;
|
|
|
- struct {
|
|
|
- guint8 password[32];
|
|
|
- guint8 master[32];
|
|
|
- guint8 auth[32];
|
|
|
- } keys;
|
|
|
-} StandardFileAuthParams;
|
|
|
-
|
|
|
typedef struct {
|
|
|
IridiumStandardFile *client;
|
|
|
gchar *password;
|
|
|
@@ -68,7 +42,7 @@ struct _IridiumStandardFile
|
|
|
gchar *token;
|
|
|
SoupSession *session;
|
|
|
SoupURI *base_uri;
|
|
|
- StandardFileAuthParams auth_params;
|
|
|
+ IridiumAuthParams auth_params;
|
|
|
};
|
|
|
|
|
|
G_DEFINE_TYPE (IridiumStandardFile, iridium_standard_file, G_TYPE_OBJECT)
|
|
|
@@ -93,148 +67,6 @@ iridium_standard_file_new (void)
|
|
|
return g_object_new (IRIDIUM_TYPE_STANDARD_FILE, NULL);
|
|
|
}
|
|
|
|
|
|
-static guint8 *
|
|
|
-unhexlify (const gchar *s, gsize length)
|
|
|
-{
|
|
|
- guint8 *result;
|
|
|
-
|
|
|
- result = g_malloc0 (length / 2);
|
|
|
-
|
|
|
- for (gsize i = 0; i < length / 2; i++)
|
|
|
- sscanf (&s[i * 2], "%2hhx", &result[i]);
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-static gchar *
|
|
|
-hexlify (const guint8 *s, gsize length)
|
|
|
-{
|
|
|
- gchar *result;
|
|
|
-
|
|
|
- result = g_malloc0 (2 * length + 1);
|
|
|
-
|
|
|
- for (gsize i = 0; i < length; i++)
|
|
|
- g_snprintf (&result[2 * i], 3, "%02x", s[i]);
|
|
|
-
|
|
|
- return result;
|
|
|
-}
|
|
|
-
|
|
|
-static void
|
|
|
-derive_keys (const guint8 *password,
|
|
|
- StandardFileAuthParams *params)
|
|
|
-{
|
|
|
- struct hmac_sha512_ctx context;
|
|
|
- guint8 dst[96];
|
|
|
-
|
|
|
- g_assert_nonnull (params->salt);
|
|
|
-
|
|
|
- hmac_sha512_set_key (&context, strlen ((gchar *) password), password);
|
|
|
-
|
|
|
- PBKDF2 (&context, hmac_sha512_update, hmac_sha512_digest, SHA512_DIGEST_SIZE,
|
|
|
- params->cost, strlen (params->salt), (guint8 *) params->salt, 96, dst);
|
|
|
-
|
|
|
- memcpy (¶ms->keys, dst, sizeof (dst));
|
|
|
-}
|
|
|
-
|
|
|
-static gchar *
|
|
|
-decrypt (const gchar *s,
|
|
|
- const gchar *check_uuid,
|
|
|
- const guint8 *enc_key,
|
|
|
- const guint8 *auth_key,
|
|
|
- gsize key_length)
|
|
|
-{
|
|
|
- gchar **v;
|
|
|
- gchar *to_auth;
|
|
|
- gchar *hash;
|
|
|
- gsize cipher_length;
|
|
|
- gsize raw_length;
|
|
|
- const gchar *version;
|
|
|
- const gchar *auth_hash;
|
|
|
- const gchar *uuid;
|
|
|
- const gchar *iv;
|
|
|
- const gchar *cipher_text;
|
|
|
- guint8 *iv_bytes;
|
|
|
- guint8 *dst;
|
|
|
- guchar *cipher_raw_text;
|
|
|
- struct hmac_sha256_ctx hmac_contextt;
|
|
|
- guint8 digest[SHA256_DIGEST_SIZE];
|
|
|
- struct aes_ctx aes_context;
|
|
|
-
|
|
|
- v = g_strsplit (s, ":", 0);
|
|
|
- g_assert_nonnull (v[0]); version = v[0];
|
|
|
- g_assert_nonnull (v[1]); auth_hash = v[1];
|
|
|
- g_assert_nonnull (v[2]); uuid = v[2];
|
|
|
- g_assert_nonnull (v[3]); iv = v[3];
|
|
|
- g_assert_nonnull (v[4]); cipher_text = v[4];
|
|
|
-
|
|
|
- g_assert_cmpstr (uuid, ==, check_uuid);
|
|
|
-
|
|
|
- to_auth = g_strjoin (":", version, uuid, iv, cipher_text, NULL);
|
|
|
- hmac_sha256_set_key (&hmac_contextt, key_length, auth_key);
|
|
|
- hmac_sha256_update (&hmac_contextt, strlen (to_auth), (guint8 *) to_auth);
|
|
|
- hmac_sha256_digest (&hmac_contextt, SHA256_DIGEST_SIZE, digest);
|
|
|
-
|
|
|
- hash = hexlify (digest, sizeof (digest));
|
|
|
- g_assert_cmpstr (hash, ==, (gchar *) auth_hash);
|
|
|
- g_free (hash);
|
|
|
-
|
|
|
- cipher_length = strlen (cipher_text);
|
|
|
- cipher_length = AES_BLOCK_SIZE * (cipher_length / AES_BLOCK_SIZE + (cipher_length % AES_BLOCK_SIZE ? 1 : 0));
|
|
|
- dst = g_malloc0 (cipher_length);
|
|
|
-
|
|
|
- aes_set_decrypt_key (&aes_context, key_length, enc_key);
|
|
|
- iv_bytes = unhexlify (iv, strlen (iv));
|
|
|
- cipher_raw_text = g_base64_decode (cipher_text, &raw_length);
|
|
|
-
|
|
|
- cbc_decrypt (&aes_context, (nettle_cipher_func *) &aes_decrypt, AES_BLOCK_SIZE, iv_bytes,
|
|
|
- raw_length, dst, (guint8 *) cipher_raw_text);
|
|
|
-
|
|
|
- dst[raw_length] = '\0';
|
|
|
- g_free (cipher_raw_text);
|
|
|
- g_free (iv_bytes);
|
|
|
- g_free (to_auth);
|
|
|
- g_strfreev (v);
|
|
|
- return (gchar *) dst;
|
|
|
-}
|
|
|
-
|
|
|
-static gchar *
|
|
|
-decrypt_item (JsonObject *item, StandardFileAuthParams *params)
|
|
|
-{
|
|
|
- const gchar *enc_item_key;
|
|
|
- const gchar *uuid;
|
|
|
- gchar *enc_auth_key;
|
|
|
- const gchar *enc_key;
|
|
|
- const gchar *auth_key;
|
|
|
- guint8 *enc_key_bytes;
|
|
|
- guint8 *auth_key_bytes;
|
|
|
- gsize enc_key_size;
|
|
|
- const gchar *enc_content;
|
|
|
- gchar *content;
|
|
|
-
|
|
|
- uuid = json_object_get_string_member (item, "uuid");
|
|
|
- enc_item_key = json_object_get_string_member (item, "enc_item_key");
|
|
|
-
|
|
|
- if (!g_strcmp0 (enc_item_key, ""))
|
|
|
- return NULL;
|
|
|
-
|
|
|
- enc_auth_key = decrypt (enc_item_key, uuid, params->keys.master, params->keys.auth, sizeof (params->keys.master));
|
|
|
-
|
|
|
- enc_key = (gchar *) enc_auth_key;
|
|
|
- enc_key_size = strlen (enc_auth_key) / 2 - 8;
|
|
|
- auth_key = &enc_auth_key[enc_key_size];
|
|
|
-
|
|
|
- enc_key_bytes = unhexlify (enc_key, enc_key_size);
|
|
|
- auth_key_bytes = unhexlify (auth_key, enc_key_size);
|
|
|
-
|
|
|
- enc_content = json_object_get_string_member (item, "content");
|
|
|
- content = decrypt (enc_content, uuid, enc_key_bytes, auth_key_bytes, enc_key_size / 2);
|
|
|
-
|
|
|
- g_free (enc_key_bytes);
|
|
|
- g_free (auth_key_bytes);
|
|
|
- g_free (enc_auth_key);
|
|
|
- return content;
|
|
|
-}
|
|
|
-
|
|
|
static IridiumNote *
|
|
|
deserialize_note (JsonObject *meta, JsonObject *data)
|
|
|
{
|
|
|
@@ -284,8 +116,8 @@ get_auth_params (JsonParser *parser,
|
|
|
|
|
|
object = json_node_get_object (json_parser_get_root (parser));
|
|
|
|
|
|
- params->client->auth_params.func = SF_FUNC_PBKDF2;
|
|
|
- params->client->auth_params.hash = SF_HASH_SHA512;
|
|
|
+ params->client->auth_params.func = IRIDIUM_CRYPTO_SF_FUNC_PBKDF2;
|
|
|
+ params->client->auth_params.hash = IRIDIUM_CRYPTO_SF_HASH_SHA512;
|
|
|
params->client->auth_params.cost = json_object_get_int_member (object, "pw_cost");
|
|
|
params->client->auth_params.key_size = json_object_get_int_member (object, "pw_key_size");
|
|
|
params->client->auth_params.salt = g_strdup (json_object_get_string_member (object, "pw_salt"));
|
|
|
@@ -305,9 +137,9 @@ get_auth_params (JsonParser *parser,
|
|
|
s = json_object_get_string_member (object, "version");
|
|
|
|
|
|
if (!g_strcmp0 (s, "001"))
|
|
|
- params->client->auth_params.version = SF_VERSION_001;
|
|
|
+ params->client->auth_params.version = IRIDIUM_CRYPTO_SF_VERSION_001;
|
|
|
else if (!g_strcmp0 (s, "002"))
|
|
|
- params->client->auth_params.version = SF_VERSION_002;
|
|
|
+ params->client->auth_params.version = IRIDIUM_CRYPTO_SF_VERSION_002;
|
|
|
else {
|
|
|
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
|
|
"StandardFile protocols other than 001 and 002 are not supported");
|
|
|
@@ -408,7 +240,7 @@ on_auth_params_response_parsed (GObject *object,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- derive_keys ((guint8 *) data->password, &data->client->auth_params);
|
|
|
+ iridium_crypto_derive_keys (&data->client->auth_params, data->password);
|
|
|
|
|
|
g_debug ("StandardFile parameters: version=%i func=%i hash=%i key_size=%u iterations=%u",
|
|
|
data->client->auth_params.version,
|
|
|
@@ -425,7 +257,7 @@ on_auth_params_response_parsed (GObject *object,
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- password = hexlify (data->client->auth_params.keys.password,
|
|
|
+ password = iridium_crypto_hexlify (data->client->auth_params.keys.password,
|
|
|
sizeof (data->client->auth_params.keys.password));
|
|
|
body = g_strdup_printf ("{\"email\": \"%s\", \"password\": \"%s\"}", data->client->email, password);
|
|
|
msg = soup_request_http_get_message (request);
|
|
|
@@ -457,7 +289,7 @@ on_send_auth_params_message (GObject *object,
|
|
|
}
|
|
|
|
|
|
parser = json_parser_new ();
|
|
|
- json_parser_load_from_stream_async (parser, stream, g_task_get_cancellable (task),
|
|
|
+ json_parser_load_from_stream_async (parser, stream, g_task_get_cancellable (task),
|
|
|
on_auth_params_response_parsed, task);
|
|
|
g_object_unref (object);
|
|
|
g_object_unref (stream);
|
|
|
@@ -469,7 +301,7 @@ on_sync_response_parsed (GObject *object,
|
|
|
gpointer user_data)
|
|
|
{
|
|
|
GTask *task;
|
|
|
- StandardFileAuthParams *auth_params;
|
|
|
+ IridiumAuthParams *auth_params;
|
|
|
JsonParser *parser;
|
|
|
JsonObject *root;
|
|
|
JsonArray *array;
|
|
|
@@ -491,10 +323,20 @@ on_sync_response_parsed (GObject *object,
|
|
|
for (guint i = 0; i < json_array_get_length (array); i++) {
|
|
|
JsonObject *data;
|
|
|
GObject *item;
|
|
|
+ const gchar *uuid;
|
|
|
+ const gchar *enc_item_key;
|
|
|
+ const gchar *enc_content;
|
|
|
gchar *content;
|
|
|
|
|
|
data = json_array_get_object_element (array, i);
|
|
|
- content = decrypt_item (data, auth_params);
|
|
|
+ uuid = json_object_get_string_member (data, "uuid");
|
|
|
+ enc_item_key = json_object_get_string_member (data, "enc_item_key");
|
|
|
+
|
|
|
+ if (!g_strcmp0 (enc_item_key, ""))
|
|
|
+ continue;
|
|
|
+
|
|
|
+ enc_content = json_object_get_string_member (data, "content");
|
|
|
+ content = iridium_crypto_decrypt_item (enc_content, auth_params, enc_item_key, uuid);
|
|
|
|
|
|
if (content) {
|
|
|
item = deserialize_item (data, content);
|
|
|
@@ -637,7 +479,10 @@ iridium_standard_file_dispose (GObject *object)
|
|
|
|
|
|
self = IRIDIUM_STANDARD_FILE (object);
|
|
|
g_object_unref (self->session);
|
|
|
- soup_uri_free (self->base_uri);
|
|
|
+
|
|
|
+ if (self->base_uri)
|
|
|
+ soup_uri_free (self->base_uri);
|
|
|
+
|
|
|
G_OBJECT_CLASS (iridium_standard_file_parent_class)->dispose (object);
|
|
|
}
|
|
|
|