From 76d74c8234ebf587dc97710f136b830315ea3ba4 Mon Sep 17 00:00:00 2001 From: BakasuraRCE Date: Sun, 26 May 2019 00:46:37 -0500 Subject: [PATCH] fishlim: Implement CBC mode in /setkey and /keyx display information from cipher mode to the user keep backward compatibility --- plugins/fishlim/fish.c | 40 +++++++++++++++++++++-------- plugins/fishlim/keystore.c | 28 +++++++++++++++----- plugins/fishlim/keystore.h | 4 +-- plugins/fishlim/plugin_hexchat.c | 44 +++++++++++++++++--------------- 4 files changed, 76 insertions(+), 40 deletions(-) diff --git a/plugins/fishlim/fish.c b/plugins/fishlim/fish.c index 20049e01..f59c5ebe 100644 --- a/plugins/fishlim/fish.c +++ b/plugins/fishlim/fish.c @@ -341,17 +341,31 @@ char *fish_decrypt(const char *key, size_t keylen, const char *data, int mode) { */ char *fish_encrypt_for_nick(const char *nick, const char *data) { char *key; - char *encrypted; + char *encrypted, *encrypted_cbc = NULL; + int mode; + int encrypted_len = 0; /* Look for key */ - key = keystore_get_key(nick); + key = keystore_get_key(nick, &mode); if (!key) return NULL; - + /* Encrypt */ - encrypted = fish_encrypt(key, strlen(key), data, strlen(data), FISH_ECB_MODE); - + encrypted = fish_encrypt(key, strlen(key), data, strlen(data), mode); + g_free(key); - return encrypted; + + if (encrypted == NULL || mode == FISH_ECB_MODE) + return encrypted; + + /* Add '*' for CBC */ + encrypted_len = strlen(encrypted); + encrypted_cbc = g_malloc0(encrypted_len + 2); + *encrypted_cbc = '*'; + + memcpy(&encrypted_cbc[1], encrypted, encrypted_len); + g_free(encrypted); + + return encrypted_cbc; } /** @@ -361,14 +375,20 @@ char *fish_encrypt_for_nick(const char *nick, const char *data) { char *fish_decrypt_from_nick(const char *nick, const char *data) { char *key; char *decrypted; + int mode; + /* Look for key */ - key = keystore_get_key(nick); + key = keystore_get_key(nick, &mode); if (!key) return NULL; - + + if (mode == FISH_CBC_MODE) + ++data; + /* Decrypt */ - decrypted = fish_decrypt(key, strlen(key), data, FISH_ECB_MODE); - + decrypted = fish_decrypt(key, strlen(key), data, mode); + g_free(key); + return decrypted; } diff --git a/plugins/fishlim/keystore.c b/plugins/fishlim/keystore.c index 6ddd5087..70779ff4 100644 --- a/plugins/fishlim/keystore.c +++ b/plugins/fishlim/keystore.c @@ -103,11 +103,11 @@ static gchar *get_nick_value(GKeyFile *keyfile, const char *nick, const char *it /** * Extracts a key from the key store file. */ -char *keystore_get_key(const char *nick) { +char *keystore_get_key(const char *nick, int *mode) { GKeyFile *keyfile; char *escaped_nick; - gchar *value; - int mode; + gchar *value, *key_mode; + int encrypted_mode; char *password; char *encrypted; char *decrypted; @@ -116,9 +116,20 @@ char *keystore_get_key(const char *nick) { keyfile = getConfigFile(); escaped_nick = escape_nickname(nick); value = get_nick_value(keyfile, escaped_nick, "key"); + key_mode = get_nick_value(keyfile, escaped_nick, "mode"); g_key_file_free(keyfile); g_free(escaped_nick); + /* Determine cipher mode */ + *mode = FISH_ECB_MODE; + if (key_mode) { + if (*key_mode == '1') + *mode = FISH_ECB_MODE; + else if (*key_mode == '2') + *mode = FISH_CBC_MODE; + g_free(key_mode); + } + if (!value) return NULL; @@ -127,15 +138,15 @@ char *keystore_get_key(const char *nick) { encrypted = (char *) value; encrypted += 4; - mode = FISH_ECB_MODE; + encrypted_mode = FISH_ECB_MODE; if (*encrypted == '*') { ++encrypted; - mode = FISH_CBC_MODE; + encrypted_mode = FISH_CBC_MODE; } password = (char *) get_keystore_password(); - decrypted = fish_decrypt((const char *) password, strlen(password), (const char *) encrypted, mode); + decrypted = fish_decrypt((const char *) password, strlen(password), (const char *) encrypted, encrypted_mode); g_free(value); return decrypted; } else { @@ -206,7 +217,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS /** * Sets a key in the key store file. */ -gboolean keystore_store_key(const char *nick, const char *key) { +gboolean keystore_store_key(const char *nick, const char *key, int mode) { const char *password; char *encrypted; char *wrapped; @@ -235,6 +246,9 @@ gboolean keystore_store_key(const char *nick, const char *key) { /* Store unencrypted in file */ g_key_file_set_string(keyfile, escaped_nick, "key", key); } + + /* Store cipher mode */ + g_key_file_set_integer(keyfile, escaped_nick, "mode", mode); /* Save key store file */ ok = save_keystore(keyfile); diff --git a/plugins/fishlim/keystore.h b/plugins/fishlim/keystore.h index 3d90606a..95ae651c 100644 --- a/plugins/fishlim/keystore.h +++ b/plugins/fishlim/keystore.h @@ -29,8 +29,8 @@ #include -char *keystore_get_key(const char *nick); -gboolean keystore_store_key(const char *nick, const char *key); +char *keystore_get_key(const char *nick, int *mode); +gboolean keystore_store_key(const char *nick, const char *key, int mode); gboolean keystore_delete_nick(const char *nick); #endif diff --git a/plugins/fishlim/plugin_hexchat.c b/plugins/fishlim/plugin_hexchat.c index 3eaad986..8677b6a7 100644 --- a/plugins/fishlim/plugin_hexchat.c +++ b/plugins/fishlim/plugin_hexchat.c @@ -37,11 +37,13 @@ #include "keystore.h" #include "irc.h" +static const char *fish_modes[] = {"", "ECB", "CBC", NULL}; + static const char plugin_name[] = "FiSHLiM"; static const char plugin_desc[] = "Encryption plugin for the FiSH protocol. Less is More!"; static const char plugin_version[] = "0.1.0"; -static const char usage_setkey[] = "Usage: SETKEY [] , sets the key for a channel or nick"; +static const char usage_setkey[] = "Usage: SETKEY [] [:], sets the key for a channel or nick. Modes: ECB, CBC"; static const char usage_delkey[] = "Usage: DELKEY , deletes the key for a channel or nick"; static const char usage_keyx[] = "Usage: KEYX [], performs DH1080 key-exchange with "; static const char usage_topic[] = "Usage: TOPIC+ , sets a new encrypted topic for the current channel"; @@ -236,8 +238,8 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) { const char *dh_pubkey = word[5]; hexchat_context *query_ctx; const char *prefix; - gboolean cbc; char *sender, *secret_key, *priv_key = NULL; + int mode = FISH_ECB_MODE; if (!*dh_message || !*dh_pubkey || strlen(dh_pubkey) != 181) return HEXCHAT_EAT_NONE; @@ -254,19 +256,15 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) { if (*dh_message == '+' || *dh_message == '-') dh_message++; /* identify-msg */ - cbc = g_strcmp0 (word[6], "CBC") == 0; + if (g_strcmp0 (word[6], "CBC") == 0) + mode = FISH_CBC_MODE; if (!strcmp(dh_message, "DH1080_INIT")) { char *pub_key; - if (cbc) { - hexchat_print(ph, "Received key exchange for CBC mode which is not supported."); - goto cleanup; - } - - hexchat_printf(ph, "Received public key from %s, sending mine...", sender); + hexchat_printf(ph, "Received public key from %s (%s), sending mine...", sender, fish_modes[mode]); if (dh1080_generate_key(&priv_key, &pub_key)) { - hexchat_commandf(ph, "quote NOTICE %s :DH1080_FINISH %s", sender, pub_key); + hexchat_commandf(ph, "quote NOTICE %s :DH1080_FINISH %s%s", sender, pub_key, (mode == FISH_CBC_MODE) ? " CBC" : ""); g_free(pub_key); } else { hexchat_print(ph, "Failed to generate keys"); @@ -279,11 +277,6 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) { g_hash_table_steal(pending_exchanges, sender_lower); g_free(sender_lower); - if (cbc) { - hexchat_print(ph, "Received key exchange for CBC mode which is not supported."); - goto cleanup; - } - if (!priv_key) { hexchat_printf(ph, "Received a key exchange response for unknown user: %s", sender); goto cleanup; @@ -295,8 +288,8 @@ static int handle_keyx_notice(char *word[], char *word_eol[], void *userdata) { } if (dh1080_compute_key(priv_key, dh_pubkey, &secret_key)) { - keystore_store_key(sender, secret_key); - hexchat_printf(ph, "Stored new key for %s", sender); + keystore_store_key(sender, secret_key, mode); + hexchat_printf(ph, "Stored new key for %s (%s)", sender, fish_modes[mode]); g_free(secret_key); } else { hexchat_print(ph, "Failed to create secret key!"); @@ -314,6 +307,7 @@ cleanup: static int handle_setkey(char *word[], char *word_eol[], void *userdata) { const char *nick; const char *key; + int mode; /* Check syntax */ if (*word[2] == '\0') { @@ -331,9 +325,17 @@ static int handle_setkey(char *word[], char *word_eol[], void *userdata) { key = word_eol[3]; } + mode = FISH_ECB_MODE; + if (!strncmp("cbc:", key, 4) || !strncmp("CBC:", key, 4)) { + key = key+4; + mode = FISH_CBC_MODE; + } else if (!strncmp("ecb:", key, 4) || !strncmp("ECB:", key, 4)) { + key = key+4; + } + /* Set password */ - if (keystore_store_key(nick, key)) { - hexchat_printf(ph, "Stored key for %s\n", nick); + if (keystore_store_key(nick, key, mode)) { + hexchat_printf(ph, "Stored key for %s (%s)\n", nick, fish_modes[mode]); } else { hexchat_printf(ph, "\00305Failed to store key in addon_fishlim.conf\n"); } @@ -391,8 +393,8 @@ static int handle_keyx(char *word[], char *word_eol[], void *userdata) { if (dh1080_generate_key(&priv_key, &pub_key)) { g_hash_table_replace (pending_exchanges, g_ascii_strdown(target, -1), priv_key); - hexchat_commandf(ph, "quote NOTICE %s :DH1080_INIT %s", target, pub_key); - hexchat_printf(ph, "Sent public key to %s, waiting for reply...", target); + hexchat_commandf(ph, "quote NOTICE %s :DH1080_INIT %s CBC", target, pub_key); + hexchat_printf(ph, "Sent public key to %s (CBC), waiting for reply...", target); g_free(pub_key); } else {