fishlim: Implement CBC mode in /setkey and /keyx
display information from cipher mode to the user keep backward compatibility
This commit is contained in:
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
Reference in New Issue
Block a user