From 39cc04fc2eee8ee1f961169f47af81991d954ecd Mon Sep 17 00:00:00 2001 From: LDA Date: Sun, 25 Aug 2024 23:00:31 +0200 Subject: [PATCH] [MOD] HMAC-based mediachecking --- LICENSE | 4 +-- src/MatrixEventHandler.c | 4 +-- src/Parsee/HMAC.c | 76 ++++++++++++++++++++++++++++++++++++++++ src/Parsee/User.c | 14 ++++++-- src/Routes/Media.c | 18 ++++++++-- src/include/Parsee.h | 8 +++++ 6 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 src/Parsee/HMAC.c diff --git a/LICENSE b/LICENSE index 5d9765c..1e1282b 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ -For the files src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, see COPYING.CC0 -to be present. +For the files src/Parsee/HMAC.c, src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, +see COPYING.CC0. For any other file in src/, see COPYING.AGPL as the primary license. As Parsee depends on Cytoplasm, its license is left here in COPYING.CYTO diff --git a/src/MatrixEventHandler.c b/src/MatrixEventHandler.c index effcc45..247f907 100644 --- a/src/MatrixEventHandler.c +++ b/src/MatrixEventHandler.c @@ -25,8 +25,8 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name) while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 32) { char *nonce_str = StrInt(nonce); - char *input = StrConcat(4, sender, name, data->id, nonce_str); - char *hex = ParseeSHA256(input); + char *input = StrConcat(3, sender, name, nonce_str); + char *hex = ParseeHMACS(data->id, input); if (strlen(hex) >= 8) { diff --git a/src/Parsee/HMAC.c b/src/Parsee/HMAC.c new file mode 100644 index 0000000..3904ebc --- /dev/null +++ b/src/Parsee/HMAC.c @@ -0,0 +1,76 @@ +/* CC0 implementation of a HMAC system based on Cytoplasm. + * Ignore the scary "Parsee.h", its practically unused. */ +#include + +#include +#include +#include + +#include + +/* A 64-byte key! */ +static uint8_t * +ComputeKPad(char *key, uint8_t pad) +{ + size_t klen; + uint8_t *kp; + uint8_t *kopad; + size_t i; + if ((klen = strlen(key)) <= 64) + { + kp = Malloc(klen * sizeof(uint8_t)); + memcpy(kp, key, klen); + } + else + { + kp = (uint8_t *) Sha256(key); + klen = 32; + } + + /* Now that we have K', lets compute it XORd with opad */ + kopad = Malloc(64 * sizeof(uint8_t)); + for (i = 0; i < 64; i++) + { + uint8_t byte = i < klen ? kp[i] : 0x00; + kopad[i] = byte ^ pad; + } + + Free(kp); + return kopad; +} + +char * +ParseeHMAC(char *key, uint8_t *msg, size_t msglen) +{ + uint8_t *opad, *ipad; + uint8_t *innersha; + uint8_t *outer; + unsigned char *sha; + char *str; + if (!key || !msg || !msglen) + { + return NULL; + } + + opad = ComputeKPad(key, 0x5C); + + ipad = ComputeKPad(key, 0x36); + ipad = Realloc(ipad, 64 + msglen); + memcpy(ipad + 64, msg, msglen); + innersha = Sha256Raw(ipad, 64 + msglen); + + outer = Malloc(64 + 32); + memcpy(outer, opad, 64); + memcpy(outer + 64, innersha, 32); + + sha = Sha256Raw(outer, 64 + 32); + str = ShaToHex(sha, HASH_SHA256); + + Free(innersha); + Free(outer); + Free(ipad); + Free(opad); + Free(sha); + + return str; +} diff --git a/src/Parsee/User.c b/src/Parsee/User.c index f1ac101..79c8a55 100644 --- a/src/Parsee/User.c +++ b/src/Parsee/User.c @@ -667,7 +667,8 @@ ParseeToUnauth(ParseeData *data, char *mxc) { Uri *url = NULL; char *ret; -#define PAT "%s/_matrix/client/v1/media/download/%s%s" + char *key, *hmac; +#define PAT "%s/_matrix/client/v1/media/download/%s%s?hmac=%s" size_t l; if (!data || !mxc) { @@ -684,18 +685,25 @@ ParseeToUnauth(ParseeData *data, char *mxc) return NULL; } + key = StrConcat(2, url->host, url->path); + hmac = ParseeHMACS(data->id, key); + Free(key); + l = snprintf(NULL, 0, PAT, data->config->media_base, - url->host, url->path + url->host, url->path, + hmac ); ret = Malloc(l + 3); snprintf(ret, l + 1, PAT, data->config->media_base, - url->host, url->path + url->host, url->path, + hmac ); UriFree(url); + Free(hmac); return ret; } diff --git a/src/Routes/Media.c b/src/Routes/Media.c index 45d79d0..137ef0f 100644 --- a/src/Routes/Media.c +++ b/src/Routes/Media.c @@ -2,27 +2,41 @@ #include #include +#include #include #include #include +#include + RouteHead(RouteMedia, arr, argp) { ParseeHttpArg *args = argp; HttpClientContext *cctx; - HashMap *reqh; + HashMap *reqh, *params; char *server = ArrayGet(arr, 0); char *identi = ArrayGet(arr, 1); char *path, *key, *val; + char *hmac, *chkmak = NULL; + + params = HttpRequestParams(args->ctx); + hmac = HashMapGet(params, "hmac"); /* TODO: Make it check the DB for its validicity. "Purging" would be useful. */ - if (!server || !identi) { + char *concat = StrConcat(3, server, "/", identi); + chkmak = ParseeHMACS(args->data->id, concat); + Free(concat); + } + if (!server || !identi || !hmac || !StrEquals(hmac, chkmak)) + { + Free(chkmak); HttpResponseStatus(args->ctx, HTTP_BAD_REQUEST); return MatrixCreateError("M_NOT_YET_UPLOADED", "No server/identifier"); } + Free(chkmak); server = HttpUrlEncode(server); identi = HttpUrlEncode(identi); diff --git a/src/include/Parsee.h b/src/include/Parsee.h index e27fc76..8182675 100644 --- a/src/include/Parsee.h +++ b/src/include/Parsee.h @@ -361,4 +361,12 @@ extern char * ParseeGenerateMTO(char *common_id); * Modifies: the Parsee config */ extern void ParseeSetThreads(int xmpp, int http); +/** Computes an HMAC (with SHA-256) with a known key, and a generic message. + * -------------- + * Returns: a hex representation of the HMAC[HEAP]. + * Thrasher: Free + * Modifies: NOTHING */ +extern char * ParseeHMAC(char *key, uint8_t *msg, size_t msglen); +#define ParseeHMACS(key, msg) ParseeHMAC(key, (uint8_t *) msg, strlen(msg)) + #endif