packages/net/snort/patches/200-snortsam.patch
florian 27ac5da954 [package] Snort: patch for snortsam support (update for 2.9.2.2)
This patch introduces support for Snort plugin Snortsam. (resend, for snort version 2.9.2.2 - for 2.8.4.1 is located there http://patchwork.openwrt.org/patch/2381/)

Signed-off-by: Jiri Slachta <jiri@slachta.eu>

git-svn-id: svn://svn.openwrt.org/openwrt/packages@33170 3c298f89-4303-0410-b956-a3cf2f4a3e73
2012-08-13 14:08:42 +00:00

3017 lines
113 KiB
Diff

diff -ruN snort-2.9.2.2/autojunk.sh snort-2.9.2.2_bkup/autojunk.sh
--- snort-2.9.2.2/autojunk.sh 1969-12-31 16:00:00.000000000 -0800
+++ snort-2.9.2.2_bkup/autojunk.sh 2012-04-08 20:34:57.385687022 -0700
@@ -0,0 +1,7 @@
+#!/bin/sh
+# the list of commands that need to run before we do a compile
+libtoolize --automake --copy
+aclocal -I m4
+autoheader
+automake --add-missing --copy
+autoconf
diff -ruN snort-2.9.2.2/etc/snort.conf snort-2.9.2.2_bkup/etc/snort.conf
--- snort-2.9.2.2/etc/snort.conf 2012-03-19 15:57:09.000000000 -0700
+++ snort-2.9.2.2_bkup/etc/snort.conf 2012-04-08 20:34:57.385687022 -0700
@@ -536,11 +536,38 @@
# prelude
# output alert_prelude
+###################################################
+# snortsam
+###################################################
+# In order to cause Snort to send a blocking request to the SnortSam agent,
+# that agent has to be listed, including the port it listens on,
+# and the encryption key it is using. The statement for that is:
+#
+# output alert_fwsam: {SnortSam Station}:{port}/{password}
+#
+# {SnortSam Station}: IP address or host name of the host where SnortSam is running.
+# {port}: The port the remote SnortSam agent listens on.
+# {password}: The password, or key, used for encryption of the
+# communication to the remote agent.
+#
+# At the very least, the IP address or host name of the host running SnortSam
+# needs to be specified. If the port is omitted, it defaults to TCP port 898.
+# If the password is omitted, it defaults to a preset password.
+# (In which case it needs to be omitted on the SnortSam agent as well)
+#
+# More than one host can be specified, but has to be done on the same line.
+# Just separate them with one or more spaces.
+#
+# Examples:
+#
+# output alert_fwsam: firewall/idspassword
+# output alert_fwsam: fw1.domain.tld:898/mykey
+# output alert_fwsam: 192.168.0.1/borderfw 192.168.1.254/wanfw
+
# metadata reference data. do not modify these lines
include classification.config
include reference.config
-
###################################################
# Step #7: Customize your rule set
# For more information, see Snort Manual, Writing Snort Rules
diff -ruN snort-2.9.2.2/src/fatal.h snort-2.9.2.2_bkup/src/fatal.h
--- snort-2.9.2.2/src/fatal.h 1969-12-31 16:00:00.000000000 -0800
+++ snort-2.9.2.2_bkup/src/fatal.h 2012-04-08 20:34:57.385687022 -0700
@@ -0,0 +1,40 @@
+/* $Id$ */
+/*
+** Copyright (C) 2002-2008 Sourcefire, Inc.
+** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License Version 2 as
+** published by the Free Software Foundation. You may not use, modify or
+** distribute this program under any other version of the GNU General
+** Public License.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __FATAL_H__
+#define __FATAL_H__
+
+
+/*
+ * in debugging mode print out the filename and the line number where the
+ * failure have occured
+ */
+
+
+#ifdef DEBUG
+ #define FATAL(msg) { printf("%s:%d: ", __FILE__, __LINE__); FatalError( (char *) msg); }
+#else
+ #define FATAL(msg) FatalError( (char *) msg)
+#endif
+
+
+
+#endif /* __FATAL_H__ */
diff -ruN snort-2.9.2.2/src/Makefile.am snort-2.9.2.2_bkup/src/Makefile.am
--- snort-2.9.2.2/src/Makefile.am 2011-10-26 11:28:52.000000000 -0700
+++ snort-2.9.2.2_bkup/src/Makefile.am 2012-04-08 20:34:57.385687022 -0700
@@ -59,6 +59,7 @@
rate_filter.c rate_filter.h \
obfuscation.c obfuscation.h \
rule_option_types.h \
+twofish.c twofish.h \
sfdaq.c sfdaq.h \
idle_processing.c idle_processing.h idle_processing_funcs.h
diff -ruN snort-2.9.2.2/src/output-plugins/Makefile.am snort-2.9.2.2_bkup/src/output-plugins/Makefile.am
--- snort-2.9.2.2/src/output-plugins/Makefile.am 2010-06-09 15:05:17.000000000 -0700
+++ snort-2.9.2.2_bkup/src/output-plugins/Makefile.am 2012-04-08 20:34:57.385687022 -0700
@@ -15,6 +15,7 @@
spo_log_tcpdump.h spo_unified.c spo_unified2.c spo_unified.h spo_unified2.h \
spo_log_ascii.c spo_log_ascii.h spo_alert_sf_socket.h spo_alert_sf_socket.c \
$(PRELUDE_CODE) spo_alert_arubaaction.c spo_alert_arubaaction.h \
+spo_alert_fwsam.c spo_alert_fwsam.h \
spo_alert_test.c spo_alert_test.h
INCLUDES = @INCLUDES@
diff -ruN snort-2.9.2.2/src/output-plugins/spo_alert_fwsam.c snort-2.9.2.2_bkup/src/output-plugins/spo_alert_fwsam.c
--- snort-2.9.2.2/src/output-plugins/spo_alert_fwsam.c 1969-12-31 16:00:00.000000000 -0800
+++ snort-2.9.2.2_bkup/src/output-plugins/spo_alert_fwsam.c 2012-04-08 23:40:57.676343063 -0700
@@ -0,0 +1,1387 @@
+/* $id: snortpatchb,v 1.2 2002/10/26 03:32:35 fknobbe Exp $
+**
+** spo_alert_fwsam.c
+**
+** Copyright (c) 2001-2004 Frank Knobbe <frank@knobbe.us>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/*
+ * Purpose:
+ *
+ * This module sends alerts to a remote service on a host running SnortSam
+ * (the agent) which will block the intruding IP address on a variety of
+ * host and network firewalls.
+ *
+ * SnortSam also performs checks against a white-list of never-to-be-blocked IP addresses,
+ * can override block durations (for example for known proxies), and can detect attack conditions
+ * where too many blocks are received within a defined interval. If an attack is detected
+ * it will unblock the last x blocks and wait for the attack to end.
+ *
+ * See the SnortSam documentation for more information.
+ *
+ *
+ * Output Plugin Parameters:
+ ***************************
+ *
+ * output alert_fwsam: <SnortSam Station>:<port>/<key>
+ *
+ * <FW Mgmt Station>: The IP address or host name of the host running SnortSam.
+ * <port>: The port the remote SnortSam service listens on (default 898).
+ * <key>: The key used for authentication (encryption really)
+ * of the communication to the remote service.
+ *
+ * Examples:
+ *
+ * output alert_fwsam: snortsambox/idspassword
+ * output alert_fwsam: fw1.domain.tld:898/mykey
+ * output alert_fwsam: 192.168.0.1/borderfw 192.168.1.254/wanfw
+ *
+ *
+ * Rule Options:
+ ***************
+ *
+ * fwsam: who[how],time;
+ *
+ * who: src, source, dst, dest, destination
+ * IP address to be blocked according to snort rule (some rules
+ * are reversed, i.e. homenet -> any [and you want to block any]).
+ * src denotes IP to the left of -> and dst denotes IP to the right
+ *
+ * how: Optional. In, out, src, dest, either, both, this, conn, connection
+ * Tells FW-1 to block packets INcoming from host, OUTgoing to host,
+ * EITHERway, or only THIS connection (IP/Service pair).
+ * See 'fw sam' for more information. May be ignored by other plugins.
+ *
+ * time: Duration of block in seconds. (Accepts 'days', 'months', 'weeks',
+ * 'years', 'minutes', 'seconds', 'hours'. Alternatively, a value of
+ * 0, or the keyword PERManent, INFinite, or ALWAYS, will block the
+ * host permanently. Be careful with this!
+ * Tells FW-1 (and others) how long to inhibit packets from the host.
+ *
+ * Examples:
+ *
+ * fwsam: src[either],15min;
+ * or dst[in], 2 days 4 hours
+ * or src, 1 hour
+ *
+ * (default: src[either],5min)
+ *
+ *
+ * Effect:
+ *
+ * Alerts are sent to the remote SnortSam services on Firewall-1 Management Stations
+ * or other hosts running SnortSam (as required for Cisco Routers and PIX).
+ * The remote services will invoke the SAM configuration via the fw sam
+ * command line, or by sending a packet to the SAM port 18183, or by using the official
+ * OPSEC API calls, or by telnetting into Cisco routers or PIX firewalls.
+ * The communication over the network is encrypted using two-fish.
+ * (Implementation ripped from CryptCat by Farm9 with permission.)
+ *
+ * Future Plans:
+ *
+ * - Custom alert trigger per rule (x alerts in y secs) --> Seems to exist in Snort 1.9 now.
+ * - Enable/Allow tagged fwsam: arguments to provide different values to
+ * different stations. --> Seems to be accomplished with custom rule-types
+ *
+ *
+ * Comments:
+ *
+ * It seem that above wishes can be implemented with todays setup. Feedback concerning
+ * these is greatly appreciated.
+ *
+*/
+
+
+#include "spo_alert_fwsam.h"
+#include "twofish.h"
+/* external globals from rules.c */
+extern char *file_name;
+extern int file_line;
+extern OptTreeNode *otn_tmp;
+extern char *snort_conf_dir; /* extern PV pv; */
+
+
+/* my globals */
+
+FWsamList *FWsamStationList=NULL; /* Global (for all alert-types) list of snortsam stations */
+FWsamOptions *FWsamOptionField=NULL;
+unsigned long FWsamMaxOptions=0;
+
+
+/*
+ * Function: AlertFWsamSetup()
+ *
+ * Purpose: Registers the output plugin keyword and initialization
+ * function into the output plugin list. This is the function that
+ * gets called from InitOutputPlugins() in plugbase.c.
+ * It also registers itself as a plugin in order to parse every rule
+ * and to set the appropiate flags from fwsam: option.
+ *
+ * Arguments: None.
+ *
+ * Returns: void function
+ *
+*/
+void AlertFWsamSetup(void)
+{
+ /* link the preprocessor keyword to the init function in the preproc list */
+ RegisterOutputPlugin("alert_fwsam", OUTPUT_TYPE_FLAG__ALERT, AlertFWsamInit);
+ RegisterRuleOption("fwsam", AlertFWsamOptionInit, NULL, OPT_TYPE_ACTION, NULL);
+
+#ifdef FWSAMDEBUG /* This allows debugging of fwsam only */
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamSetup) Output plugin is plugged in...\n");
+#endif
+}
+
+
+/* This function checks if a given snortsam station is already in
+ * a given list.
+*/
+int FWsamStationExists(FWsamStation *who,FWsamList *list)
+{
+ while(list)
+ {
+ if(list->station) {
+// if( who->stationip.s_addr==list->station->stationip.s_addr &&
+ if(IP_EQUALITY(&who->stationip, &list->station->stationip) &&
+ who->stationport==list->station->stationport)
+ return TRUE;
+ }
+ list=list->next;
+ }
+ return FALSE;
+}
+
+/*
+ * Function: AlertFWsamInit(char *args)
+ *
+ * Purpose: Calls the argument parsing function, performs final setup on data
+ * structs, links the preproc function into the function list.
+ *
+ * Arguments: args => ptr to argument string
+ *
+ * Returns: void function
+ *
+*/
+void AlertFWsamInit(char *args)
+{ char *ap;
+ unsigned long statip,cnt,again,i;
+ char *stathost,*statport,*statpass;
+ FWsamStation *station;
+ FWsamList *fwsamlist=NULL; /* alert-type dependent list of snortsam stations */
+ FWsamList *listp,*newlistp;
+ struct hostent *hoste;
+ char buf[1024]="";
+ FILE *fp;
+ FWsamOptions tempopt;
+
+#ifdef FWSAMDEBUG
+ unsigned long hostcnt=0;
+
+
+
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Output plugin initializing...\n");
+#endif
+
+ /* pv.alert_plugin_active = 1; */
+
+ /* parse the argument list from the rules file */
+
+ if(args == NULL)
+ FatalError("ERROR %s (%d) => [Alert_FWsam](AlertFWsamInit) No arguments to alert_fwsam preprocessor!\n", file_name, file_line);
+
+ if(!FWsamOptionField && !FWsamMaxOptions)
+ { strncpy(buf,snort_conf_dir,sizeof(buf)-1);
+ strncpy(buf+strlen(buf),SID_MAPFILE,sizeof(buf)-strlen(buf)-1);
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamSetup) Using file: %s\n",buf);
+#endif
+ fp=fopen(buf,"rt");
+ if(!fp)
+ { strncpy(buf,snort_conf_dir,sizeof(buf)-1);
+ strncpy(buf+strlen(buf),SID_ALT_MAPFILE,sizeof(buf)-strlen(buf)-1);
+ fp=fopen(buf,"rt");
+ }
+ if(fp) /* Check for presence of map file and read those in, sorted. */
+ { LogMessage("INFO => [Alert_FWsam](AlertFWsamSetup) Using sid-map file: %s\n",buf);
+
+ while(FWsamReadLine(buf,sizeof(buf),fp))
+ if(*buf)
+ FWsamMaxOptions++;
+ if(FWsamMaxOptions)
+ { if((FWsamOptionField=(FWsamOptions *)malloc(sizeof(FWsamOptions)*FWsamMaxOptions))==NULL)
+ FatalError("ERROR => [Alert_FWsam](AlertFWsamSetup) malloc failed for OptionField!\n");
+ fseek(fp,0,SEEK_SET);
+ for(cnt=0;cnt<FWsamMaxOptions;)
+ { FWsamReadLine(buf,sizeof(buf),fp);
+ if(*buf)
+ FWsamParseLine(&(FWsamOptionField[cnt++]),buf);
+ }
+ if(FWsamMaxOptions>1)
+ { for(again=TRUE,cnt=FWsamMaxOptions-1;cnt>=1 && again;cnt--)
+ { for(again=FALSE,i=0;i<cnt;i++)
+ { if(FWsamOptionField[i].sid>FWsamOptionField[i+1].sid)
+ { memcpy(&tempopt,&(FWsamOptionField[i]),sizeof(FWsamOptions));
+ memcpy(&(FWsamOptionField[i]),&(FWsamOptionField[i+1]),sizeof(FWsamOptions));
+ memcpy(&(FWsamOptionField[i+1]),&tempopt,sizeof(FWsamOptions));
+ again=TRUE;
+ }
+ }
+ }
+ }
+ }
+ else
+ FWsamMaxOptions=1;
+ fclose(fp);
+ }
+ else
+ FWsamMaxOptions=1;
+ }
+
+
+ ap=args; /* start at the beginning of the argument */
+ while(*ap && isspace(*ap)) ap++;
+ while(*ap)
+ { stathost=ap; /* first argument should be host */
+ statport=NULL;
+ statpass=NULL;
+ while(*ap && *ap!=':' && *ap!='/' && !isspace(*ap)) ap++; /* find token */
+ switch(*ap)
+ { case ':': *ap++=0; /* grab the port */
+ statport=ap;
+ while(*ap && *ap!='/' && !isspace(*ap)) ap++;
+ if(*ap!='/')
+ break;
+ case '/': *ap++=0; /* grab the key */
+ statpass=ap;
+ while(*ap && !isspace(*ap)) ap++;
+ default: break;
+ }
+ if(*ap)
+ { *ap++=0;
+ while(isspace(*ap)) ap++;
+ }
+ /* now we have the first host with port and password (key) */
+ /* next we check for valid/blank password/port */
+ if(statpass!=NULL)
+ if(!*statpass)
+ statpass=NULL;
+ if(statport!=NULL)
+ if(!*statport)
+ statport=NULL;
+ statip=0;
+ /* now we check if a valid host was specified */
+ if(inet_addr(stathost)==INADDR_NONE)
+ { hoste=gethostbyname(stathost);
+ if (!hoste)
+ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWsamInit) Unable to resolve host '%s'!\n",file_name,file_line,stathost);
+ else
+ statip=*(unsigned long *)hoste->h_addr;
+ }
+ else
+ { statip=inet_addr(stathost);
+ if(!statip)
+ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWsamInit) Invalid host address '%s'!\n",file_name,file_line,stathost);
+ }
+ if(statip)
+ { /* groovie, a valid host. Let's alloc and assemble the structure for it. */
+ if((station=(FWsamStation *)malloc(sizeof(FWsamStation)))==NULL)
+ FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for station!\n");
+
+// station->stationip.s_addr=statip; /* the IP address */
+ station->stationip.ip32[0] = statip; /* the IP address */
+ if(statport!=NULL && atoi(statport)>0) /* if the user specified one */
+ station->stationport=atoi(statport); /* use users setting */
+ else
+ station->stationport=FWSAM_DEFAULTPORT; /* set the default port */
+
+ if(statpass!=NULL) /* if specified by user */
+ strncpy(station->stationkey,statpass,TwoFish_KEY_LENGTH); /* use defined key */
+ else
+ station->stationkey[0]=0;
+ station->stationkey[TwoFish_KEY_LENGTH]=0; /* make sure it's terminated. (damn strncpy...) */
+
+ strcpy(station->initialkey,station->stationkey);
+ station->stationfish=TwoFishInit(station->stationkey);
+
+ station->localsocketaddr.sin_port=htons(0); /* let's use dynamic ports for now */
+ station->localsocketaddr.sin_addr.s_addr=0;
+ station->localsocketaddr.sin_family=AF_INET;
+ station->stationsocketaddr.sin_port=htons(station->stationport);
+ //station->stationsocketaddr.sin_addr=station->stationip;
+ station->stationsocketaddr.sin_addr.s_addr=station->stationip.ip32[0];
+ station->stationsocketaddr.sin_family=AF_INET; /* load all socket crap and keep for later */
+
+ do
+ station->myseqno=rand(); /* the seqno this host will use */
+ while(station->myseqno<20 || station->myseqno>65500);
+ station->mykeymod[0]=rand();
+ station->mykeymod[1]=rand();
+ station->mykeymod[2]=rand();
+ station->mykeymod[3]=rand();
+ station->stationseqno=0; /* peer hasn't answered yet. */
+
+
+ if(!FWsamStationExists(station,FWsamStationList)) /* If we don't have the station already in global list....*/
+ { if(FWsamCheckIn(station)) /* ...and we can talk to the agent... */
+ { if((newlistp=(FWsamList *)malloc(sizeof(FWsamList)))==NULL)
+ FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for global newlistp!\n");
+ newlistp->station=station;
+ newlistp->next=NULL;
+
+ if(!FWsamStationList) /* ... add it to the global list/ */
+ FWsamStationList=newlistp;
+ else
+ { listp=FWsamStationList;
+ while(listp->next)
+ listp=listp->next;
+ listp->next=newlistp;
+ }
+ }
+ else
+ { TwoFishDestroy(station->stationfish); /* if not, we trash it. */
+ free(station);
+ station=NULL;
+ }
+ }
+#ifdef FWSAMDEBUG
+ else
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Host %s:%i already in global list, skipping CheckIn.\n", sfip_ntoa(&station->stationip),station->stationport);
+#endif
+
+ if(station)
+ { if(!FWsamStationExists(station,fwsamlist)) /* If we don't have the station already in local list....*/
+ { if((newlistp=(FWsamList *)malloc(sizeof(FWsamList)))==NULL)
+ FatalError("ERROR => [Alert_FWsam](AlertFWsamInit) malloc failed for local newlistp!\n");
+ newlistp->station=station;
+ newlistp->next=NULL;
+
+ if(!fwsamlist) /* ... add it to the local list/ */
+ fwsamlist=newlistp;
+ else
+ { listp=fwsamlist;
+ while(listp->next)
+ listp=listp->next;
+ listp->next=newlistp;
+ }
+ }
+
+#ifdef FWSAMDEBUG
+ else
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Host %s:%i already in local list, skipping.\n",sfip_ntoa(&station->stationip),station->stationport);
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) #%i: Host %s [%s] port %i password %s\n",++hostcnt,stathost,sfip_ntoa(&station->stationip),station->stationport,station->stationkey);
+#endif
+ }
+
+ }
+ } /* next one */
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamInit) Linking fwsam alert function to call list...\n");
+#endif
+
+ /* Set the preprocessor function into the function list */
+ AddFuncToOutputList(AlertFWsam, OUTPUT_TYPE_FLAG__ALERT, fwsamlist);
+ AddFuncToCleanExitList(AlertFWsamCleanExitFunc, fwsamlist);
+
+/*
+* This ifdef function reloads snortsam config/list on SIG HUP
+* 04082012 RZ
+*/
+#ifdef SNORT_RELOAD
+ AddFuncToReloadList(AlertFWsamRestartFunc, fwsamlist);
+#endif
+
+}
+
+
+/* This routine reads in a str from a file, snips white-spaces
+ * off the front and back, removes comments, and pretties the
+ * string. Returns true or false if a line was read or not.
+*/
+int FWsamReadLine(char *buf,unsigned long bufsize,FILE *fp)
+{ char *p;
+
+ if(fgets(buf,bufsize-1,fp))
+ { buf[bufsize-1]=0;
+
+#ifdef FWSAMDEBUG_off
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamReadLine) Line: %s\n",buf);
+#endif
+
+ p=buf;
+ while(isspace(*p))
+ p++;
+ if(p>buf);
+ strcpy(buf,p);
+ if(*buf)
+ { p=buf+strlen(buf)-1; /* remove leading and trailing spaces */
+ while(isspace(*p))
+ *p-- =0;
+ }
+ p=buf;
+ if(*p=='#' || *p==';')
+ *p=0;
+ else
+ p++;
+ while(*p) /* remove inline comments (except escaped #'s and ;'s) */
+ { if(*p=='#' || *p==';')
+ { if(*(p-1)=='\\')
+ strcpy(p-1,p);
+ else
+ *p=0;
+ }
+ else
+ p++;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/* Parses the duration of the argument, recognizing minutes, hours, etc..
+*/
+unsigned long FWsamParseDuration(char *p)
+{ unsigned long dur=0,tdu;
+ char *tok,c1,c2;
+
+ while(*p)
+ { tok=p;
+ while(*p && isdigit(*p))
+ p++;
+ if(*p)
+ { c1=tolower(*p);
+ *p=0;
+ p++;
+ if(*p && !isdigit(*p))
+ { c2=tolower(*p++);
+ while(*p && !isdigit(*p))
+ p++;
+ }
+ else
+ c2=0;
+ tdu=atol(tok);
+ switch(c1)
+ { case 'm': if(c2=='o') /* month */
+ tdu*=(60*60*24*30); /* use 30 days */
+ else
+ tdu*=60; /* minutes */
+ case 's': break; /* seconds */
+ case 'h': tdu*=(60*60); /* hours */
+ break;
+ case 'd': tdu*=(60*60*24); /* days */
+ break;
+ case 'w': tdu*=(60*60*24*7); /* week */
+ break;
+ case 'y': tdu*=(60*60*24*365); /* year */
+ break;
+ }
+ dur+=tdu;
+ }
+ else
+ dur+=atol(tok);
+ }
+
+ return dur;
+}
+
+
+/* This routine parses an option line. It is called by FWsamParseLine,
+ * which parses the sid-block.map file, and also by AlertFWsamOptionInit,
+ * which is called by Snort when processing fwsam: options in rules.
+ * It returns TRUE it there is a possible option problem, otherwise FALSE.
+*/
+int FWsamParseOption(FWsamOptions *optp,char *ap)
+{ int possprob=FALSE;
+
+ /* set defaults */
+
+ optp->duration=300; /* default of 5 minute block */
+ optp->how=FWSAM_HOW_INOUT; /* inbound and outbound block */
+ optp->who=FWSAM_WHO_SRC; /* the source */
+ optp->loglevel=FWSAM_LOG_LONGALERT; /* the log level default */
+ /* parse the fwsam keywords */
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWamOptionInit) Parse Options Args: %s\n",ap);
+#endif
+
+ if(*ap) /* should be dst/src (the WHO) or duration */
+ { if(isdigit(*ap))
+ optp->duration=FWsamParseDuration(ap);
+ else
+ { switch(*ap) /* yeah, we're lazy and check only the first character */
+ { case 'p': ; /* permanent, perm */
+ case 'f': ; /* forever */
+ case 'i': optp->duration=0; /* infinite, inf */
+ break;
+ case 'd': optp->who=FWSAM_WHO_DST; /* destination, dest, dst */
+ break;
+ case 's': optp->who=FWSAM_WHO_SRC; /* source, src */
+ break;
+ default: possprob=TRUE;
+ }
+ while(*ap && *ap!=',' && *ap!='[')
+ ap++;
+ if(*ap=='[')
+ { ap++; /* now we have the HOW */
+ switch(*ap)
+ { case 'i': ; /* in */
+ case 's': optp->how=FWSAM_HOW_IN; /* source, src */
+ break;
+ case 'o': ; /* out */
+ case 'd': optp->how=FWSAM_HOW_OUT; /* destination, dest, dst */
+ break;
+ case 'b': ; /* both */
+ case 'e': optp->how=FWSAM_HOW_INOUT; /* either */
+ break;
+ case 't': ; /* this */
+ case 'c': optp->how=FWSAM_HOW_THIS; /* connection, conn */
+ break;
+ default: possprob=TRUE;
+ }
+ while(*ap && *ap!=',')
+ ap++;
+ }
+ if(*ap==',')
+ { ap++;
+ if(isdigit(*ap)) /* and figure out how long to block */
+ optp->duration=FWsamParseDuration(ap);
+ else if(*ap=='p' || *ap=='f' || *ap=='i')
+ optp->duration=0;
+ else
+ possprob=TRUE;
+ }
+ else if(!*ap)
+ possprob=TRUE;
+ }
+ }
+ else
+ possprob=TRUE;
+
+ return possprob;
+}
+
+
+/* This goes through the lines of sid-block.map and sets the
+ * options for fwsam if the file is being used.
+*/
+void FWsamParseLine(FWsamOptions *optp,char *buf)
+{ char *ap;
+
+ ap=buf; /* start at the beginning of the argument */
+
+ while(*ap)
+ { if(isspace(*ap)) /* normalize spaces (tabs into space, etc) */
+ *ap=' ';
+ if(isupper(*ap)) /* and set to lower case */
+ *ap=tolower(*ap);
+ ap++;
+ }
+ while((ap=strrchr(buf,' '))!=NULL) /* remove spaces */
+ strcpy(ap,ap+1);
+
+ ap=buf;
+ if(*ap)
+ { while(*ap && *ap!=':' && *ap!='|')
+ ap++;
+ *ap++ =0;
+ while(*ap && (*ap==':' || *ap=='|'))
+ ap++;
+
+ optp->sid=(unsigned long)atol(buf);
+
+ if(FWsamParseOption(optp,ap))
+ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWamOptionInit) Possible option problem. Using %s[%s],%lu.\n",file_name,file_line,(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration);
+ }
+ else
+ optp->sid=0;
+}
+
+
+
+/*
+ * Function: AlertFWsamOptionInit(char *data, OptTreeNode *otn, int protocol)
+ *
+ * Purpose: Parses each rule and sets the option flags in the tree.
+ *
+ * Arguments: args => ptr to argument string
+ *
+ * Returns: void function
+ *
+*/
+void AlertFWsamOptionInit(char *args,OptTreeNode *otn,int protocol)
+{
+ FWsamOptions *optp;
+ char *ap;
+
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWamOptionInit) FWsamOptionInit is parsing...\n");
+#endif
+
+ if((optp=(FWsamOptions *)malloc(sizeof(FWsamOptions)))==NULL)
+ FatalError("ERROR => [Alert_FWsam](AlertFWamOptionInit) malloc failed for opt!\n");
+
+
+ ap=args; /* start at the beginning of the argument */
+
+ while(*ap)
+ { if(isspace(*ap)) /* normalize spaces (tabs into space, etc) */
+ *ap=' ';
+ if(isupper(*ap)) /* and set to lower case */
+ *ap=tolower(*ap);
+ ap++;
+ }
+ while((ap=strrchr(args,' '))!=NULL) /* remove spaces */
+ strcpy(ap,ap+1);
+
+
+ if(FWsamParseOption(optp,args))
+ LogMessage("WARNING %s (%d) => [Alert_FWsam](AlertFWamOptionInit) Possible option problem. Using %s[%s],%lu.\n",file_name,file_line,(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration);
+
+ otn->ds_list[PLUGIN_FWSAM]=(FWsamOptions *)optp;
+}
+
+
+/* Generates a new encryption key for TwoFish based on seq numbers and a random that
+ * the SnortSam agents send on checkin (in protocol)
+*/
+void FWsamNewStationKey(FWsamStation *station,FWsamPacket *packet)
+{
+ //unsigned char newkey[TwoFish_KEY_LENGTH+2];
+ char newkey[TwoFish_KEY_LENGTH+2];
+ int i;
+
+ newkey[0]=packet->snortseqno[0]; /* current snort seq # (which both know) */
+ newkey[1]=packet->snortseqno[1];
+ newkey[2]=packet->fwseqno[0]; /* current SnortSam seq # (which both know) */
+ newkey[3]=packet->fwseqno[1];
+ newkey[4]=packet->protocol[0]; /* the random SnortSam chose */
+ newkey[5]=packet->protocol[1];
+
+ strncpy(newkey+6,station->stationkey,TwoFish_KEY_LENGTH-6); /* append old key */
+ newkey[TwoFish_KEY_LENGTH]=0;
+
+ newkey[0]^=station->mykeymod[0]; /* modify key with key modifiers which were */
+ newkey[1]^=station->mykeymod[1]; /* exchanged during the check-in handshake. */
+ newkey[2]^=station->mykeymod[2];
+ newkey[3]^=station->mykeymod[3];
+ newkey[4]^=station->fwkeymod[0];
+ newkey[5]^=station->fwkeymod[1];
+ newkey[6]^=station->fwkeymod[2];
+ newkey[7]^=station->fwkeymod[3];
+
+ for(i=0;i<=7;i++)
+ if(newkey[i]==0)
+ newkey[i]++;
+
+ strcpy(station->stationkey,newkey);
+ TwoFishDestroy(station->stationfish);
+ station->stationfish=TwoFishInit(newkey);
+}
+
+
+/* This routine will search the option list as defined
+ * by the sid-block.map file and return a pointer
+ * to the matching record.
+*/
+FWsamOptions *FWsamGetOption(unsigned long sid)
+{ signed long i,step,diff,o,o2;
+
+#ifdef FWSAM_FANCYFETCH /* Fancy-fetch jumps in decreasing n/2 steps and takes much less lookups */
+ o=o2= -1;
+ i=step=FWsamMaxOptions>>1;
+ while(i>=0 && i<FWsamMaxOptions && i!=o2)
+ { diff=sid-FWsamOptionField[i].sid;
+ if(!diff)
+ return &(FWsamOptionField[i]);
+ if(step>1)
+ step=step>>1;
+ o2=o;
+ o=i;
+ if(diff>0)
+ i+=step;
+ else
+ i-=step;
+ }
+#else /* This is just a sequential list lookup */
+ for(i=0;i<FWsamMaxOptions;i++)
+ if(FWsamOptionField[i].sid==sid)
+ return &(FWsamOptionField[i]);
+#endif
+ return NULL;
+}
+
+
+/****************************************************************************
+ *
+ * Function: AlertFWsam(Packet *, char *)
+ *
+ * Purpose: Send the current alert to a remote module on a FW-1 mgmt station
+ *
+ * Arguments: p => pointer to the packet data struct
+ * msg => the message to print in the alert
+ *
+ * Returns: void function
+ *
+ ***************************************************************************/
+void AlertFWsam(Packet *p, char *msg, void *arg, Event *event)
+{ FWsamOptions *optp;
+ FWsamPacket sampacket;
+ FWsamStation *station=NULL;
+ FWsamList *fwsamlist;
+ SOCKET stationsocket;
+ int i,len,deletestation,stationtry=0;
+ //unsigned char *encbuf,*decbuf;
+ char *encbuf,*decbuf;
+ static unsigned long lastbsip[FWSAM_REPET_BLOCKS],lastbdip[FWSAM_REPET_BLOCKS],
+ lastbduration[FWSAM_REPET_BLOCKS],lastbtime[FWSAM_REPET_BLOCKS];
+ static unsigned short lastbsp[FWSAM_REPET_BLOCKS],lastbdp[FWSAM_REPET_BLOCKS],
+ lastbproto[FWSAM_REPET_BLOCKS],lastbpointer;
+ static unsigned char lastbmode[FWSAM_REPET_BLOCKS];
+ static unsigned long btime=0;
+
+
+ if(otn_tmp==NULL)
+ {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] NULL otn_tmp!\n");
+#endif
+ return;
+ }
+ if(p == NULL)
+ {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] NULL packet!\n");
+#endif
+ return;
+ }
+ if(arg == NULL)
+ {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] NULL arg!\n");
+#endif
+ return;
+ }
+
+ /* SnortSam does no IPv6 */
+ if (!IS_IP4(p)) {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] not acting on non-IP4 packet!\n");
+#endif
+ return;
+ }
+
+ optp=NULL;
+
+ if(FWsamOptionField) /* If using the file (field present), let's use that */
+ optp=FWsamGetOption(event->sig_id);
+
+ if(!optp) /* If file not present, check if an fwsam option was defined on the triggering rule */
+ optp=otn_tmp->ds_list[PLUGIN_FWSAM];
+
+ if(optp) /* if options specified for this rule */
+ { if(!btime) /* if this is the first time this function is */
+ { for(i=0;i<FWSAM_REPET_BLOCKS;i++) /* called, reset the time and protocol to 0. */
+ { lastbproto[i]=0;
+ lastbtime[i]=0;
+ }
+ }
+
+ fwsamlist=(FWsamList *)arg;
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Alert -> Msg=\"%s\"\n",msg);
+
+ LogMessage("DEBUG => [Alert_FWsam] Alert -> Option: %s[%s],%lu.\n",(optp->who==FWSAM_WHO_SRC)?"src":"dst",(optp->how==FWSAM_HOW_IN)?"in":((optp->how==FWSAM_HOW_OUT)?"out":"either"),optp->duration);
+#endif
+
+ len=TRUE;
+ btime=(unsigned long)time(NULL); /* get current time */
+ /* This is a cheap check to see if the blocking request matches any of the previous requests. */
+ for(i=0;i<FWSAM_REPET_BLOCKS && len;i++)
+ { if( ((optp->how==FWSAM_HOW_THIS)? /* if blocking mode SERVICE, check for src and dst */
+ ( lastbsip[i]==p->iph->ip_src.s_addr && lastbdip[i]==p->iph->ip_dst.s_addr &&lastbproto[i]==p->iph->ip_proto &&
+ ((p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)? /* check port only of TCP or UDP */
+/* ((optp->who==FWSAM_WHO_SRC)?(lastbsp[i]==p->sp):(lastbdp[i]==p->dp)):TRUE) ): */
+ lastbdp[i]==p->dp:TRUE) ):
+ ((optp->who==FWSAM_WHO_SRC)?(lastbsip[i]==p->iph->ip_src.s_addr):(lastbdip[i]==p->iph->ip_dst.s_addr))) && /* otherwise if we block source, only compare source. Same for dest. */
+ lastbduration[i]==optp->duration &&
+ (lastbmode[i]&(FWSAM_HOW|FWSAM_WHO))==(optp->how|optp->who) &&
+ (btime-lastbtime[i]<((optp->duration>FWSAM_REPET_TIME)?FWSAM_REPET_TIME:optp->duration)))
+ { len=FALSE; /* If so, we don't need to block again. */
+ }
+ }
+ if(len)
+ { if(++lastbpointer>=FWSAM_REPET_BLOCKS) /* increase repetitive check pointer */
+ lastbpointer=0;
+ lastbsip[lastbpointer]=p->iph->ip_src.s_addr; /* and note packet details */
+ lastbdip[lastbpointer]=p->iph->ip_dst.s_addr;
+ lastbduration[lastbpointer]=optp->duration;
+ lastbmode[lastbpointer]=optp->how|optp->who|optp->loglevel;
+ lastbproto[lastbpointer]=p->iph->ip_proto;
+ if(p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)
+ { lastbsp[lastbpointer]=p->sp; /* set ports if TCP or UDP */
+ lastbdp[lastbpointer]=p->dp;
+ }
+ lastbtime[lastbpointer]=btime;
+
+
+ while(fwsamlist!=NULL)
+ { station=fwsamlist->station;
+ //if(station->stationip.s_addr)
+ if(station->stationip.ip32[0])
+ { deletestation=FALSE;
+ stationtry++; /* first try */
+ /* create a socket for the station */
+ stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if(stationsocket==INVALID_SOCKET)
+ FatalError("ERROR => [Alert_FWsam] Funky socket error (socket)!\n");
+ if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr)))
+ FatalError("ERROR => [Alert_FWsam] Could not bind socket!\n");
+
+ /* let's connect to the agent */
+ if(connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr)))
+ {
+ LogMessage("WARNING => [Alert_FWsam] Could not send block to host %s. Will try later.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ stationtry=0;
+ }
+ else
+ {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Connected to host %s.\n",sfip_ntoa(&station->stationip));
+#endif
+ /* now build the packet */
+ station->myseqno+=station->stationseqno; /* increase my seqno by adding agent seq no */
+ sampacket.endiancheck=1; /* This is an endian indicator for Snortsam */
+ sampacket.snortseqno[0]=(char)station->myseqno;
+ sampacket.snortseqno[1]=(char)(station->myseqno>>8);
+ sampacket.fwseqno[0]=(char)station->stationseqno;/* fill station seqno */
+ sampacket.fwseqno[1]=(char)(station->stationseqno>>8);
+ sampacket.status=FWSAM_STATUS_BLOCK; /* set block mode */
+ sampacket.version=FWSAM_PACKETVERSION; /* set packet version */
+ sampacket.duration[0]=(char)optp->duration; /* set duration */
+ sampacket.duration[1]=(char)(optp->duration>>8);
+ sampacket.duration[2]=(char)(optp->duration>>16);
+ sampacket.duration[3]=(char)(optp->duration>>24);
+ sampacket.fwmode=optp->how|optp->who|optp->loglevel; /* set the mode */
+ sampacket.dstip[0]=(char)p->iph->ip_dst.s_addr; /* destination IP */
+ sampacket.dstip[1]=(char)(p->iph->ip_dst.s_addr>>8);
+ sampacket.dstip[2]=(char)(p->iph->ip_dst.s_addr>>16);
+ sampacket.dstip[3]=(char)(p->iph->ip_dst.s_addr>>24);
+ sampacket.srcip[0]=(char)p->iph->ip_src.s_addr; /* source IP */
+ sampacket.srcip[1]=(char)(p->iph->ip_src.s_addr>>8);
+ sampacket.srcip[2]=(char)(p->iph->ip_src.s_addr>>16);
+ sampacket.srcip[3]=(char)(p->iph->ip_src.s_addr>>24);
+ sampacket.protocol[0]=(char)p->iph->ip_proto; /* protocol */
+ sampacket.protocol[1]=(char)(p->iph->ip_proto>>8);/* protocol */
+
+ if(p->iph->ip_proto==IPPROTO_TCP || p->iph->ip_proto==IPPROTO_UDP)
+ { sampacket.srcport[0]=(char)p->sp; /* set ports */
+ sampacket.srcport[1]=(char)(p->sp>>8);
+ sampacket.dstport[0]=(char)p->dp;
+ sampacket.dstport[1]=(char)(p->dp>>8);
+ }
+ else
+ sampacket.srcport[0]=sampacket.srcport[1]=sampacket.dstport[0]=sampacket.dstport[1]=0;
+
+ sampacket.sig_id[0]=(char)event->sig_id; /* set signature ID */
+ sampacket.sig_id[1]=(char)(event->sig_id>>8);
+ sampacket.sig_id[2]=(char)(event->sig_id>>16);
+ sampacket.sig_id[3]=(char)(event->sig_id>>24);
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Sending BLOCK\n");
+ LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo: %x\n",station->myseqno);
+ LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo : %x\n",station->stationseqno);
+ LogMessage("DEBUG => [Alert_FWsam] Status : %i\n",FWSAM_STATUS_BLOCK);
+ LogMessage("DEBUG => [Alert_FWsam] Mode : %i\n",optp->how|optp->who|optp->loglevel);
+ LogMessage("DEBUG => [Alert_FWsam] Duration : %li\n",optp->duration);
+ LogMessage("DEBUG => [Alert_FWsam] Protocol : %i\n",GET_IPH_PROTO(p));
+#ifdef SUP_IP6
+ LogMessage("DEBUG => [Alert_FWsam] Src IP : %s\n",sfip_ntoa(GET_SRC_IP(p)));
+ LogMessage("DEBUG => [Alert_FWsam] Dest IP : %s\n",sfip_ntoa(GET_DST_IP(p)));
+#else
+ LogMessage("DEBUG => [Alert_FWsam] Src IP : %s\n",inet_ntoa(p->iph->ip_src));
+ LogMessage("DEBUG => [Alert_FWsam] Dest IP : %s\n",inet_ntoa(p->iph->ip_dst));
+#endif
+ LogMessage("DEBUG => [Alert_FWsam] Src Port : %i\n",p->sp);
+ LogMessage("DEBUG => [Alert_FWsam] Dest Port : %i\n",p->dp);
+ LogMessage("DEBUG => [Alert_FWsam] Sig_ID : %lu\n",event->sig_id);
+
+#endif
+
+ encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get the encryption buffer */
+ len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt the packet with current key */
+
+ if(send(stationsocket,encbuf,len,0)!=len) /* weird...could not send */
+ { LogMessage("WARNING => [Alert_FWsam] Could not send to host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ stationtry=0;
+ }
+ else
+ { i=FWSAM_NETWAIT;
+#ifdef WIN32
+ ioctlsocket(stationsocket,FIONBIO,&i); /* set non blocking and wait for */
+#else
+ ioctl(stationsocket,FIONBIO,&i); /* set non blocking and wait for */
+#endif
+ while(i-- >1) /* the response packet */
+ { waitms(10); /* wait for response (default maximum 3 secs */
+ if(recv(stationsocket,encbuf,len,0)==len)
+ i=0; /* if we received packet we set the counter to 0. */
+ /* by the time we check with if, it's already dec'ed to -1 */
+ }
+ if(!i) /* id we timed out (i was one, then dec'ed)... */
+ { LogMessage("WARNING => [Alert_FWsam] Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ stationtry=0;
+ }
+ else /* got a packet */
+ { decbuf=(char *)&sampacket; /* get the pointer to the packet struct */
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt the packet with current key */
+
+ if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+ { strcpy(station->stationkey,station->initialkey); /* try the intial key */
+ TwoFishDestroy(station->stationfish);
+ station->stationfish=TwoFishInit(station->stationkey); /* re-initialize the TwoFish with the intial key */
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try again to decrypt */
+ LogMessage("INFO => [Alert_FWsam] Had to use initial key!\n");
+ }
+ if(len==sizeof(FWsamPacket)) /* valid decryption */
+ { if(sampacket.version==FWSAM_PACKETVERSION)/* master speaks my language */
+ { if(sampacket.status==FWSAM_STATUS_OK || sampacket.status==FWSAM_STATUS_NEWKEY
+ || sampacket.status==FWSAM_STATUS_RESYNC || sampacket.status==FWSAM_STATUS_HOLD)
+ { station->stationseqno=sampacket.fwseqno[0] | (sampacket.fwseqno[1]<<8); /* get stations seqno */
+ station->lastcontact=(unsigned long)time(NULL); /* set the last contact time (not used yet) */
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK":
+ sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY":
+ sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC":
+ sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR");
+ LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo: %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8));
+ LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo : %x\n",station->stationseqno);
+ LogMessage("DEBUG => [Alert_FWsam] Status : %i\n",sampacket.status);
+ LogMessage("DEBUG => [Alert_FWsam] Version : %i\n",sampacket.version);
+#endif
+ if(sampacket.status==FWSAM_STATUS_HOLD)
+ { i=FWSAM_NETHOLD; /* Stay on hold for a maximum of 60 secs (default) */
+ while(i-- >1) /* the response packet */
+ { waitms(10); /* wait for response */
+ if(recv(stationsocket,encbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,0)==sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE)
+ i=0; /* if we received packet we set the counter to 0. */
+ }
+ if(!i) /* id we timed out (i was one, then dec'ed)... */
+ { LogMessage("WARNING => [Alert_FWsam] Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+ stationtry=0;
+ sampacket.status=FWSAM_STATUS_ERROR;
+ }
+ else /* got a packet */
+ { decbuf=(char *)&sampacket; /* get the pointer to the packet struct */
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt the packet with current key */
+
+ if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+ { strcpy(station->stationkey,station->initialkey); /* try the intial key */
+ TwoFishDestroy(station->stationfish);
+ station->stationfish=TwoFishInit(station->stationkey); /* re-initialize the TwoFish with the intial key */
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try again to decrypt */
+ LogMessage("INFO => [Alert_FWsam] Had to use initial key again!\n");
+ }
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK":
+ sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY":
+ sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC":
+ sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR");
+ LogMessage("DEBUG => [Alert_FWsam] Snort SeqNo: %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8));
+ LogMessage("DEBUG => [Alert_FWsam] Mgmt SeqNo : %x\n",station->stationseqno);
+ LogMessage("DEBUG => [Alert_FWsam] Status : %i\n",sampacket.status);
+ LogMessage("DEBUG => [Alert_FWsam] Version : %i\n",sampacket.version);
+#endif
+ if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+ { ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ deletestation=TRUE;
+ sampacket.status=FWSAM_STATUS_ERROR;
+ }
+ else if(sampacket.version!=FWSAM_PACKETVERSION) /* invalid protocol version */
+ { ErrorMessage("ERROR => [Alert_FWsam] Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ deletestation=TRUE;
+ sampacket.status=FWSAM_STATUS_ERROR;
+ }
+ else if(sampacket.status!=FWSAM_STATUS_OK && sampacket.status!=FWSAM_STATUS_NEWKEY && sampacket.status!=FWSAM_STATUS_RESYNC)
+ { ErrorMessage("ERROR => [Alert_FWsam] Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ deletestation=TRUE;
+ sampacket.status=FWSAM_STATUS_ERROR;
+ }
+ }
+ }
+ if(sampacket.status==FWSAM_STATUS_RESYNC) /* if station want's to resync... */
+ { strcpy(station->stationkey,station->initialkey); /* ...we use the intial key... */
+ memcpy(station->fwkeymod,sampacket.duration,4); /* and note the random key modifier */
+ }
+ if(sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC)
+ {
+ FWsamNewStationKey(station,&sampacket); /* generate new TwoFish keys */
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Generated new encryption key...\n");
+#endif
+ }
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ stationtry=0;
+ }
+ else if(sampacket.status==FWSAM_STATUS_ERROR) /* if SnortSam reports an error on second try, */
+ {
+#ifdef WIN32
+ closesocket(stationsocket); /* something is messed up and ... */
+#else
+ close(stationsocket);
+#endif
+ if(stationtry>1) /* we ignore that station. */
+ { deletestation=TRUE; /* flag for deletion */
+ ErrorMessage("ERROR => [Alert_FWsam] Could not renegotiate key! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ }
+ else /* if we get an error on the first try, */
+ { if(!FWsamCheckIn(station)) /* we first try to check in again. */
+ { deletestation=TRUE;
+ ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ }
+ }
+ }
+ else /* an unknown status means trouble... */
+ { ErrorMessage("ERROR => [Alert_FWsam] Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ deletestation=TRUE;
+ }
+ }
+ else /* if the SnortSam agent uses a different packet version, we have no choice but to ignore it. */
+ { ErrorMessage("ERROR => [Alert_FWsam] Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ deletestation=TRUE;
+ }
+ }
+ else /* if the intial key failed to decrypt as well, the keys are not configured the same, and we ignore that SnortSam station. */
+ { ErrorMessage("ERROR => [Alert_FWsam] Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ deletestation=TRUE;
+ }
+ }
+ }
+ free(encbuf); /* release of the TwoFishAlloc'ed encryption buffer */
+ }
+ if(stationtry==0 || deletestation) /* if everything went real well, or real bad... */
+ { if(deletestation){ /* If it went bad, we remove the station from the list by marking the IP */
+// station->stationip.s_addr=0;
+ station->stationip.ip32[0]=0;
+ }
+ fwsamlist=fwsamlist->next;
+ }
+ }
+ else
+ fwsamlist=fwsamlist->next;
+ }
+ }
+ else
+ {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam] Skipping repetitive block.\n");
+#endif
+ }
+ }
+}
+
+/* FWsamCheckOut will be called when Snort exists. It de-registeres this snort sensor
+ * from the list of sensor that the SnortSam agent keeps.
+ */
+void FWsamCheckOut(FWsamStation *station)
+{ FWsamPacket sampacket;
+ SOCKET stationsocket;
+ int i,len;
+ char *encbuf,*decbuf;
+ //unsigned char *encbuf,*decbuf;
+
+
+ stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if(stationsocket==INVALID_SOCKET)
+ FatalError("ERROR => [Alert_FWsam](FWsamCheckOut) Funky socket error (socket)!\n");
+ if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr)))
+ FatalError("ERROR => [Alert_FWsam](FWsamCheckOut) Could not bind socket!\n");
+
+ /* let's connect to the agent */
+ if(!connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr)))
+ { LogMessage("INFO => [Alert_FWsam](FWsamCheckOut) Disconnecting from host %s.\n",sfip_ntoa(&station->stationip));
+ /* now build the packet */
+ station->myseqno+=station->stationseqno; /* increase my seqno */
+ sampacket.endiancheck=1;
+ sampacket.snortseqno[0]=(char)station->myseqno;
+ sampacket.snortseqno[1]=(char)(station->myseqno>>8);
+ sampacket.fwseqno[0]=(char)station->stationseqno; /* fill station seqno */
+ sampacket.fwseqno[1]=(char)(station->stationseqno>>8);
+ sampacket.status=FWSAM_STATUS_CHECKOUT; /* checking out... */
+ sampacket.version=FWSAM_PACKETVERSION;
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Sending CHECKOUT\n");
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Snort SeqNo: %x\n",station->myseqno);
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Mgmt SeqNo : %x\n",station->stationseqno);
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckOut) Status : %i\n",sampacket.status);
+
+#endif
+
+ encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get encryption buffer */
+ len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt packet with current key */
+
+ if(send(stationsocket,encbuf,len,0)==len)
+ { i=FWSAM_NETWAIT;
+#ifdef WIN32
+ ioctlsocket(stationsocket,FIONBIO,&i); /* set non blocking and wait for */
+#else
+ ioctl(stationsocket,FIONBIO,&i); /* set non blocking and wait for */
+#endif
+ while(i-- >1)
+ { waitms(10); /* ...wait a maximum of 3 secs for response... */
+ if(recv(stationsocket,encbuf,len,0)==len) /* ... for the status packet */
+ i=0;
+ }
+ if(i) /* if we got the packet */
+ { decbuf=(char *)&sampacket;
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish);
+
+ if(len!=sizeof(FWsamPacket)) /* invalid decryption */
+ { strcpy(station->stationkey,station->initialkey); /* try initial key */
+ TwoFishDestroy(station->stationfish); /* toss this fish */
+ station->stationfish=TwoFishInit(station->stationkey); /* re-initialze TwoFish with initial key */
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* and try to decrypt again */
+ LogMessage("INFO => [Alert_FWsam](FWsamCheckOut) Had to use initial key!\n");
+ }
+ if(len==sizeof(FWsamPacket)) /* valid decryption */
+ { if(sampacket.version!=FWSAM_PACKETVERSION) /* but don't really care since we are on the way out */
+ ErrorMessage("WARNING => [Alert_FWsam](FWsamCheckOut) Protocol version error! What the hell, we're quitting anyway! :)\n");
+ }
+ else
+ ErrorMessage("WARNING => [Alert_FWsam](FWsamCheckOut) Password mismatch! What the hell, we're quitting anyway! :)\n");
+ }
+ }
+ free(encbuf); /* release TwoFishAlloc'ed buffer */
+ }
+ else
+ LogMessage("WARNING => [Alert_FWsam] Could not connect to host %s for CheckOut. What the hell, we're quitting anyway! :)\n",sfip_ntoa(&station->stationip));
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+}
+
+
+/* FWSamFree: Disconnects all FW-1 management stations,
+ * closes sockets, and frees the structures.
+ */
+void FWsamFree(FWsamList *list)
+{
+ FWsamList *next;
+
+ while(list) /* Free pointer list for rule type */
+ {
+ next=list->next;
+ free(list);
+ list=next;
+ }
+ list=FWsamStationList;
+
+ while(list) /* Free global pointer list and stations */
+ {
+ next=list->next;
+ if (list->station)
+ {
+ if(list->station->stationip.ip32[0])
+ //if(list->station->stationip.s_addr)
+ FWsamCheckOut(list->station); /* Send a Check-Out to SnortSam, */
+
+ TwoFishDestroy(list->station->stationfish); /* toss the fish, */
+ free(list->station); /* free station, */
+ }
+ free(list); /* free pointer, */
+ list=next; /* and move to next. */
+ }
+ FWsamStationList=NULL;
+ if(FWsamOptionField)
+ free(FWsamOptionField);
+}
+
+void AlertFWsamCleanExitFunc(int signal, void *arg)
+{ FWsamList *fwsamlist;
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamCleanExitFunc) Exiting...\n");
+#endif
+
+ fwsamlist=(FWsamList *)arg;
+ FWsamFree(fwsamlist); /* Free all elements */
+}
+
+void AlertFWsamRestartFunc(int signal, void *arg)
+{ FWsamList *fwsamlist;
+
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](AlertFWsamRestartFunc) Restarting...\n");
+#endif
+
+ fwsamlist=(FWsamList *)arg;
+ FWsamFree(fwsamlist); /* Free all elements */
+}
+
+/* This routine registers this Snort sensor with SnortSam.
+ * It will also change the encryption key based on some variables.
+ */
+int FWsamCheckIn(FWsamStation *station)
+{ int i,len,stationok=TRUE;
+ FWsamPacket sampacket;
+ char *encbuf,*decbuf;
+ //unsigned char *encbuf,*decbuf;
+ SOCKET stationsocket;
+
+
+ /* create a socket for the station */
+ stationsocket=socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
+ if(stationsocket==INVALID_SOCKET)
+ FatalError("ERROR => [Alert_FWsam](FWsamCheckIn) Funky socket error (socket)!\n");
+ if(bind(stationsocket,(struct sockaddr *)&(station->localsocketaddr),sizeof(struct sockaddr)))
+ FatalError("ERROR => [Alert_FWsam](FWsamCheckIn) Could not bind socket!\n");
+
+ i=TRUE;
+ /* let's connect to the agent */
+ if(connect(stationsocket,(struct sockaddr *)&station->stationsocketaddr,sizeof(struct sockaddr)))
+ LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Could not connect to host %s. Will try later.\n",sfip_ntoa(&station->stationip));
+ else
+ { LogMessage("INFO => [Alert_FWsam](FWsamCheckIn) Connected to host %s.\n",sfip_ntoa(&station->stationip));
+ /* now build the packet */
+ sampacket.endiancheck=1;
+ sampacket.snortseqno[0]=(char)station->myseqno; /* fill my sequence number number */
+ sampacket.snortseqno[1]=(char)(station->myseqno>>8); /* fill my sequence number number */
+ sampacket.status=FWSAM_STATUS_CHECKIN; /* let's check in */
+ sampacket.version=FWSAM_PACKETVERSION; /* set the packet version */
+ memcpy(sampacket.duration,station->mykeymod,4); /* we'll send SnortSam our key modifier in the duration slot */
+ /* (the checkin packet is just the plain initial key) */
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Sending CheckIn\n");
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Snort SeqNo: %x\n",station->myseqno);
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Mode : %i\n",sampacket.status);
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Version : %i\n",sampacket.version);
+#endif
+ encbuf=TwoFishAlloc(sizeof(FWsamPacket),FALSE,FALSE,station->stationfish); /* get buffer for encryption */
+ len=TwoFishEncrypt((char *)&sampacket,&encbuf,sizeof(FWsamPacket),FALSE,station->stationfish); /* encrypt with initial key */
+ if(send(stationsocket,encbuf,len,0)!=len) /* weird...could not send */
+ LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Could not send to host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+ else
+ { i=FWSAM_NETWAIT;
+#ifdef WIN32
+ ioctlsocket(stationsocket,FIONBIO,&i); /* set non blocking and wait for */
+#else
+ ioctl(stationsocket,FIONBIO,&i); /* set non blocking and wait for */
+#endif
+ while(i-- >1)
+ { waitms(10); /* wait a maximum of 3 secs for response */
+ if(recv(stationsocket,encbuf,len,0)==len)
+ i=0;
+ }
+ if(!i) /* time up? */
+ LogMessage("WARNING => [Alert_FWsam](FWsamCheckIn) Did not receive response from host %s. Will try again later.\n",sfip_ntoa(&station->stationip));
+ else
+ { decbuf=(char *)&sampacket; /* got status packet */
+ len=TwoFishDecrypt(encbuf,&decbuf,sizeof(FWsamPacket)+TwoFish_BLOCK_SIZE,FALSE,station->stationfish); /* try to decrypt with initial key */
+ if(len==sizeof(FWsamPacket)) /* valid decryption */
+ {
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Received %s\n",sampacket.status==FWSAM_STATUS_OK?"OK":
+ sampacket.status==FWSAM_STATUS_NEWKEY?"NEWKEY":
+ sampacket.status==FWSAM_STATUS_RESYNC?"RESYNC":
+ sampacket.status==FWSAM_STATUS_HOLD?"HOLD":"ERROR");
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Snort SeqNo: %x\n",sampacket.snortseqno[0]|(sampacket.snortseqno[1]<<8));
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Mgmt SeqNo : %x\n",sampacket.fwseqno[0]|(sampacket.fwseqno[1]<<8));
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Status : %i\n",sampacket.status);
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Version : %i\n",sampacket.version);
+#endif
+ if(sampacket.version==FWSAM_PACKETVERSION) /* master speaks my language */
+ { if(sampacket.status==FWSAM_STATUS_OK || sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC)
+ { station->stationseqno=sampacket.fwseqno[0]|(sampacket.fwseqno[1]<<8); /* get stations seqno */
+ station->lastcontact=(unsigned long)time(NULL);
+
+ if(sampacket.status==FWSAM_STATUS_NEWKEY || sampacket.status==FWSAM_STATUS_RESYNC) /* generate new keys */
+ { memcpy(station->fwkeymod,sampacket.duration,4); /* note the key modifier */
+ FWsamNewStationKey(station,&sampacket); /* and generate new TwoFish keys (with key modifiers) */
+#ifdef FWSAMDEBUG
+ LogMessage("DEBUG => [Alert_FWsam](FWsamCheckIn) Generated new encryption key...\n");
+#endif
+ }
+ }
+ else /* weird, got a strange status back */
+ { ErrorMessage("ERROR => [Alert_FWsam](FWsamCheckIn) Funky handshake error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ stationok=FALSE;
+ }
+ }
+ else /* packet version does not match */
+ { ErrorMessage("ERROR =>[Alert_FWsam](FWsamCheckIn) Protocol version error! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ stationok=FALSE;
+ }
+ }
+ else /* key does not match */
+ { ErrorMessage("ERROR => [Alert_FWsam](FWsamCheckIn) Password mismatch! Ignoring host %s.\n",sfip_ntoa(&station->stationip));
+ stationok=FALSE;
+ }
+ }
+ }
+ free(encbuf); /* release TwoFishAlloc'ed buffer */
+ }
+#ifdef WIN32
+ closesocket(stationsocket);
+#else
+ close(stationsocket);
+#endif
+ return stationok;
+}
+#undef FWSAMDEBUG
+
diff -ruN snort-2.9.2.2/src/output-plugins/spo_alert_fwsam.h snort-2.9.2.2_bkup/src/output-plugins/spo_alert_fwsam.h
--- snort-2.9.2.2/src/output-plugins/spo_alert_fwsam.h 1969-12-31 16:00:00.000000000 -0800
+++ snort-2.9.2.2_bkup/src/output-plugins/spo_alert_fwsam.h 2012-04-08 20:34:57.389687124 -0700
@@ -0,0 +1,216 @@
+/* $Id: snortpatchb,v 1.5 2005/10/06 08:50:39 fknobbe Exp $
+**
+** spo_alert_fwsam.h
+**
+** Copyright (c) 2001-2004 Frank Knobbe <frank@knobbe.us>
+**
+** This program is free software; you can redistribute it and/or modify
+** it under the terms of the GNU General Public License as published by
+** the Free Software Foundation; either version 2 of the License, or
+** (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+** GNU General Public License for more details.
+**
+** You should have received a copy of the GNU General Public License
+** along with this program; if not, write to the Free Software
+** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+/* This file gets included in plugbase.c when it is integrated into the rest
+ * of the program.
+ *
+ * For more info, see the beginning of spo_alert_fwsam.c
+ *
+ */
+
+#ifndef __SPO_FWSAM_H__
+#define __SPO_FWSAM_H__
+
+#include "snort.h"
+#include "rules.h"
+#include "plugbase.h"
+#include "plugin_enum.h"
+#include "fatal.h"
+#include "util.h"
+#include "twofish.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+
+
+/* just some compatibility stuff */
+#ifdef WIN32
+#if !defined(_WINSOCKAPI_) && !defined(_WINSOCK2API_)
+#include <winsock.h>
+#endif
+#define waitms(x) Sleep(x)
+
+#else
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+#include <netdb.h>
+
+#ifdef SOLARIS
+#include <sys/filio.h>
+#endif
+
+typedef int SOCKET;
+
+#ifndef INVALID_SOCKET
+#define INVALID_SOCKET -1
+#endif
+
+#define waitms(x) usleep((x)*1000)
+
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+#ifndef bool
+#define bool int
+#endif
+
+
+#if defined(_DEBUG) || defined(DEBUG)
+#ifndef FWSAMDEBUG
+#define FWSAMDEBUG
+#endif
+#else
+#endif
+
+
+/* Official Snort PlugIn Number has been moved into plugin_enum.h */
+
+
+/* fixed defines */
+
+#define FWSAM_DEFAULTPORT 898 /* Default port if user does not specify one in snort.conf */
+ /* (Was unused last time I checked...) */
+#define FWSAM_PACKETVERSION 14 /* version of the packet. Will increase with enhancements. */
+
+#define FWSAM_STATUS_CHECKIN 1 /* snort to fw */
+#define FWSAM_STATUS_CHECKOUT 2
+#define FWSAM_STATUS_BLOCK 3
+#define FWSAM_STATUS_UNBLOCK 9
+
+#define FWSAM_STATUS_OK 4 /* fw to snort */
+#define FWSAM_STATUS_ERROR 5
+#define FWSAM_STATUS_NEWKEY 6
+#define FWSAM_STATUS_RESYNC 7
+#define FWSAM_STATUS_HOLD 8
+
+#define FWSAM_LOG_NONE 0
+#define FWSAM_LOG_SHORTLOG 1
+#define FWSAM_LOG_SHORTALERT 2
+#define FWSAM_LOG_LONGLOG 3
+#define FWSAM_LOG_LONGALERT 4
+#define FWSAM_LOG (FWSAM_LOG_SHORTLOG|FWSAM_LOG_SHORTALERT|FWSAM_LOG_LONGLOG|FWSAM_LOG_LONGALERT)
+#define FWSAM_WHO_DST 8
+#define FWSAM_WHO_SRC 16
+#define FWSAM_WHO (FWSAM_WHO_DST|FWSAM_WHO_SRC)
+#define FWSAM_HOW_IN 32
+#define FWSAM_HOW_OUT 64
+#define FWSAM_HOW_INOUT (FWSAM_HOW_IN|FWSAM_HOW_OUT)
+#define FWSAM_HOW_THIS 128
+#define FWSAM_HOW (FWSAM_HOW_IN|FWSAM_HOW_OUT|FWSAM_HOW_THIS)
+
+
+/* user adjustable defines */
+
+#define FWSAM_REPET_BLOCKS 10 /* Snort remembers this amount of last blocks and... */
+#define FWSAM_REPET_TIME 20 /* ...checks if they fall within this time. If so,... */
+ /* ...the blocking request is not send. */
+
+#define FWSAM_NETWAIT 300 /* 100th of a second. 3 sec timeout for network connections */
+#define FWSAM_NETHOLD 6000 /* 100th of a second. 60 sec timeout for holding */
+
+#define SID_MAPFILE "sid-block.map"
+#define SID_ALT_MAPFILE "sid-fwsam.map"
+
+#define FWSAM_FANCYFETCH /* This will invoke a fast sid lookup routine */
+
+
+/* vars */
+
+typedef struct _FWsamstation /* structure of a mgmt station */
+{ unsigned short myseqno;
+ unsigned short stationseqno;
+ unsigned char mykeymod[4];
+ unsigned char fwkeymod[4];
+ unsigned short stationport;
+ //struct in_addr stationip;
+ sfip_t stationip;
+ struct sockaddr_in localsocketaddr;
+ struct sockaddr_in stationsocketaddr;
+ TWOFISH *stationfish;
+ char initialkey[TwoFish_KEY_LENGTH+2];
+ char stationkey[TwoFish_KEY_LENGTH+2];
+ time_t lastcontact;
+/* time_t sleepstart; */
+} FWsamStation;
+
+typedef struct _FWsampacket /* 2 blocks (3rd block is header from TwoFish) */
+{ unsigned short endiancheck; /* 0 */
+ unsigned char srcip[4]; /* 2 */
+ unsigned char dstip[4]; /* 6 */
+ unsigned char duration[4]; /* 10 */
+ unsigned char snortseqno[2]; /* 14 */
+ unsigned char fwseqno[2]; /* 16 */
+ unsigned char srcport[2]; /* 18 */
+ unsigned char dstport[2]; /* 20 */
+ unsigned char protocol[2]; /* 22 */
+ unsigned char fwmode; /* 24 */
+ unsigned char version; /* 25 */
+ unsigned char status; /* 26 */
+ unsigned char sig_id[4]; /* 27 */
+ unsigned char fluff; /* 31 */
+} FWsamPacket; /* 32 bytes in size */
+
+typedef struct _FWsamoptions /* snort rule options */
+{ unsigned long sid;
+ unsigned long duration;
+ unsigned char who;
+ unsigned char how;
+ unsigned char loglevel;
+} FWsamOptions;
+
+typedef struct _FWsamlistpointer
+{ FWsamStation *station;
+ struct _FWsamlistpointer *next;
+} FWsamList;
+
+
+/* functions */
+void AlertFWsamSetup(void);
+void AlertFWsamInit(char *args);
+void AlertFWsamOptionInit(char *args,OptTreeNode *otn,int protocol);
+void AlertFWsamCleanExitFunc(int signal, void *arg);
+void AlertFWsamRestartFunc(int signal, void *arg);
+void AlertFWsam(Packet *p, char *msg, void *arg, Event *event);
+int FWsamCheckIn(FWsamStation *station);
+void FWsamCheckOut(FWsamStation *station);
+void FWsamNewStationKey(FWsamStation *station,FWsamPacket *packet);
+void FWsamFixPacketEndian(FWsamPacket *p);
+unsigned long FWsamParseDuration(char *p);
+void FWsamFree(FWsamList *fwsamlist);
+int FWsamStationExists(FWsamStation *who,FWsamList *list);
+int FWsamReadLine(char *,unsigned long,FILE *);
+void FWsamParseLine(FWsamOptions *,char *);
+FWsamOptions *FWsamGetOption(unsigned long);
+int FWsamParseOption(FWsamOptions *,char *);
+
+#endif /* __SPO_FWSAM_H__ */
diff -ruN snort-2.9.2.2/src/plugbase.c snort-2.9.2.2_bkup/src/plugbase.c
--- snort-2.9.2.2/src/plugbase.c 2012-03-17 14:40:16.000000000 -0700
+++ snort-2.9.2.2_bkup/src/plugbase.c 2012-04-08 20:34:57.389687124 -0700
@@ -130,6 +130,7 @@
#endif
#include "output-plugins/spo_alert_test.h"
+#include "output-plugins/spo_alert_fwsam.h"
extern ListHead *head_tmp;
extern PreprocConfigFuncNode *preproc_config_funcs;
@@ -1520,6 +1521,7 @@
#endif
AlertTestSetup();
+ AlertFWsamSetup();
}
/****************************************************************************
diff -ruN snort-2.9.2.2/src/plugin_enum.h snort-2.9.2.2_bkup/src/plugin_enum.h
--- snort-2.9.2.2/src/plugin_enum.h 2012-01-12 14:11:40.000000000 -0800
+++ snort-2.9.2.2_bkup/src/plugin_enum.h 2012-04-08 20:34:57.389687124 -0700
@@ -60,6 +60,7 @@
PLUGIN_URILEN_CHECK,
PLUGIN_DYNAMIC,
PLUGIN_FLOWBIT,
+ PLUGIN_FWSAM,
PLUGIN_FILE_DATA,
PLUGIN_BASE64_DECODE,
PLUGIN_MAX /* sentinel value */
diff -ruN snort-2.9.2.2/src/twofish.c snort-2.9.2.2_bkup/src/twofish.c
--- snort-2.9.2.2/src/twofish.c 1969-12-31 16:00:00.000000000 -0800
+++ snort-2.9.2.2_bkup/src/twofish.c 2012-04-08 20:34:57.389687124 -0700
@@ -0,0 +1,971 @@
+/* $Id: twofish.c,v 2.1 2008/12/15 20:36:05 fknobbe Exp $
+ *
+ *
+ * Copyright (C) 1997-2000 The Cryptix Foundation Limited.
+ * Copyright (C) 2000 Farm9.
+ * Copyright (C) 2001 Frank Knobbe.
+ * All rights reserved.
+ *
+ * For Cryptix code:
+ * Use, modification, copying and distribution of this software is subject
+ * the terms and conditions of the Cryptix General Licence. You should have
+ * received a copy of the Cryptix General Licence along with this library;
+ * if not, you can download a copy from http://www.cryptix.org/ .
+ *
+ * For Farm9:
+ * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and
+ * ciphertext stealing technique, added AsciiTwofish class for easy encryption
+ * decryption of text strings
+ *
+ * Frank Knobbe <frank@knobbe.us>:
+ * --- April 2001, converted from C++ to C, prefixed global variables
+ * with TwoFish, substituted some defines, changed functions to make use of
+ * variables supplied in a struct, modified and added routines for modular calls.
+ * Cleaned up the code so that defines are used instead of fixed 16's and 32's.
+ * Created two general purpose crypt routines for one block and multiple block
+ * encryption using Joh's CBC code.
+ * Added crypt routines that use a header (with a magic and data length).
+ * (Basically a major rewrite).
+ *
+ * Note: Routines labeled _TwoFish are private and should not be used
+ * (or with extreme caution).
+ *
+ */
+
+#ifndef __TWOFISH_LIBRARY_SOURCE__
+#define __TWOFISH_LIBRARY_SOURCE__
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#ifdef WIN32
+
+#ifndef u_long
+typedef unsigned long u_long;
+#endif
+#ifndef u_int32_t
+typedef unsigned long u_int32_t;
+#endif
+#ifndef u_word
+typedef unsigned short u_word;
+#endif
+#ifndef u_int16_t
+typedef unsigned short u_int16_t;
+#endif
+#ifndef u_char
+typedef unsigned char u_char;
+#endif
+#ifndef u_int8_t
+typedef unsigned char u_int8_t;
+#endif
+
+#endif /* WIN32 */
+
+#include "twofish.h"
+
+
+bool TwoFish_srand=TRUE; /* if TRUE, first call of TwoFishInit will seed rand(); */
+ /* of TwoFishInit */
+
+/* Fixed 8x8 permutation S-boxes */
+static const u_int8_t TwoFish_P[2][256] =
+{
+ { /* p0 */
+ 0xA9, 0x67, 0xB3, 0xE8, 0x04, 0xFD, 0xA3, 0x76, 0x9A, 0x92, 0x80, 0x78,
+ 0xE4, 0xDD, 0xD1, 0x38, 0x0D, 0xC6, 0x35, 0x98, 0x18, 0xF7, 0xEC, 0x6C,
+ 0x43, 0x75, 0x37, 0x26, 0xFA, 0x13, 0x94, 0x48, 0xF2, 0xD0, 0x8B, 0x30,
+ 0x84, 0x54, 0xDF, 0x23, 0x19, 0x5B, 0x3D, 0x59, 0xF3, 0xAE, 0xA2, 0x82,
+ 0x63, 0x01, 0x83, 0x2E, 0xD9, 0x51, 0x9B, 0x7C, 0xA6, 0xEB, 0xA5, 0xBE,
+ 0x16, 0x0C, 0xE3, 0x61, 0xC0, 0x8C, 0x3A, 0xF5, 0x73, 0x2C, 0x25, 0x0B,
+ 0xBB, 0x4E, 0x89, 0x6B, 0x53, 0x6A, 0xB4, 0xF1, 0xE1, 0xE6, 0xBD, 0x45,
+ 0xE2, 0xF4, 0xB6, 0x66, 0xCC, 0x95, 0x03, 0x56, 0xD4, 0x1C, 0x1E, 0xD7,
+ 0xFB, 0xC3, 0x8E, 0xB5, 0xE9, 0xCF, 0xBF, 0xBA, 0xEA, 0x77, 0x39, 0xAF,
+ 0x33, 0xC9, 0x62, 0x71, 0x81, 0x79, 0x09, 0xAD, 0x24, 0xCD, 0xF9, 0xD8,
+ 0xE5, 0xC5, 0xB9, 0x4D, 0x44, 0x08, 0x86, 0xE7, 0xA1, 0x1D, 0xAA, 0xED,
+ 0x06, 0x70, 0xB2, 0xD2, 0x41, 0x7B, 0xA0, 0x11, 0x31, 0xC2, 0x27, 0x90,
+ 0x20, 0xF6, 0x60, 0xFF, 0x96, 0x5C, 0xB1, 0xAB, 0x9E, 0x9C, 0x52, 0x1B,
+ 0x5F, 0x93, 0x0A, 0xEF, 0x91, 0x85, 0x49, 0xEE, 0x2D, 0x4F, 0x8F, 0x3B,
+ 0x47, 0x87, 0x6D, 0x46, 0xD6, 0x3E, 0x69, 0x64, 0x2A, 0xCE, 0xCB, 0x2F,
+ 0xFC, 0x97, 0x05, 0x7A, 0xAC, 0x7F, 0xD5, 0x1A, 0x4B, 0x0E, 0xA7, 0x5A,
+ 0x28, 0x14, 0x3F, 0x29, 0x88, 0x3C, 0x4C, 0x02, 0xB8, 0xDA, 0xB0, 0x17,
+ 0x55, 0x1F, 0x8A, 0x7D, 0x57, 0xC7, 0x8D, 0x74, 0xB7, 0xC4, 0x9F, 0x72,
+ 0x7E, 0x15, 0x22, 0x12, 0x58, 0x07, 0x99, 0x34, 0x6E, 0x50, 0xDE, 0x68,
+ 0x65, 0xBC, 0xDB, 0xF8, 0xC8, 0xA8, 0x2B, 0x40, 0xDC, 0xFE, 0x32, 0xA4,
+ 0xCA, 0x10, 0x21, 0xF0, 0xD3, 0x5D, 0x0F, 0x00, 0x6F, 0x9D, 0x36, 0x42,
+ 0x4A, 0x5E, 0xC1, 0xE0
+ },
+ { /* p1 */
+ 0x75, 0xF3, 0xC6, 0xF4, 0xDB, 0x7B, 0xFB, 0xC8, 0x4A, 0xD3, 0xE6, 0x6B,
+ 0x45, 0x7D, 0xE8, 0x4B, 0xD6, 0x32, 0xD8, 0xFD, 0x37, 0x71, 0xF1, 0xE1,
+ 0x30, 0x0F, 0xF8, 0x1B, 0x87, 0xFA, 0x06, 0x3F, 0x5E, 0xBA, 0xAE, 0x5B,
+ 0x8A, 0x00, 0xBC, 0x9D, 0x6D, 0xC1, 0xB1, 0x0E, 0x80, 0x5D, 0xD2, 0xD5,
+ 0xA0, 0x84, 0x07, 0x14, 0xB5, 0x90, 0x2C, 0xA3, 0xB2, 0x73, 0x4C, 0x54,
+ 0x92, 0x74, 0x36, 0x51, 0x38, 0xB0, 0xBD, 0x5A, 0xFC, 0x60, 0x62, 0x96,
+ 0x6C, 0x42, 0xF7, 0x10, 0x7C, 0x28, 0x27, 0x8C, 0x13, 0x95, 0x9C, 0xC7,
+ 0x24, 0x46, 0x3B, 0x70, 0xCA, 0xE3, 0x85, 0xCB, 0x11, 0xD0, 0x93, 0xB8,
+ 0xA6, 0x83, 0x20, 0xFF, 0x9F, 0x77, 0xC3, 0xCC, 0x03, 0x6F, 0x08, 0xBF,
+ 0x40, 0xE7, 0x2B, 0xE2, 0x79, 0x0C, 0xAA, 0x82, 0x41, 0x3A, 0xEA, 0xB9,
+ 0xE4, 0x9A, 0xA4, 0x97, 0x7E, 0xDA, 0x7A, 0x17, 0x66, 0x94, 0xA1, 0x1D,
+ 0x3D, 0xF0, 0xDE, 0xB3, 0x0B, 0x72, 0xA7, 0x1C, 0xEF, 0xD1, 0x53, 0x3E,
+ 0x8F, 0x33, 0x26, 0x5F, 0xEC, 0x76, 0x2A, 0x49, 0x81, 0x88, 0xEE, 0x21,
+ 0xC4, 0x1A, 0xEB, 0xD9, 0xC5, 0x39, 0x99, 0xCD, 0xAD, 0x31, 0x8B, 0x01,
+ 0x18, 0x23, 0xDD, 0x1F, 0x4E, 0x2D, 0xF9, 0x48, 0x4F, 0xF2, 0x65, 0x8E,
+ 0x78, 0x5C, 0x58, 0x19, 0x8D, 0xE5, 0x98, 0x57, 0x67, 0x7F, 0x05, 0x64,
+ 0xAF, 0x63, 0xB6, 0xFE, 0xF5, 0xB7, 0x3C, 0xA5, 0xCE, 0xE9, 0x68, 0x44,
+ 0xE0, 0x4D, 0x43, 0x69, 0x29, 0x2E, 0xAC, 0x15, 0x59, 0xA8, 0x0A, 0x9E,
+ 0x6E, 0x47, 0xDF, 0x34, 0x35, 0x6A, 0xCF, 0xDC, 0x22, 0xC9, 0xC0, 0x9B,
+ 0x89, 0xD4, 0xED, 0xAB, 0x12, 0xA2, 0x0D, 0x52, 0xBB, 0x02, 0x2F, 0xA9,
+ 0xD7, 0x61, 0x1E, 0xB4, 0x50, 0x04, 0xF6, 0xC2, 0x16, 0x25, 0x86, 0x56,
+ 0x55, 0x09, 0xBE, 0x91
+ }
+};
+
+static bool TwoFish_MDSready=FALSE;
+static u_int32_t TwoFish_MDS[4][256]; /* TwoFish_MDS matrix */
+
+
+#define TwoFish_LFSR1(x) (((x)>>1)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/2:0))
+#define TwoFish_LFSR2(x) (((x)>>2)^(((x)&0x02)?TwoFish_MDS_GF_FDBK/2:0)^(((x)&0x01)?TwoFish_MDS_GF_FDBK/4:0))
+
+#define TwoFish_Mx_1(x) ((u_int32_t)(x)) /* force result to dword so << will work */
+#define TwoFish_Mx_X(x) ((u_int32_t)((x)^TwoFish_LFSR2(x))) /* 5B */
+#define TwoFish_Mx_Y(x) ((u_int32_t)((x)^TwoFish_LFSR1(x)^TwoFish_LFSR2(x))) /* EF */
+#define TwoFish_RS_rem(x) { u_int8_t b=(u_int8_t)(x>>24); u_int32_t g2=((b<<1)^((b&0x80)?TwoFish_RS_GF_FDBK:0))&0xFF; u_int32_t g3=((b>>1)&0x7F)^((b&1)?TwoFish_RS_GF_FDBK>>1:0)^g2; x=(x<<8)^(g3<<24)^(g2<<16)^(g3<<8)^b; }
+
+/*#define TwoFish__b(x,N) (((u_int8_t *)&x)[((N)&3)^TwoFish_ADDR_XOR])*/ /* pick bytes out of a dword */
+
+#define TwoFish_b0(x) TwoFish__b(x,0) /* extract LSB of u_int32_t */
+#define TwoFish_b1(x) TwoFish__b(x,1)
+#define TwoFish_b2(x) TwoFish__b(x,2)
+#define TwoFish_b3(x) TwoFish__b(x,3) /* extract MSB of u_int32_t */
+
+u_int8_t TwoFish__b(u_int32_t x,int n)
+{ n&=3;
+ while(n-->0)
+ x>>=8;
+ return (u_int8_t)x;
+}
+
+
+/* TwoFish Initialization
+ *
+ * This routine generates a global data structure for use with TwoFish,
+ * initializes important values (such as subkeys, sBoxes), generates subkeys
+ * and precomputes the MDS matrix if not already done.
+ *
+ * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!')
+ *
+ * Output: Pointer to TWOFISH structure. This data structure contains key dependent data.
+ * This pointer is used with all other crypt functions.
+ */
+
+TWOFISH *TwoFishInit(char *userkey)
+{ TWOFISH *tfdata;
+ int i,x,m;
+ char tkey[TwoFish_KEY_LENGTH+40];
+
+ tfdata=malloc(sizeof(TWOFISH)); /* allocate the TwoFish structure */
+ if(tfdata!=NULL)
+ { if(*userkey)
+ { strncpy(tkey,userkey,TwoFish_KEY_LENGTH); /* use first 32 chars of user supplied password */
+ tkey[TwoFish_KEY_LENGTH]=0; /* make sure it wasn't more */
+ }
+ else
+ strcpy(tkey,TwoFish_DEFAULT_PW); /* if no key defined, use default password */
+ for(i=0,x=0,m=strlen(tkey);i<TwoFish_KEY_LENGTH;i++) /* copy into data structure */
+ { tfdata->key[i]=tkey[x++]; /* fill the whole keyspace with repeating key. */
+ if(x==m)
+ x=0;
+ }
+
+ if(!TwoFish_MDSready)
+ _TwoFish_PrecomputeMDSmatrix(); /* "Wake Up, Neo" */
+ _TwoFish_MakeSubKeys(tfdata); /* generate subkeys */
+ _TwoFish_ResetCBC(tfdata); /* reset the CBC */
+ tfdata->output=NULL; /* nothing to output yet */
+ tfdata->dontflush=FALSE; /* reset decrypt skip block flag */
+ if(TwoFish_srand)
+ { TwoFish_srand=FALSE;
+ srand(time(NULL));
+ }
+ }
+ return tfdata; /* return the data pointer */
+}
+
+
+void TwoFishDestroy(TWOFISH *tfdata)
+{ if(tfdata!=NULL)
+ free(tfdata);
+}
+
+
+/* en/decryption with CBC mode */
+unsigned long _TwoFish_CryptRawCBC(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata)
+{ unsigned long rl;
+
+ rl=len; /* remember how much data to crypt. */
+ while(len>TwoFish_BLOCK_SIZE) /* and now we process block by block. */
+ { _TwoFish_BlockCrypt(in,out,TwoFish_BLOCK_SIZE,decrypt,tfdata); /* de/encrypt it. */
+ in+=TwoFish_BLOCK_SIZE; /* adjust pointers. */
+ out+=TwoFish_BLOCK_SIZE;
+ len-=TwoFish_BLOCK_SIZE;
+ }
+ if(len>0) /* if we have less than a block left... */
+ _TwoFish_BlockCrypt(in,out,len,decrypt,tfdata); /* ...then we de/encrypt that too. */
+ if(tfdata->qBlockDefined && !tfdata->dontflush) /* in case len was exactly one block... */
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata); /* ...we need to write the... */
+ /* ...remaining bytes of the buffer */
+ return rl;
+}
+
+/* en/decryption on one block only */
+unsigned long _TwoFish_CryptRaw16(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata)
+{ /* qBlockPlain already zero'ed through ResetCBC */
+ memcpy(tfdata->qBlockPlain,in,len); /* toss the data into it. */
+ _TwoFish_BlockCrypt16(tfdata->qBlockPlain,tfdata->qBlockCrypt,decrypt,tfdata); /* encrypt just that block without CBC. */
+ memcpy(out,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE); /* and return what we got */
+ return TwoFish_BLOCK_SIZE;
+}
+
+/* en/decryption without reset of CBC and output assignment */
+unsigned long _TwoFish_CryptRaw(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata)
+{
+ if(in!=NULL && out!=NULL && len>0 && tfdata!=NULL) /* if we have valid data, then... */
+ { if(len>TwoFish_BLOCK_SIZE) /* ...check if we have more than one block. */
+ return _TwoFish_CryptRawCBC(in,out,len,decrypt,tfdata); /* if so, use the CBC routines... */
+ else
+ return _TwoFish_CryptRaw16(in,out,len,decrypt,tfdata); /* ...otherwise just do one block. */
+ }
+ return 0;
+}
+
+
+/* TwoFish Raw Encryption
+ *
+ * Does not use header, but does use CBC (if more than one block has to be encrypted).
+ *
+ * Input: Pointer to the buffer of the plaintext to be encrypted.
+ * Pointer to the buffer receiving the ciphertext.
+ * The length of the plaintext buffer.
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes encrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishEncryptRaw(char *in,
+ char *out,
+ unsigned long len,
+ TWOFISH *tfdata)
+{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */
+ tfdata->output=out; /* output straight into output buffer. */
+ return _TwoFish_CryptRaw(in,out,len,FALSE,tfdata); /* and go for it. */
+}
+
+/* TwoFish Raw Decryption
+ *
+ * Does not use header, but does use CBC (if more than one block has to be decrypted).
+ *
+ * Input: Pointer to the buffer of the ciphertext to be decrypted.
+ * Pointer to the buffer receiving the plaintext.
+ * The length of the ciphertext buffer (at least one cipher block).
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes decrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishDecryptRaw(char *in,
+ char *out,
+ unsigned long len,
+ TWOFISH *tfdata)
+{ _TwoFish_ResetCBC(tfdata); /* reset CBC flag. */
+ tfdata->output=out; /* output straight into output buffer. */
+ return _TwoFish_CryptRaw(in,out,len,TRUE,tfdata); /* and go for it. */
+}
+
+/* TwoFish Free
+ *
+ * Free's the allocated buffer.
+ *
+ * Input: Pointer to the TwoFish structure
+ *
+ * Output: (none)
+ */
+
+void TwoFishFree(TWOFISH *tfdata)
+{ if(tfdata->output!=NULL) /* if a valid buffer is present... */
+ { free(tfdata->output); /* ...then we free it for you... */
+ tfdata->output=NULL; /* ...and mark as such. */
+ }
+}
+
+/* TwoFish Set Output
+ *
+ * If you want to allocate the output buffer yourself,
+ * then you can set it with this function.
+ *
+ * Input: Pointer to your output buffer
+ * Pointer to the TwoFish structure
+ *
+ * Output: (none)
+ */
+
+void TwoFishSetOutput(char *outp,TWOFISH *tfdata)
+{ tfdata->output=outp; /* (do we really need a function for this?) */
+}
+
+/* TwoFish Alloc
+ *
+ * Allocates enough memory for the output buffer that would be required
+ *
+ * Input: Length of the plaintext.
+ * Boolean flag for BinHex Output.
+ * Pointer to the TwoFish structure.
+ *
+ * Output: Returns a pointer to the memory allocated.
+ */
+
+void *TwoFishAlloc(unsigned long len,bool binhex,bool decrypt,TWOFISH *tfdata)
+{
+/* TwoFishFree(tfdata); */ /* (don't for now) discard whatever was allocated earlier. */
+ if(decrypt) /* if decrypting... */
+ { if(binhex) /* ...and input is binhex encoded... */
+ len/=2; /* ...use half as much for output. */
+ len-=TwoFish_BLOCK_SIZE; /* Also, subtract the size of the header. */
+ }
+ else
+ { len+=TwoFish_BLOCK_SIZE; /* the size is just increased by the header... */
+ if(binhex)
+ len*=2; /* ...and doubled if output is to be binhexed. */
+ }
+ tfdata->output=malloc(len+TwoFish_BLOCK_SIZE);/* grab some memory...plus some extra (it's running over somewhere, crashes without extra padding) */
+
+ return tfdata->output; /* ...and return to caller. */
+}
+
+/* bin2hex and hex2bin conversion */
+void _TwoFish_BinHex(u_int8_t *buf,unsigned long len,bool bintohex)
+{ u_int8_t *pi,*po,c;
+
+ if(bintohex)
+ { for(pi=buf+len-1,po=buf+(2*len)-1;len>0;pi--,po--,len--) /* let's start from the end of the bin block. */
+ { c=*pi; /* grab value. */
+ c&=15; /* use lower 4 bits. */
+ if(c>9) /* convert to ascii. */
+ c+=('a'-10);
+ else
+ c+='0';
+ *po--=c; /* set the lower nibble. */
+ c=*pi; /* grab value again. */
+ c>>=4; /* right shift 4 bits. */
+ c&=15; /* make sure we only have 4 bits. */
+ if(c>9) /* convert to ascii. */
+ c+=('a'-10);
+ else
+ c+='0';
+ *po=c; /* set the higher nibble. */
+ } /* and keep going. */
+ }
+ else
+ { for(pi=buf,po=buf;len>0;pi++,po++,len-=2) /* let's start from the beginning of the hex block. */
+ { c=tolower(*pi++)-'0'; /* grab higher nibble. */
+ if(c>9) /* convert to value. */
+ c-=('0'-9);
+ *po=c<<4; /* left shit 4 bits. */
+ c=tolower(*pi)-'0'; /* grab lower nibble. */
+ if(c>9) /* convert to value. */
+ c-=('0'-9);
+ *po|=c; /* and add to value. */
+ }
+ }
+}
+
+
+/* TwoFish Encryption
+ *
+ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ * this routine will alloc the memory. In addition, it will include a small 'header'
+ * containing the magic and some salt. That way the decrypt routine can check if the
+ * packet got decrypted successfully, and return 0 instead of garbage.
+ *
+ * Input: Pointer to the buffer of the plaintext to be encrypted.
+ * Pointer to the pointer to the buffer receiving the ciphertext.
+ * The pointer either points to user allocated output buffer space, or to NULL, in which case
+ * this routine will set the pointer to the buffer allocated through the struct.
+ * The length of the plaintext buffer.
+ * Can be -1 if the input is a null terminated string, in which case we'll count for you.
+ * Boolean flag for BinHex Output (if used, output will be twice as large as input).
+ * Note: BinHex conversion overwrites (converts) input buffer!
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes encrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishEncrypt(char *in,
+ char **out,
+ signed long len,
+ bool binhex,
+ TWOFISH *tfdata)
+{ unsigned long ilen,olen;
+
+
+ if(len== -1) /* if we got -1 for len, we'll assume IN is a... */
+ ilen=strlen(in); /* ...\0 terminated string and figure len out ourselves... */
+ else
+ ilen=len; /* ...otherwise we trust you supply a correct length. */
+
+ if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */
+ { if(*out==NULL) /* if OUT points to a NULL pointer... */
+ *out=TwoFishAlloc(ilen,binhex,FALSE,tfdata); /* ...we'll (re-)allocate buffer space. */
+ if(*out!=NULL)
+ { tfdata->output=*out; /* set output buffer. */
+ tfdata->header.salt=rand()*65536+rand(); /* toss in some salt. */
+ tfdata->header.length[0]= (u_int8_t)(ilen);
+ tfdata->header.length[1]= (u_int8_t)(ilen>>8);
+ tfdata->header.length[2]= (u_int8_t)(ilen>>16);
+ tfdata->header.length[3]= (u_int8_t)(ilen>>24);
+ memcpy(tfdata->header.magic,TwoFish_MAGIC,TwoFish_MAGIC_LEN); /* set the magic. */
+ olen=TwoFish_BLOCK_SIZE; /* set output counter. */
+ _TwoFish_ResetCBC(tfdata); /* reset the CBC flag */
+ _TwoFish_BlockCrypt((u_int8_t *)&(tfdata->header),*out,olen,FALSE,tfdata); /* encrypt first block (without flush on 16 byte boundary). */
+ olen+=_TwoFish_CryptRawCBC(in,*out+TwoFish_BLOCK_SIZE,ilen,FALSE,tfdata); /* and encrypt the rest (we do not reset the CBC flag). */
+ if(binhex) /* if binhex... */
+ { _TwoFish_BinHex(*out,olen,TRUE); /* ...convert output to binhex... */
+ olen*=2; /* ...and size twice as large. */
+ }
+ tfdata->output=*out;
+ return olen;
+ }
+ }
+ return 0;
+}
+
+/* TwoFish Decryption
+ *
+ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ * this routine will alloc the memory. In addition, it will check the small 'header'
+ * containing the magic. If magic does not match we return 0. Otherwise we return the
+ * amount of bytes decrypted (should be the same as the length in the header).
+ *
+ * Input: Pointer to the buffer of the ciphertext to be decrypted.
+ * Pointer to the pointer to the buffer receiving the plaintext.
+ * The pointer either points to user allocated output buffer space, or to NULL, in which case
+ * this routine will set the pointer to the buffer allocated through the struct.
+ * The length of the ciphertext buffer.
+ * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you.
+ * Boolean flag for BinHex Input (if used, plaintext will be half as large as input).
+ * Note: BinHex conversion overwrites (converts) input buffer!
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes decrypted if successful, otherwise 0.
+ */
+
+unsigned long TwoFishDecrypt(char *in,
+ char **out,
+ signed long len,
+ bool binhex,
+ TWOFISH *tfdata)
+{ unsigned long ilen,elen,olen;
+ const u_int8_t cmagic[TwoFish_MAGIC_LEN]=TwoFish_MAGIC;
+ u_int8_t *tbuf;
+
+
+
+ if(len== -1) /* if we got -1 for len, we'll assume IN is... */
+ ilen=strlen(in); /* ...\0 terminated binhex and figure len out ourselves... */
+ else
+ ilen=len; /* ...otherwise we trust you supply a correct length. */
+
+ if(in!=NULL && out!=NULL && ilen>0 && tfdata!=NULL) /* if we got usable stuff, we'll do it. */
+ { if(*out==NULL) /* if OUT points to a NULL pointer... */
+ *out=TwoFishAlloc(ilen,binhex,TRUE,tfdata); /* ...we'll (re-)allocate buffer space. */
+ if(*out!=NULL)
+ { if(binhex) /* if binhex... */
+ { _TwoFish_BinHex(in,ilen,FALSE); /* ...convert input to values... */
+ ilen/=2; /* ...and size half as much. */
+ }
+ _TwoFish_ResetCBC(tfdata); /* reset the CBC flag. */
+
+ tbuf=(u_int8_t *)malloc(ilen+TwoFish_BLOCK_SIZE); /* get memory for data and header. */
+ if(tbuf==NULL)
+ return 0;
+ tfdata->output=tbuf; /* set output to temp buffer. */
+
+ olen=_TwoFish_CryptRawCBC(in,tbuf,ilen,TRUE,tfdata)-TwoFish_BLOCK_SIZE; /* decrypt the whole thing. */
+ memcpy(&(tfdata->header),tbuf,TwoFish_BLOCK_SIZE); /* copy first block into header. */
+ tfdata->output=*out;
+ for(elen=0;elen<TwoFish_MAGIC_LEN;elen++) /* compare magic. */
+ if(tfdata->header.magic[elen]!=cmagic[elen])
+ break;
+ if(elen==TwoFish_MAGIC_LEN) /* if magic matches then... */
+ { elen=(tfdata->header.length[0]) |
+ (tfdata->header.length[1])<<8 |
+ (tfdata->header.length[2])<<16 |
+ (tfdata->header.length[3])<<24; /* .. we know how much to expect. */
+ if(elen>olen) /* adjust if necessary. */
+ elen=olen;
+ memcpy(*out,tbuf+TwoFish_BLOCK_SIZE,elen); /* copy data into intended output. */
+ free(tbuf);
+ return elen;
+ }
+ free(tbuf);
+ }
+ }
+ return 0;
+}
+
+void _TwoFish_PrecomputeMDSmatrix(void) /* precompute the TwoFish_MDS matrix */
+{ u_int32_t m1[2];
+ u_int32_t mX[2];
+ u_int32_t mY[2];
+ u_int32_t i, j;
+
+ for (i = 0; i < 256; i++)
+ { j = TwoFish_P[0][i] & 0xFF; /* compute all the matrix elements */
+ m1[0] = j;
+ mX[0] = TwoFish_Mx_X( j ) & 0xFF;
+ mY[0] = TwoFish_Mx_Y( j ) & 0xFF;
+
+ j = TwoFish_P[1][i] & 0xFF;
+ m1[1] = j;
+ mX[1] = TwoFish_Mx_X( j ) & 0xFF;
+ mY[1] = TwoFish_Mx_Y( j ) & 0xFF;
+
+ TwoFish_MDS[0][i] = m1[TwoFish_P_00] | /* fill matrix w/ above elements */
+ mX[TwoFish_P_00] << 8 |
+ mY[TwoFish_P_00] << 16 |
+ mY[TwoFish_P_00] << 24;
+ TwoFish_MDS[1][i] = mY[TwoFish_P_10] |
+ mY[TwoFish_P_10] << 8 |
+ mX[TwoFish_P_10] << 16 |
+ m1[TwoFish_P_10] << 24;
+ TwoFish_MDS[2][i] = mX[TwoFish_P_20] |
+ mY[TwoFish_P_20] << 8 |
+ m1[TwoFish_P_20] << 16 |
+ mY[TwoFish_P_20] << 24;
+ TwoFish_MDS[3][i] = mX[TwoFish_P_30] |
+ m1[TwoFish_P_30] << 8 |
+ mY[TwoFish_P_30] << 16 |
+ mX[TwoFish_P_30] << 24;
+ }
+ TwoFish_MDSready=TRUE;
+}
+
+
+void _TwoFish_MakeSubKeys(TWOFISH *tfdata) /* Expand a user-supplied key material into a session key. */
+{ u_int32_t k64Cnt = TwoFish_KEY_LENGTH / 8;
+ u_int32_t k32e[4]; /* even 32-bit entities */
+ u_int32_t k32o[4]; /* odd 32-bit entities */
+ u_int32_t sBoxKey[4];
+ u_int32_t offset,i,j;
+ u_int32_t A, B, q=0;
+ u_int32_t k0,k1,k2,k3;
+ u_int32_t b0,b1,b2,b3;
+
+ /* split user key material into even and odd 32-bit entities and */
+ /* compute S-box keys using (12, 8) Reed-Solomon code over GF(256) */
+
+
+ for (offset=0,i=0,j=k64Cnt-1;i<4 && offset<TwoFish_KEY_LENGTH;i++,j--)
+ { k32e[i] = tfdata->key[offset++];
+ k32e[i]|= tfdata->key[offset++]<<8;
+ k32e[i]|= tfdata->key[offset++]<<16;
+ k32e[i]|= tfdata->key[offset++]<<24;
+ k32o[i] = tfdata->key[offset++];
+ k32o[i]|= tfdata->key[offset++]<<8;
+ k32o[i]|= tfdata->key[offset++]<<16;
+ k32o[i]|= tfdata->key[offset++]<<24;
+ sBoxKey[j] = _TwoFish_RS_MDS_Encode( k32e[i], k32o[i] ); /* reverse order */
+ }
+
+ /* compute the round decryption subkeys for PHT. these same subkeys */
+ /* will be used in encryption but will be applied in reverse order. */
+ i=0;
+ while(i < TwoFish_TOTAL_SUBKEYS)
+ { A = _TwoFish_F32( k64Cnt, q, k32e ); /* A uses even key entities */
+ q += TwoFish_SK_BUMP;
+
+ B = _TwoFish_F32( k64Cnt, q, k32o ); /* B uses odd key entities */
+ q += TwoFish_SK_BUMP;
+
+ B = B << 8 | B >> 24;
+
+ A += B;
+ tfdata->subKeys[i++] = A; /* combine with a PHT */
+
+ A += B;
+ tfdata->subKeys[i++] = A << TwoFish_SK_ROTL | A >> (32-TwoFish_SK_ROTL);
+ }
+
+ /* fully expand the table for speed */
+ k0 = sBoxKey[0];
+ k1 = sBoxKey[1];
+ k2 = sBoxKey[2];
+ k3 = sBoxKey[3];
+
+ for (i = 0; i < 256; i++)
+ { b0 = b1 = b2 = b3 = i;
+ switch (k64Cnt & 3)
+ { case 1: /* 64-bit keys */
+ tfdata->sBox[ 2*i ] = TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0]) ^ TwoFish_b0(k0)];
+ tfdata->sBox[ 2*i+1] = TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1]) ^ TwoFish_b1(k0)];
+ tfdata->sBox[0x200+2*i ] = TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2]) ^ TwoFish_b2(k0)];
+ tfdata->sBox[0x200+2*i+1] = TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3]) ^ TwoFish_b3(k0)];
+ break;
+ case 0: /* 256-bit keys (same as 4) */
+ b0 = (TwoFish_P[TwoFish_P_04][b0]) ^ TwoFish_b0(k3);
+ b1 = (TwoFish_P[TwoFish_P_14][b1]) ^ TwoFish_b1(k3);
+ b2 = (TwoFish_P[TwoFish_P_24][b2]) ^ TwoFish_b2(k3);
+ b3 = (TwoFish_P[TwoFish_P_34][b3]) ^ TwoFish_b3(k3);
+ case 3: /* 192-bit keys */
+ b0 = (TwoFish_P[TwoFish_P_03][b0]) ^ TwoFish_b0(k2);
+ b1 = (TwoFish_P[TwoFish_P_13][b1]) ^ TwoFish_b1(k2);
+ b2 = (TwoFish_P[TwoFish_P_23][b2]) ^ TwoFish_b2(k2);
+ b3 = (TwoFish_P[TwoFish_P_33][b3]) ^ TwoFish_b3(k2);
+ case 2: /* 128-bit keys */
+ tfdata->sBox[ 2*i ]=
+ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0]) ^
+ TwoFish_b0(k1)]) ^ TwoFish_b0(k0)];
+
+ tfdata->sBox[ 2*i+1]=
+ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1]) ^
+ TwoFish_b1(k1)]) ^ TwoFish_b1(k0)];
+
+ tfdata->sBox[0x200+2*i ]=
+ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2]) ^
+ TwoFish_b2(k1)]) ^ TwoFish_b2(k0)];
+
+ tfdata->sBox[0x200+2*i+1]=
+ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3]) ^
+ TwoFish_b3(k1)]) ^ TwoFish_b3(k0)];
+ }
+ }
+}
+
+
+/**
+ * Encrypt or decrypt exactly one block of plaintext in CBC mode.
+ * Use "ciphertext stealing" technique described on pg. 196
+ * of "Applied Cryptography" to encrypt the final partial
+ * (i.e. <16 byte) block if necessary.
+ *
+ * jojo: the "ciphertext stealing" requires we read ahead and have
+ * special handling for the last two blocks. Because of this, the
+ * output from the TwoFish algorithm is handled internally here.
+ * It would be better to have a higher level handle this as well as
+ * CBC mode. Unfortunately, I've mixed the two together, which is
+ * pretty crappy... The Java version separates these out correctly.
+ *
+ * fknobbe: I have reduced the CBC mode to work on memory buffer only.
+ * Higher routines should use an intermediate buffer and handle
+ * their output seperately (mainly so the data can be flushed
+ * in one chunk, not seperate 16 byte blocks...)
+ *
+ * @param in The plaintext.
+ * @param out The ciphertext
+ * @param size how much to encrypt
+ * @param tfdata: Pointer to the global data structure containing session keys.
+ * @return none
+ */
+void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,unsigned long size,int decrypt,TWOFISH *tfdata)
+{ u_int8_t PnMinusOne[TwoFish_BLOCK_SIZE];
+ u_int8_t CnMinusOne[TwoFish_BLOCK_SIZE];
+ u_int8_t CBCplusCprime[TwoFish_BLOCK_SIZE];
+ u_int8_t Pn[TwoFish_BLOCK_SIZE];
+ u_int8_t *p,*pout;
+ unsigned long i;
+
+ /* here is where we implement CBC mode and cipher block stealing */
+ if(size==TwoFish_BLOCK_SIZE)
+ { /* if we are encrypting, CBC means we XOR the plain text block with the */
+ /* previous cipher text block before encrypting */
+ if(!decrypt && tfdata->qBlockDefined)
+ { for(p=in,i=0;i<TwoFish_BLOCK_SIZE;i++,p++)
+ Pn[i]=*p ^ tfdata->qBlockCrypt[i]; /* FK: I'm copying the xor'ed input into Pn... */
+ }
+ else
+ memcpy(Pn,in,TwoFish_BLOCK_SIZE); /* FK: same here. we work of Pn all the time. */
+
+ /* TwoFish block level encryption or decryption */
+ _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata);
+
+ /* if we are decrypting, CBC means we XOR the result of the decryption */
+ /* with the previous cipher text block to get the resulting plain text */
+ if(decrypt && tfdata->qBlockDefined)
+ { for (p=out,i=0;i<TwoFish_BLOCK_SIZE;i++,p++)
+ *p^=tfdata->qBlockPlain[i];
+ }
+
+ /* save the input and output blocks, since CBC needs these for XOR */
+ /* operations */
+ _TwoFish_qBlockPush(Pn,out,tfdata);
+ }
+ else
+ { /* cipher block stealing, we are at Pn, */
+ /* but since Cn-1 must now be replaced with CnC' */
+ /* we pop it off, and recalculate Cn-1 */
+
+ if(decrypt)
+ { /* We are on an odd block, and had to do cipher block stealing, */
+ /* so the PnMinusOne has to be derived differently. */
+
+ /* First we decrypt it into CBC and C' */
+ _TwoFish_qBlockPop(CnMinusOne,PnMinusOne,tfdata);
+ _TwoFish_BlockCrypt16(CnMinusOne,CBCplusCprime,decrypt,tfdata);
+
+ /* we then xor the first few bytes with the "in" bytes (Cn) */
+ /* to recover Pn, which we put in out */
+ for(p=in,pout=out,i=0;i<size;i++,p++,pout++)
+ *pout=*p ^ CBCplusCprime[i];
+
+ /* We now recover the original CnMinusOne, which consists of */
+ /* the first "size" bytes of "in" data, followed by the */
+ /* "Cprime" portion of CBCplusCprime */
+ for(p=in,i=0;i<size;i++,p++)
+ CnMinusOne[i]=*p;
+ for(;i<TwoFish_BLOCK_SIZE;i++)
+ CnMinusOne[i]=CBCplusCprime[i];
+
+ /* we now decrypt CnMinusOne to get PnMinusOne xored with Cn-2 */
+ _TwoFish_BlockCrypt16(CnMinusOne,PnMinusOne,decrypt,tfdata);
+
+ for(i=0;i<TwoFish_BLOCK_SIZE;i++)
+ PnMinusOne[i]=PnMinusOne[i] ^ tfdata->prevCipher[i];
+
+ /* So at this point, out has PnMinusOne */
+ _TwoFish_qBlockPush(CnMinusOne,PnMinusOne,tfdata);
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+ _TwoFish_FlushOutput(out,size,tfdata);
+ }
+ else
+ { _TwoFish_qBlockPop(PnMinusOne,CnMinusOne,tfdata);
+ memset(Pn,0,TwoFish_BLOCK_SIZE);
+ memcpy(Pn,in,size);
+ for(i=0;i<TwoFish_BLOCK_SIZE;i++)
+ Pn[i]^=CnMinusOne[i];
+ _TwoFish_BlockCrypt16(Pn,out,decrypt,tfdata);
+ _TwoFish_qBlockPush(Pn,out,tfdata); /* now we officially have Cn-1 */
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+ _TwoFish_FlushOutput(CnMinusOne,size,tfdata); /* old Cn-1 becomes new partial Cn */
+ }
+ tfdata->qBlockDefined=FALSE;
+ }
+}
+
+void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata)
+{ if(tfdata->qBlockDefined)
+ _TwoFish_FlushOutput(tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE,tfdata);
+ memcpy(tfdata->prevCipher,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE);
+ memcpy(tfdata->qBlockPlain,p,TwoFish_BLOCK_SIZE);
+ memcpy(tfdata->qBlockCrypt,c,TwoFish_BLOCK_SIZE);
+ tfdata->qBlockDefined=TRUE;
+}
+
+void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata)
+{ memcpy(p,tfdata->qBlockPlain,TwoFish_BLOCK_SIZE );
+ memcpy(c,tfdata->qBlockCrypt,TwoFish_BLOCK_SIZE );
+ tfdata->qBlockDefined=FALSE;
+}
+
+/* Reset's the CBC flag and zero's PrevCipher (through qBlockPlain) (important) */
+void _TwoFish_ResetCBC(TWOFISH *tfdata)
+{ tfdata->qBlockDefined=FALSE;
+ memset(tfdata->qBlockPlain,0,TwoFish_BLOCK_SIZE);
+}
+
+void _TwoFish_FlushOutput(u_int8_t *b,unsigned long len,TWOFISH *tfdata)
+{ unsigned long i;
+
+ for(i=0;i<len && !tfdata->dontflush;i++)
+ *tfdata->output++ = *b++;
+ tfdata->dontflush=FALSE;
+}
+
+void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata)
+{ u_int32_t x0,x1,x2,x3;
+ u_int32_t k,t0,t1,R;
+
+
+ x0=*in++;
+ x0|=(*in++ << 8 );
+ x0|=(*in++ << 16);
+ x0|=(*in++ << 24);
+ x1=*in++;
+ x1|=(*in++ << 8 );
+ x1|=(*in++ << 16);
+ x1|=(*in++ << 24);
+ x2=*in++;
+ x2|=(*in++ << 8 );
+ x2|=(*in++ << 16);
+ x2|=(*in++ << 24);
+ x3=*in++;
+ x3|=(*in++ << 8 );
+ x3|=(*in++ << 16);
+ x3|=(*in++ << 24);
+
+ if(decrypt)
+ { x0 ^= tfdata->subKeys[4]; /* swap input and output whitening keys when decrypting */
+ x1 ^= tfdata->subKeys[5];
+ x2 ^= tfdata->subKeys[6];
+ x3 ^= tfdata->subKeys[7];
+
+ k = 7+(TwoFish_ROUNDS*2);
+ for (R = 0; R < TwoFish_ROUNDS; R += 2)
+ { t0 = _TwoFish_Fe320( tfdata->sBox, x0);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x1);
+ x3 ^= t0 + (t1<<1) + tfdata->subKeys[k--];
+ x3 = x3 >> 1 | x3 << 31;
+ x2 = x2 << 1 | x2 >> 31;
+ x2 ^= t0 + t1 + tfdata->subKeys[k--];
+
+ t0 = _TwoFish_Fe320( tfdata->sBox, x2);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x3);
+ x1 ^= t0 + (t1<<1) + tfdata->subKeys[k--];
+ x1 = x1 >> 1 | x1 << 31;
+ x0 = x0 << 1 | x0 >> 31;
+ x0 ^= t0 + t1 + tfdata->subKeys[k--];
+ }
+
+ x2 ^= tfdata->subKeys[0];
+ x3 ^= tfdata->subKeys[1];
+ x0 ^= tfdata->subKeys[2];
+ x1 ^= tfdata->subKeys[3];
+ }
+ else
+ { x0 ^= tfdata->subKeys[0];
+ x1 ^= tfdata->subKeys[1];
+ x2 ^= tfdata->subKeys[2];
+ x3 ^= tfdata->subKeys[3];
+
+ k = 8;
+ for (R = 0; R < TwoFish_ROUNDS; R += 2)
+ { t0 = _TwoFish_Fe320( tfdata->sBox, x0);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x1);
+ x2 ^= t0 + t1 + tfdata->subKeys[k++];
+ x2 = x2 >> 1 | x2 << 31;
+ x3 = x3 << 1 | x3 >> 31;
+ x3 ^= t0 + (t1<<1) + tfdata->subKeys[k++];
+
+ t0 = _TwoFish_Fe320( tfdata->sBox, x2);
+ t1 = _TwoFish_Fe323( tfdata->sBox, x3);
+ x0 ^= t0 + t1 + tfdata->subKeys[k++];
+ x0 = x0 >> 1 | x0 << 31;
+ x1 = x1 << 1 | x1 >> 31;
+ x1 ^= t0 + (t1<<1) + tfdata->subKeys[k++];
+ }
+
+ x2 ^= tfdata->subKeys[4];
+ x3 ^= tfdata->subKeys[5];
+ x0 ^= tfdata->subKeys[6];
+ x1 ^= tfdata->subKeys[7];
+ }
+
+ *out++ = (u_int8_t)(x2 );
+ *out++ = (u_int8_t)(x2 >> 8);
+ *out++ = (u_int8_t)(x2 >> 16);
+ *out++ = (u_int8_t)(x2 >> 24);
+
+ *out++ = (u_int8_t)(x3 );
+ *out++ = (u_int8_t)(x3 >> 8);
+ *out++ = (u_int8_t)(x3 >> 16);
+ *out++ = (u_int8_t)(x3 >> 24);
+
+ *out++ = (u_int8_t)(x0 );
+ *out++ = (u_int8_t)(x0 >> 8);
+ *out++ = (u_int8_t)(x0 >> 16);
+ *out++ = (u_int8_t)(x0 >> 24);
+
+ *out++ = (u_int8_t)(x1 );
+ *out++ = (u_int8_t)(x1 >> 8);
+ *out++ = (u_int8_t)(x1 >> 16);
+ *out++ = (u_int8_t)(x1 >> 24);
+}
+
+/**
+ * Use (12, 8) Reed-Solomon code over GF(256) to produce a key S-box
+ * 32-bit entity from two key material 32-bit entities.
+ *
+ * @param k0 1st 32-bit entity.
+ * @param k1 2nd 32-bit entity.
+ * @return Remainder polynomial generated using RS code
+ */
+u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1)
+{ u_int32_t i,r;
+
+ for(r=k1,i=0;i<4;i++) /* shift 1 byte at a time */
+ TwoFish_RS_rem(r);
+ r ^= k0;
+ for(i=0;i<4;i++)
+ TwoFish_RS_rem(r);
+
+ return r;
+}
+
+u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32)
+{ u_int8_t b0,b1,b2,b3;
+ u_int32_t k0,k1,k2,k3,result = 0;
+
+ b0=TwoFish_b0(x);
+ b1=TwoFish_b1(x);
+ b2=TwoFish_b2(x);
+ b3=TwoFish_b3(x);
+ k0=k32[0];
+ k1=k32[1];
+ k2=k32[2];
+ k3=k32[3];
+
+ switch (k64Cnt & 3)
+ { case 1: /* 64-bit keys */
+ result =
+ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][b0] & 0xFF) ^ TwoFish_b0(k0)] ^
+ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][b1] & 0xFF) ^ TwoFish_b1(k0)] ^
+ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][b2] & 0xFF) ^ TwoFish_b2(k0)] ^
+ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][b3] & 0xFF) ^ TwoFish_b3(k0)];
+ break;
+ case 0: /* 256-bit keys (same as 4) */
+ b0 = (TwoFish_P[TwoFish_P_04][b0] & 0xFF) ^ TwoFish_b0(k3);
+ b1 = (TwoFish_P[TwoFish_P_14][b1] & 0xFF) ^ TwoFish_b1(k3);
+ b2 = (TwoFish_P[TwoFish_P_24][b2] & 0xFF) ^ TwoFish_b2(k3);
+ b3 = (TwoFish_P[TwoFish_P_34][b3] & 0xFF) ^ TwoFish_b3(k3);
+
+ case 3: /* 192-bit keys */
+ b0 = (TwoFish_P[TwoFish_P_03][b0] & 0xFF) ^ TwoFish_b0(k2);
+ b1 = (TwoFish_P[TwoFish_P_13][b1] & 0xFF) ^ TwoFish_b1(k2);
+ b2 = (TwoFish_P[TwoFish_P_23][b2] & 0xFF) ^ TwoFish_b2(k2);
+ b3 = (TwoFish_P[TwoFish_P_33][b3] & 0xFF) ^ TwoFish_b3(k2);
+ case 2: /* 128-bit keys (optimize for this case) */
+ result =
+ TwoFish_MDS[0][(TwoFish_P[TwoFish_P_01][(TwoFish_P[TwoFish_P_02][b0] & 0xFF) ^ TwoFish_b0(k1)] & 0xFF) ^ TwoFish_b0(k0)] ^
+ TwoFish_MDS[1][(TwoFish_P[TwoFish_P_11][(TwoFish_P[TwoFish_P_12][b1] & 0xFF) ^ TwoFish_b1(k1)] & 0xFF) ^ TwoFish_b1(k0)] ^
+ TwoFish_MDS[2][(TwoFish_P[TwoFish_P_21][(TwoFish_P[TwoFish_P_22][b2] & 0xFF) ^ TwoFish_b2(k1)] & 0xFF) ^ TwoFish_b2(k0)] ^
+ TwoFish_MDS[3][(TwoFish_P[TwoFish_P_31][(TwoFish_P[TwoFish_P_32][b3] & 0xFF) ^ TwoFish_b3(k1)] & 0xFF) ^ TwoFish_b3(k0)];
+ break;
+ }
+ return result;
+}
+
+u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x)
+{ return lsBox[ TwoFish_b0(x)<<1 ]^
+ lsBox[ ((TwoFish_b1(x)<<1)|1)]^
+ lsBox[0x200+ (TwoFish_b2(x)<<1) ]^
+ lsBox[0x200+((TwoFish_b3(x)<<1)|1)];
+}
+
+u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x)
+{ return lsBox[ (TwoFish_b3(x)<<1) ]^
+ lsBox[ ((TwoFish_b0(x)<<1)|1)]^
+ lsBox[0x200+ (TwoFish_b1(x)<<1) ]^
+ lsBox[0x200+((TwoFish_b2(x)<<1)|1)];
+}
+
+u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R)
+{ return lsBox[ 2*TwoFish__b(x,R ) ]^
+ lsBox[ 2*TwoFish__b(x,R+1)+1]^
+ lsBox[0x200+2*TwoFish__b(x,R+2) ]^
+ lsBox[0x200+2*TwoFish__b(x,R+3)+1];
+}
+
+
+#endif
diff -ruN snort-2.9.2.2/src/twofish.h snort-2.9.2.2_bkup/src/twofish.h
--- snort-2.9.2.2/src/twofish.h 1969-12-31 16:00:00.000000000 -0800
+++ snort-2.9.2.2_bkup/src/twofish.h 2012-04-08 20:34:57.389687124 -0700
@@ -0,0 +1,276 @@
+/* $Id: twofish.h,v 2.1 2008/12/15 20:36:05 fknobbe Exp $
+ *
+ *
+ * Copyright (C) 1997-2000 The Cryptix Foundation Limited.
+ * Copyright (C) 2000 Farm9.
+ * Copyright (C) 2001 Frank Knobbe.
+ * All rights reserved.
+ *
+ * For Cryptix code:
+ * Use, modification, copying and distribution of this software is subject
+ * the terms and conditions of the Cryptix General Licence. You should have
+ * received a copy of the Cryptix General Licence along with this library;
+ * if not, you can download a copy from http://www.cryptix.org/ .
+ *
+ * For Farm9:
+ * --- jojo@farm9.com, August 2000, converted from Java to C++, added CBC mode and
+ * ciphertext stealing technique, added AsciiTwofish class for easy encryption
+ * decryption of text strings
+ *
+ * Frank Knobbe <frank@knobbe.us>:
+ * --- April 2001, converted from C++ to C, prefixed global variables
+ * with TwoFish, substituted some defines, changed functions to make use of
+ * variables supplied in a struct, modified and added routines for modular calls.
+ * Cleaned up the code so that defines are used instead of fixed 16's and 32's.
+ * Created two general purpose crypt routines for one block and multiple block
+ * encryption using Joh's CBC code.
+ * Added crypt routines that use a header (with a magic and data length).
+ * (Basically a major rewrite).
+ *
+ * Note: Routines labeled _TwoFish are private and should not be used
+ * (or with extreme caution).
+ *
+ */
+
+#ifndef __TWOFISH_LIBRARY_HEADER__
+#define __TWOFISH_LIBRARY_HEADER__
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE !FALSE
+#endif
+#ifndef bool
+#define bool int
+#endif
+
+
+/* Constants */
+
+#define TwoFish_DEFAULT_PW "SnortHas2FishEncryptionRoutines!" /* default password (not more than 32 chars) */
+#define TwoFish_MAGIC "TwoFish" /* to indentify a successful decryption */
+
+enum
+{ TwoFish_KEY_SIZE = 256, /* Valid values: 64, 128, 192, 256 */
+ /* User 256, other key sizes have not been tested. */
+ /* (But should work. I substituted as much as */
+ /* I could with this define.) */
+ TwoFish_ROUNDS = 16,
+ TwoFish_BLOCK_SIZE = 16, /* bytes in a data-block */
+ TwoFish_KEY_LENGTH = TwoFish_KEY_SIZE/8, /* 32= 256-bit key */
+ TwoFish_TOTAL_SUBKEYS = 4+4+2*TwoFish_ROUNDS,
+ TwoFish_MAGIC_LEN = TwoFish_BLOCK_SIZE-8,
+ TwoFish_SK_BUMP = 0x01010101,
+ TwoFish_SK_ROTL = 9,
+ TwoFish_P_00 = 1,
+ TwoFish_P_01 = 0,
+ TwoFish_P_02 = 0,
+ TwoFish_P_03 = TwoFish_P_01 ^ 1,
+ TwoFish_P_04 = 1,
+ TwoFish_P_10 = 0,
+ TwoFish_P_11 = 0,
+ TwoFish_P_12 = 1,
+ TwoFish_P_13 = TwoFish_P_11 ^ 1,
+ TwoFish_P_14 = 0,
+ TwoFish_P_20 = 1,
+ TwoFish_P_21 = 1,
+ TwoFish_P_22 = 0,
+ TwoFish_P_23 = TwoFish_P_21 ^ 1,
+ TwoFish_P_24 = 0,
+ TwoFish_P_30 = 0,
+ TwoFish_P_31 = 1,
+ TwoFish_P_32 = 1,
+ TwoFish_P_33 = TwoFish_P_31 ^ 1,
+ TwoFish_P_34 = 1,
+ TwoFish_GF256_FDBK = 0x169,
+ TwoFish_GF256_FDBK_2 = 0x169 / 2,
+ TwoFish_GF256_FDBK_4 = 0x169 / 4,
+ TwoFish_RS_GF_FDBK = 0x14D, /* field generator */
+ TwoFish_MDS_GF_FDBK = 0x169 /* primitive polynomial for GF(256) */
+};
+
+
+/* Global data structure for callers */
+
+typedef struct
+{ u_int32_t sBox[4 * 256]; /* Key dependent S-box */
+ u_int32_t subKeys[TwoFish_TOTAL_SUBKEYS]; /* Subkeys */
+ u_int8_t key[TwoFish_KEY_LENGTH]; /* Encryption Key */
+ u_int8_t *output; /* Pointer to output buffer */
+ u_int8_t qBlockPlain[TwoFish_BLOCK_SIZE]; /* Used by CBC */
+ u_int8_t qBlockCrypt[TwoFish_BLOCK_SIZE];
+ u_int8_t prevCipher[TwoFish_BLOCK_SIZE];
+ struct /* Header for crypt functions. Has to be at least one block long. */
+ { u_int32_t salt; /* Random salt in first block (will salt the rest through CBC) */
+ u_int8_t length[4]; /* The amount of data following the header */
+ u_int8_t magic[TwoFish_MAGIC_LEN]; /* Magic to identify successful decryption */
+ } header;
+ bool qBlockDefined;
+ bool dontflush;
+} TWOFISH;
+
+#ifndef __TWOFISH_LIBRARY_SOURCE__
+
+extern bool TwoFish_srand; /* if set to TRUE (default), first call of TwoFishInit will seed rand(); */
+ /* call of TwoFishInit */
+#endif
+
+
+/**** Public Functions ****/
+
+/* TwoFish Initialization
+ *
+ * This routine generates a global data structure for use with TwoFish,
+ * initializes important values (such as subkeys, sBoxes), generates subkeys
+ * and precomputes the MDS matrix if not already done.
+ *
+ * Input: User supplied password (will be appended by default password of 'SnortHas2FishEncryptionRoutines!')
+ *
+ * Output: Pointer to TWOFISH structure. This data structure contains key dependent data.
+ * This pointer is used with all other crypt functions.
+ */
+TWOFISH *TwoFishInit(char *userkey);
+
+
+/* TwoFish Destroy
+ *
+ * Nothing else but a free...
+ *
+ * Input: Pointer to the TwoFish structure.
+ *
+ */
+void TwoFishDestroy(TWOFISH *tfdata);
+
+
+/* TwoFish Alloc
+ *
+ * Allocates enough memory for the output buffer as required.
+ *
+ * Input: Length of the plaintext.
+ * Boolean flag for BinHex Output.
+ * Pointer to the TwoFish structure.
+ *
+ * Output: Returns a pointer to the memory allocated.
+ */
+void *TwoFishAlloc(unsigned long len,bool binhex,bool decrypt,TWOFISH *tfdata);
+
+
+/* TwoFish Free
+ *
+ * Free's the allocated buffer.
+ *
+ * Input: Pointer to the TwoFish structure
+ *
+ * Output: (none)
+ */
+void TwoFishFree(TWOFISH *tfdata);
+
+
+/* TwoFish Set Output
+ *
+ * If you want to allocate the output buffer yourself,
+ * then you can set it with this function.
+ *
+ * Input: Pointer to your output buffer
+ * Pointer to the TwoFish structure
+ *
+ * Output: (none)
+ */
+void TwoFishSetOutput(char *outp,TWOFISH *tfdata);
+
+
+/* TwoFish Raw Encryption
+ *
+ * Does not use header, but does use CBC (if more than one block has to be encrypted).
+ *
+ * Input: Pointer to the buffer of the plaintext to be encrypted.
+ * Pointer to the buffer receiving the ciphertext.
+ * The length of the plaintext buffer.
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes encrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishEncryptRaw(char *in,char *out,unsigned long len,TWOFISH *tfdata);
+
+/* TwoFish Raw Decryption
+ *
+ * Does not use header, but does use CBC (if more than one block has to be decrypted).
+ *
+ * Input: Pointer to the buffer of the ciphertext to be decrypted.
+ * Pointer to the buffer receiving the plaintext.
+ * The length of the ciphertext buffer (at least one cipher block).
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes decrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishDecryptRaw(char *in,char *out,unsigned long len,TWOFISH *tfdata);
+
+
+/* TwoFish Encryption
+ *
+ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ * this routine will alloc the memory. In addition, it will include a small 'header'
+ * containing the magic and some salt. That way the decrypt routine can check if the
+ * packet got decrypted successfully, and return 0 instead of garbage.
+ *
+ * Input: Pointer to the buffer of the plaintext to be encrypted.
+ * Pointer to the pointer to the buffer receiving the ciphertext.
+ * The pointer either points to user allocated output buffer space, or to NULL, in which case
+ * this routine will set the pointer to the buffer allocated through the struct.
+ * The length of the plaintext buffer.
+ * Can be -1 if the input is a null terminated string, in which case we'll count for you.
+ * Boolean flag for BinHex Output (if used, output will be twice as large as input).
+ * Note: BinHex conversion overwrites (converts) input buffer!
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes encrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishEncrypt(char *in,char **out,signed long len,bool binhex,TWOFISH *tfdata);
+
+
+/* TwoFish Decryption
+ *
+ * Uses header and CBC. If the output area has not been intialized with TwoFishAlloc,
+ * this routine will alloc the memory. In addition, it will check the small 'header'
+ * containing the magic. If magic does not match we return 0. Otherwise we return the
+ * amount of bytes decrypted (should be the same as the length in the header).
+ *
+ * Input: Pointer to the buffer of the ciphertext to be decrypted.
+ * Pointer to the pointer to the buffer receiving the plaintext.
+ * The pointer either points to user allocated output buffer space, or to NULL, in which case
+ * this routine will set the pointer to the buffer allocated through the struct.
+ * The length of the ciphertext buffer.
+ * Can be -1 if the input is a null terminated binhex string, in which case we'll count for you.
+ * Boolean flag for BinHex Input (if used, plaintext will be half as large as input).
+ * Note: BinHex conversion overwrites (converts) input buffer!
+ * The TwoFish structure.
+ *
+ * Output: The amount of bytes decrypted if successful, otherwise 0.
+ */
+unsigned long TwoFishDecrypt(char *in,char **out,signed long len,bool binhex,TWOFISH *tfdata);
+
+
+/**** Private Functions ****/
+
+u_int8_t TwoFish__b(u_int32_t x,int n);
+void _TwoFish_BinHex(u_int8_t *buf,unsigned long len,bool bintohex);
+unsigned long _TwoFish_CryptRawCBC(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata);
+unsigned long _TwoFish_CryptRaw16(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata);
+unsigned long _TwoFish_CryptRaw(char *in,char *out,unsigned long len,bool decrypt,TWOFISH *tfdata);
+void _TwoFish_PrecomputeMDSmatrix(void);
+void _TwoFish_MakeSubKeys(TWOFISH *tfdata);
+void _TwoFish_qBlockPush(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata);
+void _TwoFish_qBlockPop(u_int8_t *p,u_int8_t *c,TWOFISH *tfdata);
+void _TwoFish_ResetCBC(TWOFISH *tfdata);
+void _TwoFish_FlushOutput(u_int8_t *b,unsigned long len,TWOFISH *tfdata);
+void _TwoFish_BlockCrypt(u_int8_t *in,u_int8_t *out,unsigned long size,int decrypt,TWOFISH *tfdata);
+void _TwoFish_BlockCrypt16(u_int8_t *in,u_int8_t *out,bool decrypt,TWOFISH *tfdata);
+u_int32_t _TwoFish_RS_MDS_Encode(u_int32_t k0,u_int32_t k1);
+u_int32_t _TwoFish_F32(u_int32_t k64Cnt,u_int32_t x,u_int32_t *k32);
+u_int32_t _TwoFish_Fe320(u_int32_t *lsBox,u_int32_t x);
+u_int32_t _TwoFish_Fe323(u_int32_t *lsBox,u_int32_t x);
+u_int32_t _TwoFish_Fe32(u_int32_t *lsBox,u_int32_t x,u_int32_t R);
+
+
+#endif