From 73f313b9212d652fecb13bcb82a0f162abb897a0 Mon Sep 17 00:00:00 2001 From: William Wennerström Date: Mon, 20 Jul 2020 22:49:50 +0200 Subject: Refactor OMEMO download into AESGCMDownload tool --- src/omemo/omemo.c | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 7 deletions(-) (limited to 'src/omemo/omemo.c') diff --git a/src/omemo/omemo.c b/src/omemo/omemo.c index e08d3f06..e19b724e 100644 --- a/src/omemo/omemo.c +++ b/src/omemo/omemo.c @@ -62,6 +62,9 @@ #include "xmpp/roster_list.h" #include "xmpp/xmpp.h" +#define AESGCM_URL_NONCE_LEN (2 * OMEMO_AESGCM_NONCE_LENGTH) +#define AESGCM_URL_KEY_LEN (2 * OMEMO_AESGCM_KEY_LENGTH) + static gboolean loaded; static void _generate_pre_keys(int count); @@ -1664,12 +1667,12 @@ char* omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res) { unsigned char* key = gcry_random_bytes_secure( - AES256_GCM_KEY_LENGTH, + OMEMO_AESGCM_KEY_LENGTH, GCRY_VERY_STRONG_RANDOM); // Create nonce/IV with random bytes. - unsigned char nonce[AES256_GCM_NONCE_LENGTH]; - gcry_create_nonce(nonce, AES256_GCM_NONCE_LENGTH); + unsigned char nonce[OMEMO_AESGCM_NONCE_LENGTH]; + gcry_create_nonce(nonce, OMEMO_AESGCM_NONCE_LENGTH); char* fragment = aes256gcm_create_secure_fragment(key, nonce); *gcry_res = aes256gcm_crypt_file(in, out, file_size, key, nonce, true); @@ -1684,7 +1687,96 @@ omemo_encrypt_file(FILE* in, FILE* out, off_t file_size, int* gcry_res) return fragment; } -//int omemo_decrypt_file(FILE *in, FILE *out, off_t file_size, -// unsigned char key[], unsigned char nonce[]) { -// return aes256gcm_crypt_file(in, out, file_size, key, nonce, false); -//} +void +_bytes_from_hex(const char* hex, size_t hex_size, + unsigned char* bytes, size_t bytes_size) +{ + const unsigned char ht[] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, // 01234567 + 0x08, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 89:;<=>? + 0x00, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x00, // @ABCDEFG + }; + const size_t ht_size = sizeof(ht); + + unsigned char b0; + unsigned char b1; + + memset(bytes, 0, bytes_size); + + for (int i = 0; (i < hex_size) && (i / 2 < bytes_size); i += 2) { + b0 = ((unsigned char)hex[i + 0] & 0x1f) ^ 0x10; + b1 = ((unsigned char)hex[i + 1] & 0x1f) ^ 0x10; + + if (b0 <= ht_size && b1 <= ht_size) { + bytes[i / 2] = (unsigned char)(ht[b0] << 4) | ht[b1]; + } + } +} + +int +omemo_decrypt_file(FILE* in, FILE* out, off_t file_size, const char* fragment) +{ + char nonce_hex[AESGCM_URL_NONCE_LEN]; + char key_hex[AESGCM_URL_KEY_LEN]; + + const int nonce_pos = 0; + const int key_pos = AESGCM_URL_NONCE_LEN; + + memcpy(nonce_hex, &(fragment[nonce_pos]), AESGCM_URL_NONCE_LEN); + memcpy(key_hex, &(fragment[key_pos]), AESGCM_URL_KEY_LEN); + + unsigned char nonce[OMEMO_AESGCM_NONCE_LENGTH]; + unsigned char* key = gcry_malloc_secure(OMEMO_AESGCM_KEY_LENGTH); + + _bytes_from_hex(nonce_hex, AESGCM_URL_NONCE_LEN, + nonce, OMEMO_AESGCM_NONCE_LENGTH); + _bytes_from_hex(key_hex, AESGCM_URL_KEY_LEN, + key, OMEMO_AESGCM_KEY_LENGTH); + + int crypt_res = aes256gcm_crypt_file(in, out, file_size, key, nonce, false); + + gcry_free(key); + + return crypt_res; +} + +int +omemo_parse_aesgcm_url(const char* aesgcm_url, + char** https_url, + char** fragment) +{ + CURLUcode ret; + CURLU* url = curl_url(); + + // Required to allow for the "aesgcm://" scheme that OMEMO Media Sharing + // uses. + unsigned int curl_flags = CURLU_NON_SUPPORT_SCHEME; + + ret = curl_url_set(url, CURLUPART_URL, aesgcm_url, curl_flags); + if (ret) { + goto out; + } + + ret = curl_url_get(url, CURLUPART_FRAGMENT, fragment, curl_flags); + if (ret) { + goto out; + } + + if (strlen(*fragment) != AESGCM_URL_NONCE_LEN + AESGCM_URL_KEY_LEN) { + goto out; + } + + ret = curl_url_set(url, CURLUPART_SCHEME, "https", curl_flags); + if (ret) { + goto out; + } + + ret = curl_url_get(url, CURLUPART_URL, https_url, curl_flags); + if (ret) { + goto out; + } + +out: + curl_url_cleanup(url); + return ret; +} -- cgit 1.4.1-2-gfad0