[MOD] HMAC-based mediachecking

This commit is contained in:
LDA 2024-08-25 23:00:31 +02:00
commit 39cc04fc2e
6 changed files with 115 additions and 9 deletions

View file

@ -1,5 +1,5 @@
For the files src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile, see COPYING.CC0 For the files src/Parsee/HMAC.c, src/XML/*, tools/*, src/include/XML.h, etc/*, and Makefile,
to be present. see COPYING.CC0.
For any other file in src/, see COPYING.AGPL as the primary license. 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 As Parsee depends on Cytoplasm, its license is left here in COPYING.CYTO

View file

@ -25,8 +25,8 @@ JoinMUC(ParseeData *data, HashMap *event, char *jid, char *muc, char *name)
while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 32) while (!XMPPJoinMUC(data->jabber, jid, rev, true) && nonce < 32)
{ {
char *nonce_str = StrInt(nonce); char *nonce_str = StrInt(nonce);
char *input = StrConcat(4, sender, name, data->id, nonce_str); char *input = StrConcat(3, sender, name, nonce_str);
char *hex = ParseeSHA256(input); char *hex = ParseeHMACS(data->id, input);
if (strlen(hex) >= 8) if (strlen(hex) >= 8)
{ {

76
src/Parsee/HMAC.c Normal file
View file

@ -0,0 +1,76 @@
/* CC0 implementation of a HMAC system based on Cytoplasm.
* Ignore the scary "Parsee.h", its practically unused. */
#include <Parsee.h>
#include <Cytoplasm/Memory.h>
#include <Cytoplasm/Sha.h>
#include <Cytoplasm/Str.h>
#include <string.h>
/* 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;
}

View file

@ -667,7 +667,8 @@ ParseeToUnauth(ParseeData *data, char *mxc)
{ {
Uri *url = NULL; Uri *url = NULL;
char *ret; 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; size_t l;
if (!data || !mxc) if (!data || !mxc)
{ {
@ -684,18 +685,25 @@ ParseeToUnauth(ParseeData *data, char *mxc)
return NULL; return NULL;
} }
key = StrConcat(2, url->host, url->path);
hmac = ParseeHMACS(data->id, key);
Free(key);
l = snprintf(NULL, 0, l = snprintf(NULL, 0,
PAT, PAT,
data->config->media_base, data->config->media_base,
url->host, url->path url->host, url->path,
hmac
); );
ret = Malloc(l + 3); ret = Malloc(l + 3);
snprintf(ret, l + 1, snprintf(ret, l + 1,
PAT, PAT,
data->config->media_base, data->config->media_base,
url->host, url->path url->host, url->path,
hmac
); );
UriFree(url); UriFree(url);
Free(hmac);
return ret; return ret;
} }

View file

@ -2,27 +2,41 @@
#include <Cytoplasm/Memory.h> #include <Cytoplasm/Memory.h>
#include <Cytoplasm/Str.h> #include <Cytoplasm/Str.h>
#include <Cytoplasm/Log.h>
#include <Matrix.h> #include <Matrix.h>
#include <Parsee.h> #include <Parsee.h>
#include <AS.h> #include <AS.h>
#include <string.h>
RouteHead(RouteMedia, arr, argp) RouteHead(RouteMedia, arr, argp)
{ {
ParseeHttpArg *args = argp; ParseeHttpArg *args = argp;
HttpClientContext *cctx; HttpClientContext *cctx;
HashMap *reqh; HashMap *reqh, *params;
char *server = ArrayGet(arr, 0); char *server = ArrayGet(arr, 0);
char *identi = ArrayGet(arr, 1); char *identi = ArrayGet(arr, 1);
char *path, *key, *val; 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. /* 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); HttpResponseStatus(args->ctx, HTTP_BAD_REQUEST);
return MatrixCreateError("M_NOT_YET_UPLOADED", "No server/identifier"); return MatrixCreateError("M_NOT_YET_UPLOADED", "No server/identifier");
} }
Free(chkmak);
server = HttpUrlEncode(server); server = HttpUrlEncode(server);
identi = HttpUrlEncode(identi); identi = HttpUrlEncode(identi);

View file

@ -361,4 +361,12 @@ extern char * ParseeGenerateMTO(char *common_id);
* Modifies: the Parsee config */ * Modifies: the Parsee config */
extern void ParseeSetThreads(int xmpp, int http); 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 #endif