fishlim: Implement CBC mode in /setkey and /keyx

display information from cipher mode to the user
keep backward compatibility
This commit is contained in:
BakasuraRCE
2019-05-26 00:46:37 -05:00
parent 397ea869a7
commit 76d74c8234
4 changed files with 76 additions and 40 deletions

View File

@ -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 *fish_encrypt_for_nick(const char *nick, const char *data) {
char *key; char *key;
char *encrypted; char *encrypted, *encrypted_cbc = NULL;
int mode;
int encrypted_len = 0;
/* Look for key */ /* Look for key */
key = keystore_get_key(nick); key = keystore_get_key(nick, &mode);
if (!key) return NULL; if (!key) return NULL;
/* Encrypt */ /* 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); 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 *fish_decrypt_from_nick(const char *nick, const char *data) {
char *key; char *key;
char *decrypted; char *decrypted;
int mode;
/* Look for key */ /* Look for key */
key = keystore_get_key(nick); key = keystore_get_key(nick, &mode);
if (!key) return NULL; if (!key) return NULL;
if (mode == FISH_CBC_MODE)
++data;
/* Decrypt */ /* Decrypt */
decrypted = fish_decrypt(key, strlen(key), data, FISH_ECB_MODE); decrypted = fish_decrypt(key, strlen(key), data, mode);
g_free(key); g_free(key);
return decrypted; return decrypted;
} }

View File

