Files
bitchx/dll/arcfour/arcfour.c
Kevin Easton 99c5ec9872 Change arcfour example module to use ARC4CHAT instead of SCHAT as the DCC type
The SCHAT type is already used by some other clients for SSL CHAT.  This example module doesn't work
yet anyway, so no-one can actually be using it.
2018-03-14 16:58:10 +11:00

288 lines
7.2 KiB
C

/* ARCFour - a symmetric streaming cipher - Implimentation by Humble
*
* This is a variable-key-length symmetric stream cipher developed in 1987
* by Ron Rivest (the R in RSA). It used to be proprietary but was reverse
* engineered and released publicly in September 1994. The cipher is now
* freely available but the name RC4 is a trademark of RSA Data Security
* Inc. This cipher is secure, proven, easy to impliment, and quite fast.
*/
#define IN_MODULE
#include "irc.h"
#include "struct.h"
#include "ircaux.h"
#include "ctcp.h"
#include "status.h"
#include "lastlog.h"
#include "server.h"
#include "screen.h"
#include "vars.h"
#include "misc.h"
#include "output.h"
#include "module.h"
#include "hash2.h"
#include "hook.h"
#include "dcc.h"
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>
#include <unistd.h>
#include "arcfour.h"
#include "md5.h"
#define INIT_MODULE
#include "modval.h"
#define MODULE_NAME "arcfour"
typedef struct {
int sock;
char ukey[16];
arckey *outbox;
arckey *inbox;
} arclist;
/* from dcc.c. Why isnt this in dcc.h? */
typedef struct _DCC_List
{
struct _DCC_List *next;
char *nick; /* do NOT free this. it's a shared pointer. */
SocketList sock;
} DCC_List;
static arclist *keyboxes[16];
static const double arc_ver = 1.0;
static unsigned int typenum = 0;
/*
* Initialize our box, and return the key used. It better be enough to hold
* 16 chars + 1 null!
*/
static char *init_box(char *ukey, arckey *key)
{
MD5_CTX md5context;
unsigned char buf[256];
int fd;
fd = open("/dev/urandom", O_RDONLY);
if (fd >= 0) {
read(fd, buf, sizeof(buf));
close(fd);
}
else
return NULL;
MD5Init(&md5context);
MD5Update(&md5context, buf, sizeof(buf));
MD5Final(&md5context);
memcpy(ukey, buf, 16);
ukey[16] = '\0';
arcfourInit(key, md5context.digest, 16);
return ukey;
}
static inline void arcfourInit(arckey *arc, void *userkey, unsigned short len)
{
register arcword *S = arc->state, x = 0, y = 0, pos = 0, tmp;
unsigned char *userkey_byte = userkey;
/* Seed the S-box linearly, then mix in the key while stiring briskly */
arc->i = arc->j = 0; /* Initialize i and j to 0 */
while(--x, (S[x] = x)); /* Initialize S-box, backwards */
/* Note: Some of these optimizations REQUIRE arcword to be 8-bit unsigned */
do { /* Spread user key into real key */
y += S[x] + userkey_byte[pos]; /* Keys, shaken, not stirred */
tmp = S[x]; S[x] = S[y]; S[y] = tmp; /* Swap S[i] and S[j] */
if (++pos >= len) pos = 0; /* Repeat user key to fill array */
} while(++x); /* ++x is faster than x++ */
}
static inline char *arcfourCrypt(arckey *arc, char *data, int len)
{
register arcword *S = arc->state, i = arc->i, j = arc->j, tmp;
register int c = 0;
do {
j += S[++i]; /* Shake S-box, stir well */
tmp = S[i]; S[i] = S[j]; S[j] = tmp; /* Swap S[i] and S[j] */
data[c] ^= S[(S[i] + S[j])]; /* XOR the crypto into our data */
} while (++c < len); /* Neat, ++x is faster then x++ */
arc->i = i; /* Save modified i and j counters */
arc->j = j; /* Continue where we left off */
return data; /* Return pointer to ciphertext */
}
int Arcfour_Init(IrcCommandDll **intp, Function_ptr *global_table)
{
static const struct dcc_ops schat_ops = { NULL, start_dcc_crypt, dcc_schat_input, send_dcc_encrypt, end_dcc_crypt };
initialize_module(MODULE_NAME);
memset(keyboxes, 0, sizeof(keyboxes));
typenum = add_dcc_bind("ARC4CHAT", MODULE_NAME, &schat_ops);
add_module_proc(DCC_PROC, MODULE_NAME, "ARC4CHAT", "ArcFour DCC Chat", 0, 0, dcc_sdcc, NULL);
return 0;
}
static arclist *find_box(int sock)
{
int i, tmp;
tmp = sizeof(keyboxes)/sizeof(arclist *);
for (i = 0; i < tmp; i++)
if (keyboxes[i] && (keyboxes[i]->sock == sock))
return keyboxes[i];
return (arclist *)NULL;
}
static char *dcc_crypt (int sock, char *buf, int len)
{
arclist *box;
if ((box = find_box(sock))) {
arcfourCrypt(box->outbox, buf, len-2);
return buf;
}
return NULL;
}
static int send_dcc_encrypt (int type, int sock, char *buf, int len)
{
if (type == DCC_CHAT) {
if (dcc_crypt(sock, buf, len)) {
write(sock, buf, len);
return 0;
}
}
return -1;
}
static int dcc_schat_input(int type, int sock, char *buf, int parm, int buf_size)
{
int len;
len = dgets(buf, sock, parm, buf_size - 1, NULL);
if (len > 0)
{
buf[len-1] = '\0';
dcc_crypt(sock, buf, len);
buf[len] = '\0';
}
return len;
}
/* Here we initialize the cryptography. Send the other end our key, and read
* in theirs. The socket "s" won't have a crypt box unless it is supposed to
* an encrypted connection.
*/
static int start_dcc_crypt (int s, int type, unsigned long d_addr, unsigned short d_port)
{
arclist *tmpbox;
put_it("start_dcc_crypt");
if ((tmpbox = find_box(s))) {
int len;
char randkey[17];
char buf[BIG_BUFFER_SIZE+1];
memset(randkey, 0, sizeof(randkey));
memset(buf, 0, sizeof(buf));
tmpbox->outbox = (arckey *)new_malloc(sizeof(arckey));
if (init_box(randkey, tmpbox->outbox) == NULL)
{
new_free(&tmpbox->outbox);
return -1;
}
snprintf(buf, BIG_BUFFER_SIZE, "SecureDCC %s\r\n%n", randkey, &len);
write(s, buf, len);
memset(buf, 0, sizeof(buf));
if ((len = dgets(buf, s, 1, BIG_BUFFER_SIZE, NULL)) > 0) {
if (!my_strnicmp("SecureDCC", buf, 9)) {
tmpbox->inbox = (arckey *)new_malloc(sizeof(arckey));
arcfourInit(tmpbox->inbox, next_arg(buf, NULL), 16);
}
}
return 0;
}
return -1;
}
static int end_dcc_crypt(int s, unsigned long d_addr, unsigned short d_port)
{
int i;
for(i = 0; i < 16; i++) {
if (keyboxes[i] && (keyboxes[i]->sock == s)) {
new_free(&(keyboxes[i]->inbox));
new_free(&(keyboxes[i]->outbox));
new_free(&keyboxes[i]);
return 0;
}
}
return -1;
}
static void start_dcc_chat(int s)
{
struct sockaddr_in remaddr;
socklen_t sra;
int type;
int new_s = -1;
char *nick = NULL;
unsigned long flags;
DCC_int *n = NULL;
SocketList *sa;
sa = get_socket(s);
flags = sa->flags;
nick = sa->server;
sra = sizeof(struct sockaddr_in);
new_s = accept(s, (struct sockaddr *) &remaddr, &sra);
type = flags & DCC_TYPES;
n = get_socketinfo(s);
/* This uses the ordinary dcc_chat_socketread() function - it will call our
* input filter function dcc_schat_input(). */
if ((add_socketread(new_s, ntohs(remaddr.sin_port), flags, nick, dcc_chat_socketread, NULL)) < 0)
{
erase_dcc_info(s, 0, "%s", convert_output_format("$G %RDCC error: accept() failed. punt!!", NULL, NULL));
close_socketread(s);
return;
}
flags &= ~DCC_WAIT;
flags |= DCC_ACTIVE;
set_socketflags(new_s, flags);
set_socketinfo(new_s, n);
/*
put_it("%s", convert_output_format(fget_string_var(FORMAT_DCC_CONNECT_FSET),
"%s %s %s %s %s %d", update_clock(GET_TIME),
dcc_types[type],
nick, n->userhost?n->userhost:"u@h",
inet_ntoa(remaddr.sin_addr),ntohs(remaddr.sin_port)));
*/
get_time(&n->starttime);
close_socketread(s);
start_dcc_crypt(new_s, type, n->remote.s_addr, ntohs(remaddr.sin_port));
}
/* set up the dcc hooks */
void dcc_sdcc (char *name, char *args)
{
char *p;
if (!my_stricmp(name, "schat") && (strlen(args) > 0)) {
if (*args == ' ')
new_next_arg(args, &args);
else {
p = strchr(args, ' ');
if (p && *p)
*p = 0;
}
dcc_create(args, "ARC4CHAT", NULL, 0, 0, typenum, DCC_TWOCLIENTS, start_dcc_chat);
}
}