Merge branch 'cbc'
This commit is contained in:
commit
7e5ecc68fe
11
README
11
README
|
@ -2,8 +2,8 @@ Introduction
|
|||
============
|
||||
|
||||
This is an encryption add-on for irssi, it's based on blowfish. It
|
||||
supports private messages and channel encryption. It also includes a
|
||||
secure key-exchange system.
|
||||
supports private messages and channel encryption in ECB and CBC
|
||||
modes. It also includes a secure key-exchange system.
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
@ -148,7 +148,7 @@ Send a FiSHed action to the current window.
|
|||
/setkey [servertag] [nick / #channel] <key>
|
||||
|
||||
Sets the key used to FiSH the messages for the current window or to the
|
||||
specified target.
|
||||
specified target. To use CBC mode, prefix the key with "cbc:".
|
||||
|
||||
/delkey [servertag] [nick/#channel]
|
||||
|
||||
|
@ -160,9 +160,10 @@ the specified target.
|
|||
Shows the used key to FiSH the messages for the current window or to the
|
||||
specified target. The key will appear in the target window.
|
||||
|
||||
/keyx
|
||||
/keyx [-ecb] [nick]
|
||||
|
||||
Forces a DH key exchange in the current window.
|
||||
Forces a DH key exchange in the current window or to the specified
|
||||
target. The default mode is CBC, use "-ecb" to use ECB Mode.
|
||||
|
||||
/setinipw <password>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Introduction
|
||||
|
||||
This is an encryption add-on for irssi, it's based on blowfish. It supports private messages and channel encryption. It also includes a secure key-exchange system.
|
||||
This is an encryption add-on for irssi, it's based on blowfish. It supports private messages and channel encryption in **ECB** and **CBC** modes. It also includes a secure key-exchange system.
|
||||
|
||||
# Requirements
|
||||
|
||||
|
@ -161,7 +161,7 @@ Send a FiSHed action to the current window.
|
|||
```
|
||||
/setkey [servertag] [nick / #channel] <key>
|
||||
```
|
||||
Sets the key used to FiSH the messages for the current window or to the specified target.
|
||||
Sets the key used to FiSH the messages for the current window or to the specified target. To use CBC mode, prefix the key with "cbc:".
|
||||
|
||||
```
|
||||
/delkey [servertag] [nick/#channel]
|
||||
|
@ -174,9 +174,9 @@ Unsets the key used to FiSH the messages for the current window or to the specif
|
|||
Shows the used key to FiSH the messages for the current window or to the specified target. The key will appear in the target window.
|
||||
|
||||
```
|
||||
/keyx
|
||||
/keyx [-ecb] [nick]
|
||||
```
|
||||
Forces a DH key exchange in the current window.
|
||||
Forces a DH key exchange in the current window or to the specified target. The default mode is CBC, use "-ecb" to use ECB Mode.
|
||||
|
||||
```
|
||||
/setinipw <password>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/FiSH_version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/FiSH_version.h)
|
||||
|
||||
ADD_LIBRARY(fish MODULE base64.c blowfish.c inifile.c DH1080.c FiSH.c password.c)
|
||||
ADD_LIBRARY(fish MODULE base64.c blowfish.c blowfish_cbc.c inifile.c DH1080.c FiSH.c password.c)
|
||||
TARGET_LINK_LIBRARIES(fish crypto glib-2.0)
|
||||
|
||||
if (APPLE)
|
||||
|
|
236
src/FiSH.c
236
src/FiSH.c
|
@ -18,7 +18,7 @@ int getContactKey(const char *contactPtr, char *theKey)
|
|||
int bRet = FALSE;
|
||||
|
||||
iniValue = allocateIni(contactPtr, "key", iniPath);
|
||||
getIniValue(contactPtr, "key", "", iniValue.key, iniValue.iniKeySize, iniPath);
|
||||
getIniValue(contactPtr, "key", "", iniValue.key, iniValue.keySize, iniPath);
|
||||
|
||||
// don't process, encrypted key not found in ini
|
||||
if (strlen(iniValue.key) < 16) {
|
||||
|
@ -29,11 +29,9 @@ int getContactKey(const char *contactPtr, char *theKey)
|
|||
// encrypted key found
|
||||
if (strncmp(iniValue.key, "+OK ", 4) == 0) {
|
||||
if (theKey) {
|
||||
// if it's not just a test, lets decrypt the key
|
||||
decrypt_string((char *)iniKey, iniValue.key + 4, theKey,
|
||||
strlen(iniValue.key + 4));
|
||||
}
|
||||
|
||||
bRet = TRUE;
|
||||
}
|
||||
|
||||
|
@ -110,8 +108,13 @@ int FiSH_encrypt(const SERVER_REC * serverRec, const char *msgPtr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
strcpy(bf_dest, "+OK ");
|
||||
encrypt_string(iniValue.key, msgPtr, bf_dest + 4, strlen(msgPtr));
|
||||
if (iniValue.cbc == 1) {
|
||||
strcpy(bf_dest, "+OK *");
|
||||
encrypt_string_cbc(iniValue.key, msgPtr, bf_dest + 5, strlen(msgPtr));
|
||||
} else {
|
||||
strcpy(bf_dest, "+OK ");
|
||||
encrypt_string(iniValue.key, msgPtr, bf_dest + 4, strlen(msgPtr));
|
||||
}
|
||||
|
||||
freeIni(iniValue);
|
||||
return 1;
|
||||
|
@ -128,6 +131,8 @@ int FiSH_decrypt(const SERVER_REC * serverRec, char *msg_ptr,
|
|||
char bf_dest[1000] = "";
|
||||
char myMark[20] = "";
|
||||
int msg_len, i, mark_broken_block = 0, action_found = 0;
|
||||
int mode = 0;
|
||||
int cbc_ret = 0;
|
||||
|
||||
if (IsNULLorEmpty(msg_ptr) || decrypted_msg == NULL || IsNULLorEmpty(target))
|
||||
return 0;
|
||||
|
@ -142,9 +147,19 @@ int FiSH_decrypt(const SERVER_REC * serverRec, char *msg_ptr,
|
|||
else
|
||||
return 0; // don't process, blowcrypt-prefix not found
|
||||
|
||||
// Verify base64 string
|
||||
// Strip the * from the CBC mode
|
||||
if (strncmp(msg_ptr, "*", 1) == 0) {
|
||||
mode = 1;
|
||||
msg_ptr++;
|
||||
}
|
||||
|
||||
msg_len = strlen(msg_ptr);
|
||||
if ((strspn(msg_ptr, B64) != (size_t) msg_len) || (msg_len < 12))
|
||||
|
||||
// Verify base64 string - only for ECB
|
||||
if (mode == 0 && (strspn(msg_ptr, B64) != (size_t) msg_len))
|
||||
return 0;
|
||||
|
||||
if (msg_len < 12)
|
||||
return 0;
|
||||
|
||||
if (getIniSectionForContact(serverRec, target, contactName) == FALSE)
|
||||
|
@ -163,7 +178,7 @@ int FiSH_decrypt(const SERVER_REC * serverRec, char *msg_ptr,
|
|||
|
||||
// block-align blowcrypt strings if truncated by IRC server (each block is 12 chars long)
|
||||
// such a truncated block is destroyed and not needed anymore
|
||||
if (msg_len != (msg_len / 12) * 12) {
|
||||
if ((mode == 0) && (msg_len != (msg_len / 12) * 12)) {
|
||||
msg_len = (msg_len / 12) * 12;
|
||||
msg_ptr[msg_len] = '\0';
|
||||
strncpy(myMark, settings_get_str("mark_broken_block"),
|
||||
|
@ -174,7 +189,21 @@ int FiSH_decrypt(const SERVER_REC * serverRec, char *msg_ptr,
|
|||
mark_broken_block = 1;
|
||||
}
|
||||
|
||||
decrypt_string(iniValue.key, msg_ptr, bf_dest, msg_len);
|
||||
if (iniValue.cbc == 1) {
|
||||
cbc_ret = decrypt_string_cbc(iniValue.key, msg_ptr, bf_dest, msg_len);
|
||||
} else {
|
||||
decrypt_string(iniValue.key, msg_ptr, bf_dest, msg_len);
|
||||
}
|
||||
|
||||
if (cbc_ret == -1) {
|
||||
strncpy(myMark, settings_get_str("mark_broken_block"),
|
||||
sizeof(myMark));
|
||||
if (*myMark == '\0' || isNoChar(*myMark))
|
||||
mark_broken_block = 0;
|
||||
else
|
||||
mark_broken_block = 1;
|
||||
}
|
||||
|
||||
freeIni(iniValue);
|
||||
|
||||
if (*bf_dest == '\0')
|
||||
|
@ -634,7 +663,7 @@ void cmd_helpfish(const char *arg, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
" /setkey [-<server tag>] [<nick | #channel>] <key>\n"
|
||||
" /delkey [-<server tag>] [<nick | #channel>]\n"
|
||||
" /key|showkey [-<server tag>] [<nick | #channel>]\n"
|
||||
" /keyx [<nick>] (DH1080 KeyXchange)\n"
|
||||
" /keyx [-ecb] [<nick>]\n"
|
||||
" /setinipw <blow.ini_password>\n"
|
||||
" /unsetinipw\n"
|
||||
" /fishlogin\n");
|
||||
|
@ -691,15 +720,15 @@ int recrypt_ini_file(const char *iniPath, const char *iniPath_new,
|
|||
re_enc = 1;
|
||||
|
||||
bfKeySize = (strlen(value) * 2) * sizeof(char);
|
||||
bfKey = (char *) malloc(bfKeySize);
|
||||
bfKey = (char *) calloc(bfKeySize, sizeof(char));
|
||||
decrypt_string(old_iniKey, value + 4, bfKey, strlen(value + 4));
|
||||
|
||||
newbfKeySize = (strlen(bfKey) * 2)* sizeof(char);
|
||||
newbfKey = (char *) malloc(newbfKeySize);
|
||||
newbfKey = (char *) calloc(newbfKeySize, sizeof(char));
|
||||
encrypt_string(iniKey, bfKey, newbfKey, strlen(bfKey));
|
||||
|
||||
plusOkSize = (strlen(newbfKey) * 2) * sizeof(char);
|
||||
plusOk = (char *) malloc(plusOkSize);
|
||||
plusOk = (char *) calloc(plusOkSize, sizeof(char));
|
||||
snprintf(plusOk, plusOkSize, "+OK %s", newbfKey);
|
||||
|
||||
setIniValue(groups[i], keys[j], plusOk, iniPath_new);
|
||||
|
@ -740,14 +769,14 @@ void cmd_setinipw(const char *iniPW, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
char *new_iniKey;
|
||||
|
||||
old_iniKeySize = strlen(iniKey) * sizeof(char);
|
||||
old_iniKey = (char *) malloc(old_iniKeySize);
|
||||
old_iniKey = (char *) calloc(old_iniKeySize + 1, sizeof(char));
|
||||
strcpy(old_iniKey, iniKey);
|
||||
|
||||
if (iniPW != NULL) {
|
||||
int pw_len = strlen(iniPW);
|
||||
size_t pw_len = strlen(iniPW);
|
||||
|
||||
new_iniKeySize = (pw_len * 2) * sizeof(char);
|
||||
new_iniKey = (char *) malloc(new_iniKeySize);
|
||||
new_iniKeySize = pw_len * 2 + 1;
|
||||
new_iniKey = (char *) calloc(new_iniKeySize, sizeof(char));
|
||||
|
||||
if (pw_len < 1 || (size_t) pw_len > new_iniKeySize) {
|
||||
printtext(server,
|
||||
|
@ -790,7 +819,7 @@ void cmd_setinipw(const char *iniPW, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
htob64(key, B64digest, 32);
|
||||
|
||||
free(iniKey);
|
||||
iniKey = (char *) malloc((strlen(B64digest)* 2) * sizeof(char));
|
||||
iniKey = (char *) calloc(strlen(B64digest) * 2, sizeof(char));
|
||||
|
||||
strcpy(iniKey, B64digest); // this is used for encrypting blow.ini
|
||||
|
||||
|
@ -874,6 +903,24 @@ static void cmd_unsetinipw(const char *arg, SERVER_REC * server,
|
|||
"\002FiSH:\002 Changed back to default blow.ini password, you won't have to enter it on start-up anymore!");
|
||||
}
|
||||
|
||||
int detect_mode(const char *key)
|
||||
{
|
||||
char mode[4];
|
||||
int BLOWFISH_ECB = 0;
|
||||
int BLOWFISH_CBC = 1;
|
||||
|
||||
if (strlen(key) > 4) {
|
||||
strncpy(mode, key, 3);
|
||||
mode[3] = '\0';
|
||||
|
||||
if (strcmp(mode, "cbc") == 0) {
|
||||
return BLOWFISH_CBC;
|
||||
}
|
||||
}
|
||||
|
||||
return BLOWFISH_ECB;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the key for a nick / channel in a server
|
||||
* @param data command
|
||||
|
@ -886,6 +933,7 @@ void cmd_setkey(const char *data, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
char contactName[CONTACT_SIZE] = "";
|
||||
char *encryptedKey;
|
||||
int keySize;
|
||||
int mode = 0;
|
||||
|
||||
const char *target, *key;
|
||||
void *free_arg;
|
||||
|
@ -930,9 +978,14 @@ void cmd_setkey(const char *data, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
}
|
||||
|
||||
keySize = (strlen(key) * 3) * sizeof(char);
|
||||
encryptedKey = (char *) malloc(keySize);
|
||||
encryptedKey = (char *) calloc(keySize, sizeof(char));
|
||||
mode = detect_mode(key);
|
||||
|
||||
encrypt_key((char *)key, encryptedKey);
|
||||
if (mode == 1) {
|
||||
encrypt_key((char *)key + 4, encryptedKey);
|
||||
} else {
|
||||
encrypt_key((char *)key, encryptedKey);
|
||||
}
|
||||
|
||||
if (getIniSectionForContact(server, target, contactName) == FALSE) {
|
||||
bzero(encryptedKey, keySize);
|
||||
|
@ -951,13 +1004,19 @@ void cmd_setkey(const char *data, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
return;
|
||||
}
|
||||
|
||||
if (mode == 1) {
|
||||
setIniValue(contactName, "cbc", "1", iniPath);
|
||||
} else {
|
||||
setIniValue(contactName, "cbc", "0", iniPath);
|
||||
}
|
||||
|
||||
bzero(encryptedKey, keySize);
|
||||
free(encryptedKey);
|
||||
|
||||
printtext(server, item != NULL ? window_item_get_target(item) : NULL,
|
||||
MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Key for %s@%s successfully set!", target,
|
||||
server->tag);
|
||||
"\002FiSH:\002 Key for %s@%s (%s) successfully set!", target,
|
||||
server->tag, mode == 1 ? "CBC" : "ECB");
|
||||
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
|
@ -1054,63 +1113,101 @@ void cmd_key(const char *data, SERVER_REC * server, WI_ITEM_REC * item)
|
|||
}
|
||||
|
||||
printtext(server, target, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Key for %s@%s: %s", target, server->tag,
|
||||
iniValue.key);
|
||||
"\002FiSH:\002 Key for %s@%s: %s (%s)", target, server->tag,
|
||||
iniValue.key, iniValue.cbc == 1 ? "CBC" : "ECB");
|
||||
|
||||
freeIni(iniValue);
|
||||
}
|
||||
|
||||
void cmd_keyx(const char *target, SERVER_REC * server, WI_ITEM_REC * item)
|
||||
void cmd_keyx(const char *data, SERVER_REC * server, WI_ITEM_REC * item)
|
||||
{
|
||||
GHashTable *optlist = NULL;
|
||||
char *target = NULL;
|
||||
void *free_arg = NULL;
|
||||
int ecb = 0;
|
||||
|
||||
if (server == NULL) {
|
||||
printtext(NULL, NULL, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 No connection to server.");
|
||||
return;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_GETREST | PARAM_FLAG_OPTIONS,
|
||||
"keyx", &optlist, &target))
|
||||
goto fail;
|
||||
|
||||
ecb = g_hash_table_lookup(optlist, "ecb") != NULL;
|
||||
|
||||
if (item != NULL && IsNULLorEmpty(target))
|
||||
target = (char *)window_item_get_target(item);
|
||||
|
||||
if (IsNULLorEmpty(target)) {
|
||||
if (item != NULL)
|
||||
target = window_item_get_target(item);
|
||||
else {
|
||||
printtext(NULL, NULL, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Please define nick/#channel. Usage: /keyx <nick/#channel>");
|
||||
return;
|
||||
}
|
||||
printtext(NULL, NULL, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Please define nick/#channel. Usage: /keyx [-ecb] <nick>");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (server_ischannel(server, target)) {
|
||||
printtext(server, target, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 KeyXchange does not work for channels!");
|
||||
return;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
target = (char *)g_strchomp(target);
|
||||
|
||||
DH1080_gen(g_myPrivKey, g_myPubKey);
|
||||
|
||||
irc_send_cmdv((IRC_SERVER_REC *) server, "NOTICE %s :%s %s", target,
|
||||
"DH1080_INIT", g_myPubKey);
|
||||
irc_send_cmdv((IRC_SERVER_REC *) server, "NOTICE %s :%s%s%s", target,
|
||||
DH1080_INIT, g_myPubKey, ecb == 0 ? CBC_SUFFIX : "");
|
||||
|
||||
printtext(server, item != NULL ? window_item_get_target(item) : NULL,
|
||||
MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Sent my DH1080 public key to %s, waiting for reply ...",
|
||||
target);
|
||||
"\002FiSH:\002 Sent my DH1080 public key to %s@%s (%s), waiting for reply ...",
|
||||
target, server->tag, ecb == 1 ? "ECB" : "CBC");
|
||||
fail:
|
||||
if(free_arg) {
|
||||
cmd_params_free(free_arg);
|
||||
}
|
||||
}
|
||||
|
||||
void DH1080_received(SERVER_REC * server, char *msg, char *nick, char *address,
|
||||
char *target)
|
||||
{
|
||||
int i;
|
||||
char hisPubKey[300], contactName[CONTACT_SIZE] =
|
||||
"", encryptedKey[KEYBUF_SIZE] = "";
|
||||
int msg_len;
|
||||
char hisPubKey[300];
|
||||
char contactName[CONTACT_SIZE] = "";
|
||||
char encryptedKey[KEYBUF_SIZE] = "";
|
||||
// 0 for ECB, 1 for CBC
|
||||
int mode = 0;
|
||||
const unsigned int DH1080_INIT_LEN = strlen(DH1080_INIT);
|
||||
const unsigned int DH1080_FINISH_LEN = strlen(DH1080_FINISH);
|
||||
const unsigned int CBC_SUFFIX_LEN = strlen(CBC_SUFFIX);
|
||||
|
||||
if (server_ischannel(server, target) || server_ischannel(server, nick))
|
||||
return; // no KeyXchange for channels...
|
||||
i = strlen(msg);
|
||||
if (i < 191 || i > 195)
|
||||
|
||||
msg_len = strlen(msg);
|
||||
|
||||
if (msg_len < 191 || msg_len > 199)
|
||||
return;
|
||||
|
||||
if (strncmp(msg, "DH1080_INIT ", 12) == 0) {
|
||||
strcpy(hisPubKey, msg + 12);
|
||||
if (strspn(hisPubKey, B64ABC) != strlen(hisPubKey))
|
||||
if (strncmp(msg, DH1080_INIT, DH1080_INIT_LEN) == 0) {
|
||||
|
||||
// Check for CBC at the end
|
||||
if (strcmp(msg + msg_len - CBC_SUFFIX_LEN, " CBC") == 0) {
|
||||
mode = 1;
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
strcpy(hisPubKey, msg + DH1080_INIT_LEN);
|
||||
} else {
|
||||
// Strip the " CBC" at the end
|
||||
strncpy(hisPubKey, msg + DH1080_INIT_LEN, msg_len - DH1080_INIT_LEN - CBC_SUFFIX_LEN);
|
||||
hisPubKey[msg_len - DH1080_INIT_LEN - CBC_SUFFIX_LEN] = '\0';
|
||||
}
|
||||
|
||||
// This check only applies to ECB
|
||||
if ((mode == 0) && (strspn(hisPubKey, B64ABC) != strlen(hisPubKey)))
|
||||
return;
|
||||
|
||||
if (query_find(server, nick) == NULL) { // query window not found, lets create one
|
||||
|
@ -1120,16 +1217,33 @@ void DH1080_received(SERVER_REC * server, char *msg, char *nick, char *address,
|
|||
}
|
||||
|
||||
printtext(server, nick, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Received DH1080 public key from %s, sending mine...",
|
||||
nick);
|
||||
"\002FiSH:\002 Received DH1080 public key from %s@%s (%s), sending mine...",
|
||||
nick, server->tag, mode == 0 ? "ECB" : "CBC");
|
||||
|
||||
DH1080_gen(g_myPrivKey, g_myPubKey);
|
||||
irc_send_cmdv((IRC_SERVER_REC *) server, "NOTICE %s :%s %s",
|
||||
nick, "DH1080_FINISH", g_myPubKey);
|
||||
} else if (strncmp(msg, "DH1080_FINISH ", 14) == 0)
|
||||
strcpy(hisPubKey, msg + 14);
|
||||
else
|
||||
|
||||
irc_send_cmdv((IRC_SERVER_REC *) server, "NOTICE %s :%s%s%s",
|
||||
nick, DH1080_FINISH, g_myPubKey, mode == 1 ? CBC_SUFFIX : "");
|
||||
|
||||
} else if (strncmp(msg, DH1080_FINISH, DH1080_FINISH_LEN) == 0) {
|
||||
|
||||
msg_len = strlen(msg);
|
||||
|
||||
// Check for CBC at the end
|
||||
if (strcmp(msg + msg_len - CBC_SUFFIX_LEN, CBC_SUFFIX) == 0) {
|
||||
mode = 1;
|
||||
}
|
||||
|
||||
if (mode == 0) {
|
||||
strcpy(hisPubKey, msg + DH1080_FINISH_LEN);
|
||||
} else {
|
||||
// Strip the " CBC" at the end
|
||||
strncpy(hisPubKey, msg + DH1080_FINISH_LEN, msg_len - DH1080_FINISH_LEN - CBC_SUFFIX_LEN);
|
||||
hisPubKey[msg_len - DH1080_FINISH_LEN - CBC_SUFFIX_LEN] = '\0';
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (DH1080_comp(g_myPrivKey, hisPubKey) == 0)
|
||||
return;
|
||||
|
@ -1148,10 +1262,17 @@ void DH1080_received(SERVER_REC * server, char *msg, char *nick, char *address,
|
|||
return;
|
||||
}
|
||||
|
||||
// Remember to use CBC mode
|
||||
if ((mode == 1) && (setIniValue(contactName, "cbc", "1", iniPath) == -1)) {
|
||||
printtext(server, nick, MSGLEVEL_CRAP,
|
||||
"\002FiSH ERROR:\002 Unable to write to blow.ini, probably out of space or permission denied.");
|
||||
return;
|
||||
}
|
||||
|
||||
ZeroMemory(encryptedKey, KEYBUF_SIZE);
|
||||
|
||||
printtext(server, nick, MSGLEVEL_CRAP,
|
||||
"\002FiSH:\002 Key for %s successfully set!", nick);
|
||||
"\002FiSH:\002 Key for %s@%s (%s) successfully set!", nick, server->tag, mode == 0 ? "ECB" : "CBC");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1269,6 +1390,7 @@ void setup_fish()
|
|||
command_bind("key", NULL, (SIGNAL_FUNC) cmd_key);
|
||||
command_bind("showkey", NULL, (SIGNAL_FUNC) cmd_key);
|
||||
command_bind("keyx", NULL, (SIGNAL_FUNC) cmd_keyx);
|
||||
command_set_options("keyx", "-ecb");
|
||||
command_bind("setinipw", NULL, (SIGNAL_FUNC) cmd_setinipw);
|
||||
command_bind("unsetinipw", NULL, (SIGNAL_FUNC) cmd_unsetinipw);
|
||||
|
||||
|
@ -1294,7 +1416,7 @@ void authenticated_fish_setup(const char *password, void *rec) {
|
|||
iniUsed = 0;
|
||||
}
|
||||
|
||||
iniKey = (char *) malloc((strlen(password) * 10) * sizeof(char));
|
||||
iniKey = (char *) calloc((strlen(password) * 10), sizeof(char));
|
||||
iniUsed = 1;
|
||||
|
||||
iniValue = allocateIni("FiSH", "ini_password_Hash", iniPath);
|
||||
|
@ -1307,7 +1429,7 @@ void authenticated_fish_setup(const char *password, void *rec) {
|
|||
|
||||
get_ini_password_hash(iniValue.keySize, iniValue.key);
|
||||
|
||||
B64digest = (char *) malloc((iniValue.keySize * 2) * sizeof(char));
|
||||
B64digest = (char *) calloc((iniValue.keySize * 2), sizeof(char));
|
||||
|
||||
calculate_password_key_and_hash(password, iniKey, B64digest);
|
||||
|
||||
|
@ -1379,7 +1501,7 @@ void fish_init(void)
|
|||
get_ini_password_hash(iniValue.keySize, iniValue.key);
|
||||
|
||||
if (strlen(iniValue.key) != 43) {
|
||||
iniKey = (char *) malloc((strlen(default_iniKey)* 2) * sizeof(char));
|
||||
iniKey = (char *) calloc((strlen(default_iniKey)* 2), sizeof(char));
|
||||
iniUsed = 1;
|
||||
|
||||
strcpy(iniKey, default_iniKey);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "FiSH_version.h"
|
||||
#include "inifile.h"
|
||||
#include "blowfish.h"
|
||||
#include "blowfish_cbc.h"
|
||||
#include "DH1080.h"
|
||||
#include "module.h"
|
||||
#include "password.h"
|
||||
|
@ -22,6 +23,9 @@ int keyx_query_created = 0;
|
|||
#define ZeroMemory(dest,count) memset((void *)dest, 0, count)
|
||||
#define IsNULLorEmpty(psz) (psz==NULL || *psz=='\0')
|
||||
#define isNoChar(c) ((c) == 'n' || (c) == 'N' || (c) == '0')
|
||||
#define DH1080_INIT "DH1080_INIT "
|
||||
#define DH1080_FINISH "DH1080_FINISH "
|
||||
#define CBC_SUFFIX " CBC"
|
||||
|
||||
char *isPlainPrefix(const char *msg);
|
||||
char *strfcpy(char *dest, char *buffer, int destSize); // removes leading and trailing blanks from string
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
#include "blowfish_cbc.h"
|
||||
|
||||
int
|
||||
encrypt_string_cbc (const char *key, const char *str, char *dest, int len)
|
||||
{
|
||||
BF_KEY bf_key;
|
||||
unsigned char ivec[BF_BLOCK] = {0};
|
||||
BIO *l_mem = NULL, *l_b64 = NULL;
|
||||
int ret = -1;
|
||||
|
||||
if (!key || !key[0])
|
||||
return 0;
|
||||
|
||||
BF_set_key (&bf_key, strlen (key), (const unsigned char *) key);
|
||||
|
||||
l_b64 = BIO_new(BIO_f_base64());
|
||||
if(!l_b64) {
|
||||
goto fail;
|
||||
}
|
||||
BIO_set_flags(l_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
l_mem = BIO_new(BIO_s_mem());
|
||||
if(!l_mem) {
|
||||
goto fail;
|
||||
}
|
||||
l_b64 = BIO_push(l_b64, l_mem);
|
||||
|
||||
{
|
||||
/* for some f*cked up reason, Mircryption's CBC blowfish does not use an
|
||||
explicit IV, but prepends 8 bytes of random data to the actual string
|
||||
instead, so we have to do this too... */
|
||||
unsigned char block[BF_BLOCK] = {0};
|
||||
RAND_bytes(block, sizeof(block));
|
||||
BF_cbc_encrypt(block, block, BF_BLOCK, &bf_key, ivec, BF_ENCRYPT);
|
||||
if(BIO_write(l_b64, block, sizeof(block)) != sizeof(block)) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
while (len > 0)
|
||||
{
|
||||
const size_t blocksize = len < 8 ? len : BF_BLOCK;
|
||||
unsigned char block[BF_BLOCK] = { 0 }; /* pad with zero */
|
||||
|
||||
memcpy (block, str, blocksize);
|
||||
BF_cbc_encrypt(block, block, BF_BLOCK, &bf_key, ivec, BF_ENCRYPT);
|
||||
|
||||
if(BIO_write(l_b64, block, sizeof(block)) != sizeof(block)) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
len -= blocksize;
|
||||
str += blocksize;
|
||||
}
|
||||
|
||||
BUF_MEM *l_ptr = NULL;
|
||||
BIO_flush(l_b64);
|
||||
BIO_get_mem_ptr(l_b64, &l_ptr);
|
||||
memcpy(dest, l_ptr->data, l_ptr->length);
|
||||
dest[l_ptr->length] = 0;
|
||||
ret = 1;
|
||||
fail:
|
||||
if(l_b64) {
|
||||
BIO_free_all(l_b64);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
decrypt_string_cbc (const char *key, const char *str, char *dest, int len)
|
||||
{
|
||||
BF_KEY bf_key;
|
||||
BIO *l_b64 = NULL;
|
||||
int ret = -1;
|
||||
unsigned char ivec[BF_BLOCK] = {0};
|
||||
unsigned char block[BF_BLOCK] = {0};
|
||||
char * dest_begin = dest;
|
||||
int inlen = 0;
|
||||
|
||||
/* Pad encoded string with 0 bits in case it's bogus */
|
||||
if (!key || !key[0])
|
||||
return 0;
|
||||
|
||||
BF_set_key (&bf_key, strlen (key), (const unsigned char *) key);
|
||||
|
||||
l_b64 = BIO_new(BIO_f_base64());
|
||||
if(!l_b64) {
|
||||
goto fail;
|
||||
}
|
||||
BIO_set_flags(l_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||
BIO *l_mem = BIO_new_mem_buf(str, len);
|
||||
if(!l_mem) {
|
||||
goto fail;
|
||||
}
|
||||
l_b64 = BIO_push(l_b64, l_mem);
|
||||
|
||||
while ((inlen = BIO_read(l_b64, block, sizeof(block))) > 0)
|
||||
{
|
||||
if(inlen != BF_BLOCK) {
|
||||
ret *= -1;
|
||||
break;
|
||||
}
|
||||
|
||||
BF_cbc_encrypt(block, block, BF_BLOCK, &bf_key, ivec, BF_DECRYPT);
|
||||
|
||||
memcpy (dest, block, BF_BLOCK);
|
||||
dest += BF_BLOCK;
|
||||
}
|
||||
*dest++ = 0;
|
||||
// get rid of first 8 bytes
|
||||
memmove(dest_begin, dest_begin + BF_BLOCK, strlen(dest_begin + BF_BLOCK) + 1);
|
||||
ret *= -1;
|
||||
fail:
|
||||
if(l_b64) {
|
||||
BIO_free_all(l_b64);
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <openssl/blowfish.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/buffer.h>
|
||||
#include "FiSH_version.h"
|
||||
#ifdef HAVE_STDINT
|
||||
#include <stdint.h>
|
||||
#else
|
||||
#ifdef HAVE_INTTYPES
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int decrypt_string_cbc(const char *key, const char *str, char *dest, int len);
|
||||
int encrypt_string_cbc(const char *key, const char *str, char *dest, int len);
|
|
@ -46,10 +46,13 @@
|
|||
getIniValue(const char *section, const char *key, const char *default_value,
|
||||
char *buffer, int buflen, const char *filepath)
|
||||
{
|
||||
GKeyFile *key_file;
|
||||
GKeyFile *key_file = NULL;
|
||||
GError *error = NULL;
|
||||
gchar *value = NULL;
|
||||
|
||||
if(buflen <= 0) return -1;
|
||||
buffer[0] = 0;
|
||||
|
||||
key_file = g_key_file_new();
|
||||
|
||||
// If file was read OK...
|
||||
|
@ -60,7 +63,7 @@ getIniValue(const char *section, const char *key, const char *default_value,
|
|||
value = g_key_file_get_string(key_file, section, key, &error);
|
||||
if (value != NULL && error == NULL) {
|
||||
strncpy(buffer, value, (size_t) buflen);
|
||||
buffer[buflen] = '\0';
|
||||
buffer[buflen-1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,6 +74,7 @@ getIniValue(const char *section, const char *key, const char *default_value,
|
|||
if (error != NULL) {
|
||||
g_clear_error (&error);
|
||||
strncpy(buffer, default_value, (size_t) buflen);
|
||||
buffer[buflen-1] = '\0';
|
||||
}
|
||||
|
||||
return (int)strlen(buffer);
|
||||
|
@ -200,10 +204,17 @@ void writeIniFile(GKeyFile * key_file, const char *filepath)
|
|||
allocateIni(const char *section, const char *key, const char *filepath)
|
||||
{
|
||||
struct IniValue iniValue;
|
||||
char mode[2] = {0};
|
||||
|
||||
iniValue.iniKeySize = getIniSize(section, key, filepath);
|
||||
iniValue.keySize = (iniValue.iniKeySize * 2) * sizeof(char);
|
||||
iniValue.key = (char *)malloc(iniValue.keySize);
|
||||
iniValue.keySize = iniValue.iniKeySize * 2 + 1;
|
||||
iniValue.key = (char *)calloc(iniValue.keySize, sizeof(char));
|
||||
iniValue.cbc = 0;
|
||||
|
||||
getIniValue(section, "cbc", "0", mode, sizeof(mode), filepath);
|
||||
if (strcmp(mode, "1") == 0) {
|
||||
iniValue.cbc = 1;
|
||||
}
|
||||
|
||||
return iniValue;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ struct IniValue {
|
|||
char *key;
|
||||
int iniKeySize;
|
||||
int keySize;
|
||||
int cbc;
|
||||
};
|
||||
|
||||
int setIniValue(const char *section, const char *key, const char *value,
|
||||
|
|
Loading…
Reference in New Issue