From f6f41a510b50661388303a0a04c49ddae793f4be Mon Sep 17 00:00:00 2001 From: jfreegman Date: Sun, 23 Jan 2022 11:32:57 -0500 Subject: [PATCH] Add some simple impersonation detection on friend requests This will alert the user when the first six bytes of a new contact's public key is the same as any other contact in their list. These 6 bytes are used elsewhere in toxic for unique identification. Also did a small refactor regarding the KEY_IDENT_BYTES define --- src/chat.c | 8 ++++---- src/log.c | 8 ++++---- src/prompt.c | 31 ++++++++++++++++++++++++++++--- src/toxic.h | 2 +- 4 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/chat.c b/src/chat.c index 573e77b..d9641ed 100644 --- a/src/chat.c +++ b/src/chat.c @@ -1385,7 +1385,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m) self->x = x2; /* Truncate note if it doesn't fit in statusbar */ - size_t maxlen = x2 - getcurx(statusbar->topline) - (KEY_IDENT_DIGITS * 2) - 6; + size_t maxlen = x2 - getcurx(statusbar->topline) - KEY_IDENT_BYTES - 6; pthread_mutex_lock(&Winthread.lock); size_t statusmsg_len = statusbar->statusmsg_len; @@ -1416,10 +1416,10 @@ static void chat_onDraw(ToxWindow *self, Tox *m) int s_x; getyx(statusbar->topline, s_y, s_x); - mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - (KEY_IDENT_DIGITS * 2) - 3); + mvwhline(statusbar->topline, s_y, s_x, ' ', x2 - s_x - KEY_IDENT_BYTES - 3); wattroff(statusbar->topline, COLOR_PAIR(BAR_TEXT)); - wmove(statusbar->topline, 0, x2 - (KEY_IDENT_DIGITS * 2) - 3); + wmove(statusbar->topline, 0, x2 - KEY_IDENT_BYTES - 3); wattron(statusbar->topline, COLOR_PAIR(BAR_ACCENT)); wprintw(statusbar->topline, "{"); @@ -1427,7 +1427,7 @@ static void chat_onDraw(ToxWindow *self, Tox *m) wattron(statusbar->topline, COLOR_PAIR(BAR_TEXT)); - for (size_t i = 0; i < KEY_IDENT_DIGITS; ++i) { + for (size_t i = 0; i < KEY_IDENT_BYTES / 2; ++i) { wprintw(statusbar->topline, "%02X", Friends.list[self->num].pub_key[i] & 0xff); } diff --git a/src/log.c b/src/log.c index bcbd7b1..15547ab 100644 --- a/src/log.c +++ b/src/log.c @@ -62,21 +62,21 @@ static int get_log_path(char *dest, int destsize, const char *name, const char * /* first 6 bytes of selfkey */ char self_id[32] = {0}; - path_len += KEY_IDENT_DIGITS * 2; + path_len += KEY_IDENT_BYTES; sprintf(&self_id[0], "%02X", selfkey[0] & 0xff); sprintf(&self_id[2], "%02X", selfkey[1] & 0xff); sprintf(&self_id[4], "%02X", selfkey[2] & 0xff); - self_id[KEY_IDENT_DIGITS * 2] = '\0'; + self_id[KEY_IDENT_BYTES] = '\0'; char other_id[32] = {0}; if (otherkey) { /* first 6 bytes of otherkey */ - path_len += KEY_IDENT_DIGITS * 2; + path_len += KEY_IDENT_BYTES; sprintf(&other_id[0], "%02X", otherkey[0] & 0xff); sprintf(&other_id[2], "%02X", otherkey[1] & 0xff); sprintf(&other_id[4], "%02X", otherkey[2] & 0xff); - other_id[KEY_IDENT_DIGITS * 2] = '\0'; + other_id[KEY_IDENT_BYTES] = '\0'; } if (path_len >= destsize) { diff --git a/src/prompt.c b/src/prompt.c index 1b084d5..9f35b8f 100644 --- a/src/prompt.c +++ b/src/prompt.c @@ -175,9 +175,7 @@ static int add_friend_request(const char *public_key, const char *data) return -1; } - int i; - - for (i = 0; i <= FrndRequests.max_idx; ++i) { + for (int i = 0; i <= FrndRequests.max_idx; ++i) { if (!FrndRequests.request[i].active) { FrndRequests.request[i].active = true; memcpy(FrndRequests.request[i].key, public_key, TOX_PUBLIC_KEY_SIZE); @@ -526,6 +524,26 @@ static void prompt_onConnectionChange(ToxWindow *self, Tox *m, uint32_t friendnu } } +/** + * Return true is the first 3 bytes of `key` are identical to any other contact in the contact list. + */ +static bool key_is_similar(const char *key) +{ + for (size_t i = 0; i < Friends.max_idx; ++i) { + const ToxicFriend *friend = &Friends.list[i]; + + if (!friend->active) { + continue; + } + + if (memcmp(friend->pub_key, key, KEY_IDENT_BYTES / 2) == 0) { + return true; + } + } + + return false; +} + static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, const char *data, size_t length) { UNUSED_VAR(m); @@ -536,6 +554,13 @@ static void prompt_onFriendRequest(ToxWindow *self, Tox *m, const char *key, con line_info_add(self, true, NULL, NULL, SYS_MSG, 0, 0, "Friend request with the message '%s'", data); write_to_log("Friend request with the message '%s'", "", ctx->log, true); + if (key_is_similar(key)) { + line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, + "WARNING: This contact's public key is suspiciously similar to that of another contact "); + line_info_add(self, false, NULL, NULL, SYS_MSG, 0, RED, + "in your list. This may be an impersonation attempt, or it may have occurred by chance."); + } + int n = add_friend_request(key, data); if (n == -1) { diff --git a/src/toxic.h b/src/toxic.h index d2f6a74..b914912 100644 --- a/src/toxic.h +++ b/src/toxic.h @@ -46,7 +46,7 @@ #define MAX_STR_SIZE TOX_MAX_MESSAGE_LENGTH /* must be >= TOX_MAX_MESSAGE_LENGTH */ #define MAX_CMDNAME_SIZE 64 #define TOXIC_MAX_NAME_LENGTH 32 /* Must be <= TOX_MAX_NAME_LENGTH */ -#define KEY_IDENT_DIGITS 3 /* number of hex digits to display for the pub-key based identifier */ +#define KEY_IDENT_BYTES 6 /* number of hex digits to display for the public key identifier */ #define TIME_STR_SIZE 32 #define COLOR_STR_SIZE 10 /* should fit every color option */