Revision [464]

Last edited on 2006-04-03 21:28:26 by KogAdmin [expanded note on ratbox/chary]
Additions:
<< A note on Chary 1.1 and later versions of Ratbox:
they've decided to change to Base64 encoding, and a 2048bit key as well as swapping to a custom numeric. Right now you can get the new tools at http://respond.ircd-ratbox.org/ and I'll eventually port this, but I don't want to be the maintainer of any xchat plugins... << ::c::
Deletions:
<< NOTE: this does not work on charybdis 1.1 and greater, which seems to want 2048bit keys << ::c::


Revision [463]

Edited on 2006-04-03 21:19:02 by KogAdmin [chary 1.1]
Additions:
<< NOTE: this does not work on charybdis 1.1 and greater, which seems to want 2048bit keys << ::c::


Revision [350]

Edited on 2005-12-11 04:06:32 by KogAdmin [added source/binary archives, removed annoying source]
Additions:
== Step 1: OpenSSL ==
== Step 2: Generation of keys ==
== Step 3: ircd.conf ==
== Step 4: operator usage/CHALLENGE ==
If you're using Xchat, you can use the scripts I've written. It's just a proof of concept right now, but it works quite nicely:
<load the module>
/challenge passphrase thisismypassphrase
/challenge keyfile /path/to/keyfile
/challange login opername
You MUST have a passphrase - while it's possible to generate a key without one, my plugin won't deal with those. Certs without passwords should be a no-no. I suppose it IS somewhat better than no cert since the text is still encrypted... You'll have to modify that on your own (and it's rather easy...). Bear in mind that this is also a first draft, also my first Xchat plugin, so I need to figure out a way to use dialogs and store values (such as key location for networks).
__Files__
~- [[http://epiphanic.org/files/challenge-src.tar.gz Linux/Unix source + build script]]
~- [[http://epiphanic.org/files/challenge-bin.tar.gz Linux .so]]
~- [[http://epiphanic.org/files/xchat-challenge-src.zip Windows source + MiniGW/GNU Tools makefile]]
~- [[http://epiphanic.org/files/xchat-challenge-bin.zip Windows .dll]]
== Notes ==
Deletions:
=== Step 1: OpenSSL ===
=== Step 2: Generation of keys ===
=== Step 3: ircd.conf ===
=== Step 4: operator usage/CHALLENGE ===
=== Notes ===
I've also written an Xchat plugin that works just fine on Windows, and probably on Nix too, although I haven't tested it:
What you need:
~- source: see below
~- xchat-plugin.h: [[http://www.xchat.org/docs/plugin20.html#win32 available here]]
~- plugin.def: see below
~- libeay32.dll: found it in my Xchat dir (using silverex.info build)
one of these days I'll just include the dll/src in a zip...
== actual source ==
%%(c)
/*
Xchat plug: Hybrid operator challenge system wrapper, win32
Kog@gamesnet.com
Based on winresponse

Known grammar:
challenge keyfile /path/to/file.key
challenge passphrase "passphrase goes here"
challenge login name
*/
/* Includes? Yes please */
#include "xchat-plugin.h"
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/md5.h>
/* Some defines for the framework */
#define PNAME "Hybrid Challenge wrapper"
#define PDESC "Wraps Hybrid7 (and derivitive) challenge requests"
#define PVERSION "0.2"
#define PHELP "Challenge: acceptable commands: keyfile /path/to/key.file, passphrase phrasehere, login name"
#define BUFSIZE 512
/* Error codes */
#define DOC_FILE 0
#define DOC_RSA 1
#define DOC_CHAL 2
#define DOC_DEC 3
#define DOC_GOOD 4
static xchat_plugin *ph; /* Xchat win32 C needs this */
static xchat_hook *hook; /* For unhooking */
/* Let's hold some stuff... */
static char passPhrase[BUFSIZE];
static char keyFile[BUFSIZE];
static char operName[BUFSIZE];
static char challengeString[2048];
static char response[2048];
/*--------------- misc functions ---------------------------------------------*/
/*--------------- taken from winrespond --------------------------------------*/
static int pass_cb(char *buf, int size, int rwflag, void *u)
{
int len;
char *tmp = passPhrase;
if (tmp == NULL)
return 0;

len = strlen(tmp);

if (len <= 0)
return 0;

if (len > size)
len = size;

memcpy(buf, tmp, len);
return len;
}
static void binary_to_hex( unsigned char * bin, char * hex, int length )
{
char * trans = "0123456789ABCDEF";
int i;
for( i = 0; i < length; i++ )
{
hex[i<<1] = trans[bin[i] >> 4];
hex[(i<<1)+1] = trans[bin[i] & 0xf];
}

hex[i<<1] = '\0';
}
static int hex_to_binary(const char *from, char *to, int len)
{
char a, b=1;
int p=0;
const char *ptr = from;

while (-1)
{
a = *ptr++;
if (!a)
break;
b = *ptr++;

/* If this happens, we got bad input. */
if (!b)
break;
if (p >= len)
break;
if (!((a >= '0' && a <= '9') || (a >= 'A' && a <= 'F')))
break;
if (!((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F')))
break;
to[p++] = ((a <= '9') ? (a - '0') : (a - 'A' + 0xA))<<4 |
((b <= '9') ? (b - '0') : (b - 'A' + 0xA));
}

return p;
}
static int DoChallenge(char *prvkey, char *passphrase, char *challenge, char *response)
{
FILE *kfile;
RSA *rsa = NULL;
char ndata[257], ddata[257];
if (!(kfile = fopen(prvkey, "r")))
return DOC_FILE;
SSLeay_add_all_ciphers();
rsa = PEM_read_RSAPrivateKey(kfile, NULL, pass_cb, NULL);
if (!rsa)
{
fclose(kfile);
return DOC_RSA;
}
if (hex_to_binary(challenge, ndata, 128) != 128)
return DOC_CHAL;
if (RSA_private_decrypt(128, (unsigned char*)ndata,
(unsigned char*)ddata, rsa, RSA_PKCS1_PADDING) == -1)
return DOC_DEC;
binary_to_hex((unsigned char *)ddata, ndata, 32);
strcpy(response, ndata);
return DOC_GOOD;
}
/* -------- XChat functions ------------------------------------------------- */
/* -------- All written by yours truly -------------------------------------- */
/* Actual /challenge */
static int auth(char *word[], char *word_eol[], void *userdata)
{
/* Bust out the actual challenge from IRC grammar */
char temp[BUFSIZE];
char *p = word[4];
p++;
strcpy(temp, p);

/* Start the challenge bit, based on winrespond */
int errorCode;

/* OK - this switch was written by Winrespond's authors */
errorCode = DoChallenge(keyFile, passPhrase, temp, response);
switch(errorCode)
{
case DOC_FILE:
xchat_print(ph,"Challenge: Please Enter a Valid Key File");
break;
case DOC_RSA:
xchat_print(ph, "Challenge: Unable to Read Private Key: Passphrase?");
break;

case DOC_CHAL:
xchat_print(ph, "Challenge: Bad Challenge");
break;

case DOC_DEC:
xchat_print(ph, "Challenge: Decryption Error");
break;

case DOC_GOOD:
xchat_commandf(ph, "quote challenge +%s", response);
break;
}

return XCHAT_EAT_ALL;
}
/* Callback used for wrapping /challenge */
static int challenge(char *word[], char *word_eol[], void *userdata)
{
/* Error checking */
if (!word[2][0] || !word[3][0])
{
xchat_print (ph, PHELP);
return XCHAT_EAT_ALL;
}

/* Set keyfile */
if (!stricmp(word[2],"keyfile"))
{
memcpy((char *)keyFile, (char *)word[3], BUFSIZE);
return XCHAT_EAT_ALL;
}
/* Set passphrase */
if (!stricmp(word[2], "passphrase"))
{
memcpy((char *)passPhrase, (char *)word[3], BUFSIZE);
return XCHAT_EAT_ALL;
}
/* oper up */
if (!stricmp(word[2], "login"))
{
if (passPhrase[0] && keyFile[0])
{
memcpy((char *)operName, (char *)word[3], BUFSIZE);
hook = xchat_hook_server(ph, "386", XCHAT_PRI_NORM, auth, NULL);
xchat_commandf(ph, "quote challenge %s", operName);
return XCHAT_EAT_ALL;
}
else
{
xchat_print(ph, "Challenge: looks like you forgot your passphrase or key file");
xchat_print(ph, PHELP);
return XCHAT_EAT_ALL;
}
}

xchat_print(ph, PHELP);
return XCHAT_EAT_ALL;
}
/* Xchat plugin framework function */
void xchat_plugin_get_info(char **name, char **desc, char **version, void **reserved)
{
*name = PNAME;
*desc = PDESC;
*version = PVERSION;
}
/* init */
int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
{
ph = plugin_handle;
/* tell xchat our info */
*plugin_name = PNAME;
*plugin_desc = PDESC;
*plugin_version = PVERSION;
/* hook into command tree, notify user */
xchat_hook_command(ph, "challenge", XCHAT_PRI_NORM, challenge, PHELP, 0);
xchat_printf(ph, "Challenge plugin v%s loaded successfully!\n", PVERSION);
xchat_printf(ph, "Acceptable commands: /challenge passphrase phrase, /challenge keyfile /path/to/file, /challenge login username");
return 1;
}
== Makefile ==
I used MiniGW that had been installed w/ Dev-CPP, but I suppose you could get the packages set up on your own. Probably include the OpenSSL bundle, haven't looked. My makefile:
#The whole enchillada
challenge.dll: challenge.obj
dllwrap --def plugin.def --dllname challenge.dll challenge.o libeay32.dll
@echo Build successful!
@echo Tidying ...
del *.o
del *~
@echo Tidy
#Build obj for dllwrap
challenge.obj: challenge.c makefile xchat-plugin.h
@echo Beginning build...
gcc -Os -DWIN32 -shared -c challenge.c -o challenge.o
#Hardcore
clean:
del *.dll
del *.lib
del *.o
del Makefile.win
#Kill annoying files
tidy:
del *~
del *.o
(the del *~ is to kill my jEdit backups)
== Plugin.def ==
EXPORTS
xchat_plugin_init
xchat_plugin_get_info


Revision [349]

Edited on 2005-12-11 00:17:30 by KogAdmin [added source/binary archives, removed annoying source]
Additions:
xchat_printf(ph, "Acceptable commands: /challenge passphrase phrase, /challenge keyfile /path/to/file, /challenge login username");
Deletions:
#include <unistd.h>
#include <windows.h>
#include <stdio.h>
xchat_print(ph, temp);
xchat_printf(ph, "Challenge: key file set to %s", keyFile);
xchat_printf(ph, "Challenge: passphrase set to %s", passPhrase);


Revision [348]

Edited on 2005-12-10 23:59:03 by KogAdmin [includes working source]
Additions:
=== Abstract ===
=== Step 1: OpenSSL ===
=== Step 2: Generation of keys ===
=== Step 3: ircd.conf ===
=== Step 4: operator usage/CHALLENGE ===
=== Notes ===
I've also written an Xchat plugin that works just fine on Windows, and probably on Nix too, although I haven't tested it:
What you need:
~- source: see below
~- xchat-plugin.h: [[http://www.xchat.org/docs/plugin20.html#win32 available here]]
~- plugin.def: see below
~- libeay32.dll: found it in my Xchat dir (using silverex.info build)
one of these days I'll just include the dll/src in a zip...
== actual source ==
%%(c)
/*
Xchat plug: Hybrid operator challenge system wrapper, win32
Kog@gamesnet.com
Based on winresponse

Known grammar:
challenge keyfile /path/to/file.key
challenge passphrase "passphrase goes here"
challenge login name
*/
/* Includes? Yes please */
#include "xchat-plugin.h"
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/md5.h>
#include <unistd.h>
#include <windows.h>
#include <stdio.h>
/* Some defines for the framework */
#define PNAME "Hybrid Challenge wrapper"
#define PDESC "Wraps Hybrid7 (and derivitive) challenge requests"
#define PVERSION "0.2"
#define PHELP "Challenge: acceptable commands: keyfile /path/to/key.file, passphrase phrasehere, login name"
#define BUFSIZE 512
/* Error codes */
#define DOC_FILE 0
#define DOC_RSA 1
#define DOC_CHAL 2
#define DOC_DEC 3
#define DOC_GOOD 4
static xchat_plugin *ph; /* Xchat win32 C needs this */
static xchat_hook *hook; /* For unhooking */
/* Let's hold some stuff... */
static char passPhrase[BUFSIZE];
static char keyFile[BUFSIZE];
static char operName[BUFSIZE];
static char challengeString[2048];
static char response[2048];
/*--------------- misc functions ---------------------------------------------*/
/*--------------- taken from winrespond --------------------------------------*/
static int pass_cb(char *buf, int size, int rwflag, void *u)
{
int len;
char *tmp = passPhrase;
if (tmp == NULL)
return 0;

len = strlen(tmp);

if (len <= 0)
return 0;

if (len > size)
len = size;

memcpy(buf, tmp, len);
return len;
}
static void binary_to_hex( unsigned char * bin, char * hex, int length )
{
char * trans = "0123456789ABCDEF";
int i;
for( i = 0; i < length; i++ )
{
hex[i<<1] = trans[bin[i] >> 4];
hex[(i<<1)+1] = trans[bin[i] & 0xf];
}

hex[i<<1] = '\0';
}
static int hex_to_binary(const char *from, char *to, int len)
{
char a, b=1;
int p=0;
const char *ptr = from;

while (-1)
{
a = *ptr++;
if (!a)
break;
b = *ptr++;

/* If this happens, we got bad input. */
if (!b)
break;
if (p >= len)
break;
if (!((a >= '0' && a <= '9') || (a >= 'A' && a <= 'F')))
break;
if (!((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F')))
break;
to[p++] = ((a <= '9') ? (a - '0') : (a - 'A' + 0xA))<<4 |
((b <= '9') ? (b - '0') : (b - 'A' + 0xA));
}

return p;
}
static int DoChallenge(char *prvkey, char *passphrase, char *challenge, char *response)
{
FILE *kfile;
RSA *rsa = NULL;
char ndata[257], ddata[257];
if (!(kfile = fopen(prvkey, "r")))
return DOC_FILE;
SSLeay_add_all_ciphers();
rsa = PEM_read_RSAPrivateKey(kfile, NULL, pass_cb, NULL);
if (!rsa)
{
fclose(kfile);
return DOC_RSA;
}
if (hex_to_binary(challenge, ndata, 128) != 128)
return DOC_CHAL;
if (RSA_private_decrypt(128, (unsigned char*)ndata,
(unsigned char*)ddata, rsa, RSA_PKCS1_PADDING) == -1)
return DOC_DEC;
binary_to_hex((unsigned char *)ddata, ndata, 32);
strcpy(response, ndata);
return DOC_GOOD;
}
/* -------- XChat functions ------------------------------------------------- */
/* -------- All written by yours truly -------------------------------------- */
/* Actual /challenge */
static int auth(char *word[], char *word_eol[], void *userdata)
{
/* Bust out the actual challenge from IRC grammar */
char temp[BUFSIZE];
char *p = word[4];
p++;
strcpy(temp, p);
xchat_print(ph, temp);

/* Start the challenge bit, based on winrespond */
int errorCode;

/* OK - this switch was written by Winrespond's authors */
errorCode = DoChallenge(keyFile, passPhrase, temp, response);
switch(errorCode)
{
case DOC_FILE:
xchat_print(ph,"Challenge: Please Enter a Valid Key File");
break;
case DOC_RSA:
xchat_print(ph, "Challenge: Unable to Read Private Key: Passphrase?");
break;

case DOC_CHAL:
xchat_print(ph, "Challenge: Bad Challenge");
break;

case DOC_DEC:
xchat_print(ph, "Challenge: Decryption Error");
break;

case DOC_GOOD:
xchat_commandf(ph, "quote challenge +%s", response);
break;
}

return XCHAT_EAT_ALL;
}
/* Callback used for wrapping /challenge */
static int challenge(char *word[], char *word_eol[], void *userdata)
{
/* Error checking */
if (!word[2][0] || !word[3][0])
{
xchat_print (ph, PHELP);
return XCHAT_EAT_ALL;
}

/* Set keyfile */
if (!stricmp(word[2],"keyfile"))
{
memcpy((char *)keyFile, (char *)word[3], BUFSIZE);
xchat_printf(ph, "Challenge: key file set to %s", keyFile);
return XCHAT_EAT_ALL;
}
/* Set passphrase */
if (!stricmp(word[2], "passphrase"))
{
memcpy((char *)passPhrase, (char *)word[3], BUFSIZE);
xchat_printf(ph, "Challenge: passphrase set to %s", passPhrase);
return XCHAT_EAT_ALL;
}
/* oper up */
if (!stricmp(word[2], "login"))
{
if (passPhrase[0] && keyFile[0])
{
memcpy((char *)operName, (char *)word[3], BUFSIZE);
hook = xchat_hook_server(ph, "386", XCHAT_PRI_NORM, auth, NULL);
xchat_commandf(ph, "quote challenge %s", operName);
return XCHAT_EAT_ALL;
}
else
{
xchat_print(ph, "Challenge: looks like you forgot your passphrase or key file");
xchat_print(ph, PHELP);
return XCHAT_EAT_ALL;
}
}

xchat_print(ph, PHELP);
return XCHAT_EAT_ALL;
}
/* Xchat plugin framework function */
void xchat_plugin_get_info(char **name, char **desc, char **version, void **reserved)
{
*name = PNAME;
*desc = PDESC;
*version = PVERSION;
}
/* init */
int xchat_plugin_init(xchat_plugin *plugin_handle, char **plugin_name, char **plugin_desc, char **plugin_version, char *arg)
{
ph = plugin_handle;
/* tell xchat our info */
*plugin_name = PNAME;
*plugin_desc = PDESC;
*plugin_version = PVERSION;
/* hook into command tree, notify user */
xchat_hook_command(ph, "challenge", XCHAT_PRI_NORM, challenge, PHELP, 0);
xchat_printf(ph, "Challenge plugin v%s loaded successfully!\n", PVERSION);
return 1;
}
== Makefile ==
I used MiniGW that had been installed w/ Dev-CPP, but I suppose you could get the packages set up on your own. Probably include the OpenSSL bundle, haven't looked. My makefile:
#The whole enchillada
challenge.dll: challenge.obj
dllwrap --def plugin.def --dllname challenge.dll challenge.o libeay32.dll
@echo Build successful!
@echo Tidying ...
del *.o
del *~
@echo Tidy
#Build obj for dllwrap
challenge.obj: challenge.c makefile xchat-plugin.h
@echo Beginning build...
gcc -Os -DWIN32 -shared -c challenge.c -o challenge.o
#Hardcore
clean:
del *.dll
del *.lib
del *.o
del Makefile.win
#Kill annoying files
tidy:
del *~
del *.o
(the del *~ is to kill my jEdit backups)
== Plugin.def ==
EXPORTS
xchat_plugin_init
xchat_plugin_get_info
Deletions:
== Abstract ==
== Step 1: OpenSSL ==
== Step 2: Generation of keys ==
== Step 3: ircd.conf ==
== Step 4: operator usage/CHALLENGE ==
== Notes ==


Revision [342]

Edited on 2005-12-03 21:20:43 by KogAdmin [includes working source]
Additions:
The official documentation can be found [[http://kabel.pp.ru/archive/rsa/ here]].
~5 Notes
== Notes ==
Windows users: there's a lovely app called "winrespond" available [[http://kabel.pp.ru/archive/rsa/ here]], as well as both ratbox and non-ratbox compatible respond tools for nix, as well as some basic scripts.


Revision [340]

The oldest known version of this page was created on 2005-12-03 20:09:35 by KogAdmin [includes working source]
Valid XHTML :: Valid CSS: :: Powered by WikkaWiki