@ -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. * 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; GKeyFile *keyfile;
char *escaped_nick; char *escaped_nick;
gchar *value; gchar *value, *key_mode;
int mode; int encrypted_mode;
char *password; char *password;
char *encrypted; char *encrypted;
char *decrypted; char *decrypted;
@ -116,9 +116,20 @@ char *keystore_get_key(const char *nick) {
keyfile = getConfigFile(); keyfile = getConfigFile();
escaped_nick = escape_nickname(nick); escaped_nick = escape_nickname(nick);
value = get_nick_value(keyfile, escaped_nick, "key"); value = get_nick_value(keyfile, escaped_nick, "key");
key_mode = get_nick_value(keyfile, escaped_nick, "mode");
g_key_file_free(keyfile); g_key_file_free(keyfile);
g_free(escaped_nick); 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) if (!value)
return NULL; return NULL;
@ -127,15 +138,15 @@ char *keystore_get_key(const char *nick) {
encrypted = (char *) value; encrypted = (char *) value;
encrypted += 4; encrypted += 4;
mode = FISH_ECB_MODE; encrypted_mode = FISH_ECB_MODE;
if (*encrypted == '*') { if (*encrypted == '*') {
++encrypted; ++encrypted;
mode = FISH_CBC_MODE; encrypted_mode = FISH_CBC_MODE;
} }
password = (char *) get_keystore_password(); 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); g_free(value);
return decrypted; return decrypted;
} else { } else {
@ -206,7 +217,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
/** /**
* Sets a key in the key store file. * 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; const char *password;
char *encrypted; char *encrypted;
char *wrapped; char *wrapped;
@ -235,6 +246,9 @@ gboolean keystore_store_key(const char *nick, const char *key) {
/* Store unencrypted in file */ /* Store unencrypted in file */
g_key_file_set_string(keyfile, escaped_nick, "key", key); 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 */ /* Save key store file */
ok = save_keystore(keyfile); ok = save_keystore(keyfile);

View File

@ -29,8 +29,8 @@
#include <glib.h> #include <glib.h>
char *keystore_get_key(const char *nick); char *keystore_get_key(const char *nick, int *mode);
gboolean keystore_store_key(const char *nick, const char *key); gboolean keystore_store_key(const char *nick, const char *key, int mode);
gboolean keystore_delete_nick(const char *nick); gboolean keystore_delete_nick(const char *nick);
#endif #endif

View File

@ -37,11 +37,13 @@
#include "keystore.h" #include "keystore.h"
#include "irc.h" #include "irc.h"
static const char *fish_modes[] = {"", "ECB", "CBC", NULL};
static const char plugin_name[] = "FiSHLiM"; static const char plugin_name[] = "FiSHLiM";
static const char plugin_desc[] = "Encryption plugin for the FiSH protocol. Less is More!"; 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 plugin_version[] = "0.1.0";
static const char usage_setkey[] = "Usage: SETKEY [<nick or #channel>] <password>, sets the key for a channel or nick"; static const char usage_setkey[] = "Usage: SETKEY [<nick or #channel>] [<mode>:]<password>, sets the key for a channel or nick. Modes: ECB, CBC";
static const char usage_delkey[] = "Usage: DELKEY <nick or #channel>, deletes the key for a channel or nick"; static const char usage_delkey[] = "Usage: DELKEY <nick or #channel>, deletes the key for a channel or nick";
static const char usage_keyx[] = "Usage: KEYX [<nick>], performs DH1080 key-exchange with <nick>"; static const char usage_keyx[] = "Usage: KEYX [<nick>], performs DH1080 key-exchange with <nick>";
static const char usage_topic[] = "Usage: TOPIC+ <topic>, sets a new encrypted topic for the current channel"; static const char usage_topic[] = "Usage: TOPIC+ <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]; const char *dh_pubkey = word[5];
hexchat_context *query_ctx; hexchat_context *query_ctx;
const char *prefix; const char *prefix;
gboolean cbc;
char *sender, *secret_key, *priv_key = NULL; char *sender, *secret_key, *priv_key = NULL;
int mode = FISH_ECB_MODE;
if (!*dh_message || !*dh_pubkey || strlen(dh_pubkey) != 181) if (!*dh_message || !*dh_pubkey || strlen(dh_pubkey) != 181)
return HEXCHAT_EAT_NONE; 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 == '-') if (*dh_message == '+' || *dh_message == '-')
dh_message++; /* identify-msg */ 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")) { if (!strcmp(dh_message, "DH1080_INIT")) {
char *pub_key; char *pub_key;
if (cbc) { hexchat_printf(ph, "Received public key from %s (%s), sending mine...", sender, fish_modes[mode]);
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);
if (dh1080_generate_key(&priv_key, &pub_key)) { 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); g_free(pub_key);
} else { } else {
hexchat_print(ph, "Failed to generate keys"); 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_hash_table_steal(pending_exchanges, sender_lower);
g_free(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) { if (!priv_key) {
hexchat_printf(ph, "Received a key exchange response for unknown user: %s", sender); hexchat_printf(ph, "Received a key exchange response for unknown user: %s", sender);
goto cleanup; 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)) { if (dh1080_compute_key(priv_key, dh_pubkey, &secret_key)) {
keystore_store_key(sender, secret_key); keystore_store_key(sender, secret_key, mode);
hexchat_printf(ph, "Stored new key for %s", sender); hexchat_printf(ph, "Stored new key for %s (%s)", sender, fish_modes[mode]);
g_free(secret_key); g_free(secret_key);
} else { } else {
hexchat_print(ph, "Failed to create secret key!"); hexchat_print(ph, "Failed to create secret key!");
@ -314,6 +307,7 @@ cleanup:
static int handle_setkey(char *word[], char *word_eol[], void *userdata) { static int handle_setkey(char *word[], char *word_eol[], void *userdata) {
const char *nick; const char *nick;
const char *key; const char *key;
int mode;
/* Check syntax */ /* Check syntax */
if (*word[2] == '\0') { if (*word[2] == '\0') {
@ -331,9 +325,17 @@ static int handle_setkey(char *word[], char *word_eol[], void *userdata) {
key = word_eol[3]; 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 */ /* Set password */
if (keystore_store_key(nick, key)) { if (keystore_store_key(nick, key, mode)) {
hexchat_printf(ph, "Stored key for %s\n", nick); hexchat_printf(ph, "Stored key for %s (%s)\n", nick, fish_modes[mode]);
} else { } else {
hexchat_printf(ph, "\00305Failed to store key in addon_fishlim.conf\n"); 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)) { if (dh1080_generate_key(&priv_key, &pub_key)) {
g_hash_table_replace (pending_exchanges, g_ascii_strdown(target, -1), priv_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_commandf(ph, "quote NOTICE %s :DH1080_INIT %s CBC", target, pub_key);
hexchat_printf(ph, "Sent public key to %s, waiting for reply...", target); hexchat_printf(ph, "Sent public key to %s (CBC), waiting for reply...", target);
g_free(pub_key); g_free(pub_key);
} else { } else {