diff --git a/Makefile.am b/Makefile.am index c904b09..43fa77a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,7 +19,8 @@ SRC = hydra-vnc.c hydra-pcnfs.c hydra-rexec.c hydra-nntp.c hydra-socks5.c \ hydra-oracle.c hydra-vmauthd.c hydra-asterisk.c hydra-firebird.c hydra-afp.c hydra-ncp.c \ hydra-oracle-sid.c hydra-http-proxy.c hydra-http-form.c hydra-irc.c \ hydra-rdp.c hydra-s7-300.c hydra-redis.c hydra-adam6500.c \ - crc32.c d3des.c bfg.c ntlm.c sasl.c hmacmd5.c hydra-mod.c hydra-rtsp.c hydra-time.c hydra-rpcap.c + crc32.c d3des.c bfg.c ntlm.c sasl.c hmacmd5.c hydra-mod.c hydra-rtsp.c hydra-time.c hydra-rpcap.c \ + hydra-radmin2.c twofish.c OBJ = hydra-vnc.o hydra-pcnfs.o hydra-rexec.o hydra-nntp.o hydra-socks5.o \ hydra-telnet.o hydra-cisco.o hydra-http.o hydra-ftp.o hydra-imap.o \ hydra-pop3.o hydra-smb.o hydra-icq.o hydra-cisco-enable.o hydra-ldap.o \ @@ -30,7 +31,8 @@ OBJ = hydra-vnc.o hydra-pcnfs.o hydra-rexec.o hydra-nntp.o hydra-socks5.o \ hydra-oracle-sid.o hydra-oracle.o hydra-vmauthd.o hydra-asterisk.o hydra-firebird.o hydra-afp.o hydra-ncp.o \ hydra-http-proxy.o hydra-http-form.o hydra-irc.o hydra-redis.o \ hydra-rdp.o hydra-s7-300.c hydra-adam6500.o \ - crc32.o d3des.o bfg.o ntlm.o sasl.o hmacmd5.o hydra-mod.o hydra-rtsp.o hydra-time.o hydra-rpcap.o + crc32.o d3des.o bfg.o ntlm.o sasl.o hmacmd5.o hydra-mod.o hydra-rtsp.o hydra-time.o hydra-rpcap.o \ + hydra-radmin2.o twofish.o BINS = hydra pw-inspector EXTRA_DIST = README README.arm README.palm CHANGES TODO INSTALL LICENSE \ diff --git a/hydra-radmin2.c b/hydra-radmin2.c new file mode 100644 index 0000000..662a173 --- /dev/null +++ b/hydra-radmin2.c @@ -0,0 +1,325 @@ +#include "hydra-mod.h" +#include +#include +#include + +extern char *HYDRA_EXIT; + + +//Twofish references +#include "twofish/aes.h" +extern int makeKey(keyInstance *key, BYTE direction, int keyLen,CONST char *keyMaterial); +extern int cipherInit(cipherInstance *cipher, BYTE mode,CONST char *IV); +extern int blockEncrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input, int inputLen, BYTE *outBuffer); +extern int blockDecrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input, int inputLen, BYTE *outBuffer); + + +struct rmessage{ + char magic; //No touching! + unsigned int length; //Total message size of data. + unsigned int checksum; //Checksum from type to end of data. + char type; //Command type, table below. + unsigned char data[32]; //data to be sent. +}; + +void print_message(struct rmessage *msg) { + return; + int dlen = 0; + hydra_report(stderr, + "m:\t%02x\n" + "l:\t%08x\n" + "c:\t%08x\n" + "t:\t%02x\n", + msg->magic, + msg->length, + msg->checksum, + msg->type); + + hydra_report(stderr, "d:\t"); + for(dlen = 0; dlen < msg->length - 1; dlen++) { //-1 because of type. + hydra_report(stderr, "%02x", msg->data[dlen]); + } + hydra_report(stderr, "\n"); +} + +unsigned int checksum(struct rmessage *msg) { + int blen; + unsigned char *stream; + unsigned int sum; + blen = msg->length; //Get the real length. + blen += (4 - (blen % 4)); + stream = calloc(blen, sizeof(unsigned char)); + memcpy(stream, &msg->type, sizeof(unsigned char)); + memcpy(stream+1, msg->data, blen-1); + + sum = 0; + for(blen -= sizeof(unsigned int); blen > 0; blen -= sizeof(unsigned int)) { + sum += *(unsigned int *)(stream + blen); + } + sum += *(unsigned int *)stream; + + return sum; +} + + +void challenge_request(struct rmessage *msg) { + msg->magic = 0x01; + msg->length = 0x01; + msg->type = 0x1b; + msg->checksum = checksum(msg); + print_message(msg); +} + +void challenge_response(struct rmessage *msg, unsigned char *solution) { + msg->magic = 0x01; + msg->length = 0x21; + msg->type = 0x09; + memcpy(msg->data, solution, 0x20); + msg->checksum = checksum(msg); + print_message(msg); +} + + +unsigned char *message2buffer(struct rmessage *msg) { + unsigned char *data; + if(msg == NULL) { + hydra_report(stderr, "rmessage is null\n"); + hydra_child_exit(0); + return NULL; + } + + switch(msg->type) { + case 0x1b: //Challenge request + data = calloc (10, sizeof(unsigned char)); //TODO: check return + memcpy(data, &msg->magic, sizeof(char)); + *((int *)(data+1)) = htonl(msg->length); + *((int *)(data+5)) = htonl(msg->checksum); + memcpy((data+9), &msg->type, sizeof(char)); + break; + case 0x09: + data = calloc (42, sizeof(unsigned char)); //TODO: check return + memcpy(data, &msg->magic, sizeof(char)); + *((int *)(data+1)) = htonl(msg->length); + *((int *)(data+5)) = htonl(msg->checksum); + memcpy((data+9), &msg->type, sizeof(char)); + memcpy((data+10), msg->data, sizeof(char) * 32); + break; + default: + hydra_report(stderr, "unknown rmessage type\n"); + hydra_child_exit(0); + return NULL; + } + return data; +} + +struct rmessage *buffer2message(char *buffer) { + struct rmessage *msg; + msg = calloc(1, sizeof(struct rmessage)); + unsigned int sum = 0; + //TODO: check return + + //Start parsing... + msg->magic = buffer[0]; + buffer += sizeof(char); + msg->length = ntohl(*((unsigned int *)(buffer))); + buffer += sizeof(unsigned int); + msg->checksum = ntohl(*((unsigned int *)(buffer))); + buffer += sizeof(unsigned int); + msg->type = buffer[0]; + buffer += sizeof(char); + + //Verify known fields... + if(msg->magic != 0x01) { + hydra_report(stderr, "Bad magic\n"); + hydra_child_exit(0); + return NULL; + } + + switch(msg->type) { + case 0x1b: + if(msg->length != 0x21) { + hydra_report(stderr, "Bad length...%08x\n", msg->length); + hydra_child_exit(0); + return NULL; + } + memcpy(msg->data, buffer, 32); + break; + case 0x0a: + //Win! + case 0x0b: + //Lose! + break; + default: + hydra_report(stderr, "unknown rmessage type"); + hydra_child_exit(0); + return NULL; + } + return msg; +} + + +int start_radmin2(int s, char *ip, int port, unsigned char options, char *miscptr, FILE * fp) { +} + +void service_radmin2(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname) { + int sock = -1; + int index; + int count; + int bytecount; + unsigned char *request; + struct rmessage *msg; + int myport = PORT_RADMIN2; + char buffer[42]; + unsigned char password[101]; + unsigned char rawkey[16]; + unsigned char pkey[33]; + char *IV = "FEDCBA9876543210A39D4A18F85B4A52"; + unsigned char encrypted[32]; + + //Initialization nonsense. + MD5_CTX md5c; + keyInstance key; + cipherInstance cipher; + + if(port != 0) { + myport = port; + } + + memset(buffer, 0x00, sizeof(buffer)); + memset(pkey, 0x00, 33); + memset(encrypted, 0x00, 32); + memset(password, 0x00, 100); + + //Phone the mother ship + hydra_register_socket(sp); + if( memcmp(hydra_get_next_pair(), &HYDRA_EXIT, sizeof(HYDRA_EXIT)) == 0) { + return; + } + + // Get a password to work with. + strncpy(password, hydra_get_next_password(), 101); + MD5_Init(&md5c); + MD5_Update(&md5c, password, 100); + MD5_Final(rawkey, &md5c); + //Copy raw md5 data into ASCIIZ string + for(index = 0; index < 16; index++) { + count = sprintf((pkey+index*2), "%02x", rawkey[index]); + } + + /* Typical conversation goes as follows... + 0) connect to server + 1) request challenge + 2) receive 32 byte challenge response + 3) send 32 byte challenge solution + 4) receive 1 byte auth success/fail message + */ + // 0) Connect to the server + sock = hydra_connect_tcp(ip, myport); + if(sock < 0) { + hydra_report(stderr, "Error: Child with pid %d terminating, can not connect\n", (int)getpid()); + hydra_child_exit(1); + } + + // 1) request challenge (working) + msg = calloc(1, sizeof(struct rmessage)); + challenge_request(msg); + hydra_send(sock, message2buffer(msg), 10, 0); + free(msg); //We're done with challenge request messagee. + + //2) receive response (working) + index = 0; + while(index < 42) { //We're always expecting back a 42 byte buffer from a challenge request. + switch(hydra_data_ready(sock)) { + case -1: + hydra_report(stderr, "Error: Child with pid %d terminating, receive error\nerror:\t%s\n", (int)getpid(), strerror(errno)); + hydra_child_exit(1); + break; + case 0: + //keep waiting... + break; + default: + bytecount = hydra_recv(sock, buffer+index, 42 - index); + if(bytecount < 0) { + hydra_report(stderr, "Error: Child with pid %d terminating, receive error\nerror:\t%s\n", (int)getpid(), strerror(errno)); + hydra_child_exit(1); + } + index += bytecount; + } + } + + //3) Send challenge solution. + + //3.a) generate a new message from the buffer + msg = buffer2message(buffer); + + //3.b) encrypt data received using pkey & known IV + index = makeKey(&key, DIR_ENCRYPT, 128, pkey); + if(index != TRUE) { + hydra_report(stderr, "Error: Child with pid %d terminating, make key error (%08x)\n", (int)getpid(), index); + hydra_child_exit(1); + } + + index = cipherInit(&cipher, MODE_CBC, IV); + if(index != TRUE) { + hydra_report(stderr, "Error: Child with pid %d terminating, cipher init error(%08x)\n", (int)getpid(), index); + hydra_child_exit(1); + } + + index = blockEncrypt(&cipher, &key, msg->data, 32 * 8, encrypted); + if(index <= 0) { + hydra_report(stderr, "Error: Child with pid %d terminating, encrypt error(%08x)\n", (int)getpid(), index); + hydra_child_exit(1); + } + + //3.c) half sum - this is the solution to the challenge. + for(index=0; index < 16; index++) { + *(encrypted+index) += *(encrypted+index+16); + } + memset((encrypted+16), 0x00, 16); + + //3.d) send half sum + challenge_response(msg, encrypted); + request = message2buffer(msg); + + hydra_send(sock, request, 42, 0); + //4) receive auth success/failure + index = 0; + while(index < 10) { //We're always expecting back a 42 byte buffer from a challenge request. + switch(hydra_data_ready(sock)) { + case -1: + hydra_report(stderr, "Error: Child with pid %d terminating, receive error\nerror:\t%s\n", (int)getpid(), strerror(errno)); + hydra_child_exit(1); + break; + case 0: + //keep waiting... + break; + default: + bytecount = hydra_recv(sock, buffer+index, 10 - index); + if(bytecount < 0) { + hydra_report(stderr, "Error: Child with pid %d terminating, receive error\nerror:\t%s\n", (int)getpid(), strerror(errno)); + hydra_child_exit(1); + } + index += bytecount; + } + } + msg = buffer2message(buffer); + if(msg->type == 0x0a) { + hydra_completed_pair_found(); + } + //5) Disconnect + hydra_disconnect(sock); +} + +int service_radmin2_init(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname) { + // called before the childrens are forked off, so this is the function + // which should be filled if initial connections and service setup has to be + // performed once only. + // + // fill if needed. + // + // return codes: + // 0 all OK + // -1 error, hydra will exit, so print a good error message here + + return 0; +} diff --git a/hydra.c b/hydra.c index 67f06fe..2061a31 100644 --- a/hydra.c +++ b/hydra.c @@ -57,6 +57,7 @@ extern void service_http_proxy_urlenum(char *ip, int sp, unsigned char options, extern void service_s7_300(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); extern void service_rtsp(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); extern void service_rpcap(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); +extern void service_radmin2(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); // ADD NEW SERVICES HERE @@ -147,13 +148,14 @@ extern int service_xmpp_init(char *ip, int sp, unsigned char options, char *misc extern int service_s7_300_init(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); extern int service_rtsp_init(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); extern int service_rpcap_init(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); +extern int service_radmin2_init(char *ip, int sp, unsigned char options, char *miscptr, FILE * fp, int port, char *hostname); // ADD NEW SERVICES HERE // ADD NEW SERVICES HERE char *SERVICES = - "adam6500 asterisk afp cisco cisco-enable cvs firebird ftp ftps http[s]-{head|get|post} http[s]-{get|post}-form http-proxy http-proxy-urlenum icq imap[s] irc ldap2[s] ldap3[-{cram|digest}md5][s] mssql mysql ncp nntp oracle oracle-listener oracle-sid pcanywhere pcnfs pop3[s] postgres rdp redis rexec rlogin rpcap rsh rtsp s7-300 sapr3 sip smb smtp[s] smtp-enum snmp socks5 ssh sshkey svn teamspeak telnet[s] vmauthd vnc xmpp"; + "adam6500 asterisk afp cisco cisco-enable cvs firebird ftp ftps http[s]-{head|get|post} http[s]-{get|post}-form http-proxy http-proxy-urlenum icq imap[s] irc ldap2[s] ldap3[-{cram|digest}md5][s] mssql mysql ncp nntp oracle oracle-listener oracle-sid pcanywhere pcnfs pop3[s] postgres radmin2 rdp redis rexec rlogin rpcap rsh rtsp s7-300 sapr3 sip smb smtp[s] smtp-enum snmp socks5 ssh sshkey svn teamspeak telnet[s] vmauthd vnc xmpp"; #define MAXBUF 520 #define MAXLINESIZE ( ( MAXBUF / 2 ) - 4 ) @@ -1263,6 +1265,8 @@ void hydra_service_init(int target_no) { x = service_rtsp_init(hydra_targets[target_no]->ip, -1, options, hydra_options.miscptr, hydra_brains.ofp, hydra_targets[target_no]->port, hydra_targets[target_no]->target); if (strcmp(hydra_options.service, "rpcap") == 0) x = service_rpcap_init(hydra_targets[target_no]->ip, -1, options, hydra_options.miscptr, hydra_brains.ofp, hydra_targets[target_no]->port, hydra_targets[target_no]->target); + if (strcmp(hydra_options.service, "radmin2") == 0) + x = service_radmin2_init(hydra_targets[target_no]->ip, -1, options, hydra_options.miscptr, hydra_brains.ofp, hydra_targets[target_no]->port, hydra_targets[target_no]->target); // ADD NEW SERVICES HERE @@ -1469,6 +1473,8 @@ int hydra_spawn_head(int head_no, int target_no) { service_rtsp(hydra_targets[target_no]->ip, hydra_heads[head_no]->sp[1], options, hydra_options.miscptr, hydra_brains.ofp, hydra_targets[target_no]->port, hydra_targets[hydra_heads[head_no]->target_no]->target); if (strcmp(hydra_options.service, "rpcap") == 0) service_rpcap(hydra_targets[target_no]->ip, hydra_heads[head_no]->sp[1], options, hydra_options.miscptr, hydra_brains.ofp, hydra_targets[target_no]->port, hydra_targets[hydra_heads[head_no]->target_no]->target); + if (strcmp(hydra_options.service, "radmin2") == 0) + service_radmin2(hydra_targets[target_no]->ip, hydra_heads[head_no]->sp[1], options, hydra_options.miscptr, hydra_brains.ofp, hydra_targets[target_no]->port, hydra_targets[hydra_heads[head_no]->target_no]->target); // ADD NEW SERVICES HERE @@ -1569,6 +1575,7 @@ int hydra_lookup_port(char *service) { {"s7-300", PORT_S7_300, PORT_S7_300_SSL}, {"rtsp", PORT_RTSP, PORT_RTSP_SSL}, {"rpcap", PORT_RPCAP, PORT_RPCAP_SSL}, + {"radmin2", PORT_RADMIN2, PORT_RADMIN2}, // ADD NEW SERVICES HERE - add new port numbers to hydra.h {"", PORT_NOPORT, PORT_NOPORT} }; @@ -3267,6 +3274,8 @@ int main(int argc, char *argv[]) { // hydra_options.conwait = conwait = 1; i = 1; } + if (strcmp(hydra_options.service, "radmin2") == 0) + i = 1; // ADD NEW SERVICES HERE diff --git a/hydra.h b/hydra.h index 54373d4..f580e4b 100644 --- a/hydra.h +++ b/hydra.h @@ -136,6 +136,7 @@ #define PORT_RTSP_SSL 554 #define PORT_RPCAP 2002 #define PORT_RPCAP_SSL 2002 +#define PORT_RADMIN2 4899 #define False 0 #define True 1 diff --git a/twofish.c b/twofish.c new file mode 100644 index 0000000..841eb30 --- /dev/null +++ b/twofish.c @@ -0,0 +1,704 @@ +/*************************************************************************** + TWOFISH.C -- C API calls for TWOFISH AES submission + + Submitters: + Bruce Schneier, Counterpane Systems + Doug Whiting, Hi/fn + John Kelsey, Counterpane Systems + Chris Hall, Counterpane Systems + David Wagner, UC Berkeley + + Code Author: Doug Whiting, Hi/fn + + Version 1.00 April 1998 + + Copyright 1998, Hi/fn and Counterpane Systems. All rights reserved. + + Notes: + * Pedagogical version (non-optimized) + * Tab size is set to 4 characters in this file + +***************************************************************************/ + +#include "twofish/aes.h" +#include "twofish/table.h" + +/* ++***************************************************************************** +* Constants/Macros/Tables +-****************************************************************************/ + +#define VALIDATE_PARMS 1 /* nonzero --> check all parameters */ +#define FEISTEL 0 /* nonzero --> use Feistel version (slow) */ + +int tabEnable=0; /* are we gathering stats? */ +BYTE tabUsed[256]; /* one bit per table */ + +#if FEISTEL +CONST char *moduleDescription="Pedagogical C code (Feistel)"; +#else +CONST char *moduleDescription="Pedagogical C code"; +#endif +CONST char *modeString = ""; + +#define P0_USED 0x01 +#define P1_USED 0x02 +#define B0_USED 0x04 +#define B1_USED 0x08 +#define B2_USED 0x10 +#define B3_USED 0x20 +#define ALL_USED 0x3F + +/* number of rounds for various key sizes: 128, 192, 256 */ +int numRounds[4]= {0,ROUNDS_128,ROUNDS_192,ROUNDS_256}; + +#ifndef DEBUG +#ifdef GetCodeSize +#define DEBUG 1 /* force debug */ +#endif +#endif +#include "twofish/debug.h" /* debug display macros */ + +#ifdef GetCodeSize +extern DWORD Here(DWORD x); /* return caller's address! */ +DWORD TwofishCodeStart(void) { return Here(0); }; +#endif + +/* ++***************************************************************************** +* +* Function Name: TableOp +* +* Function: Handle table use checking +* +* Arguments: op = what to do (see TAB_* defns in AES.H) +* +* Return: TRUE --> done (for TAB_QUERY) +* +* Notes: This routine is for use in generating the tables KAT file. +* +-****************************************************************************/ +int TableOp(int op) + { + static int queryCnt=0; + int i; + switch (op) + { + case TAB_DISABLE: + tabEnable=0; + break; + case TAB_ENABLE: + tabEnable=1; + break; + case TAB_RESET: + queryCnt=0; + for (i=0;i<256;i++) + tabUsed[i]=0; + break; + case TAB_QUERY: + queryCnt++; + for (i=0;i<256;i++) + if (tabUsed[i] != ALL_USED) + return FALSE; + if (queryCnt < TAB_MIN_QUERY) /* do a certain minimum number */ + return FALSE; + break; + } + return TRUE; + } + + +/* ++***************************************************************************** +* +* Function Name: ParseHexDword +* +* Function: Parse ASCII hex nibbles and fill in key/iv dwords +* +* Arguments: bit = # bits to read +* srcTxt = ASCII source +* d = ptr to dwords to fill in +* dstTxt = where to make a copy of ASCII source +* (NULL ok) +* +* Return: Zero if no error. Nonzero --> invalid hex or length +* +* Notes: Note that the parameter d is a DWORD array, not a byte array. +* This routine is coded to work both for little-endian and big-endian +* architectures. The character stream is interpreted as a LITTLE-ENDIAN +* byte stream, since that is how the Pentium works, but the conversion +* happens automatically below. +* +-****************************************************************************/ +int ParseHexDword(int bits,CONST char *srcTxt,DWORD *d,char *dstTxt) + { + int i; + DWORD b; + char c; +#if ALIGN32 + char alignDummy[3]; /* keep dword alignment */ +#endif + + union /* make sure LittleEndian is defined correctly */ + { + BYTE b[4]; + DWORD d[1]; + } v; + v.d[0]=1; + if (v.b[0 ^ ADDR_XOR] != 1) /* sanity check on compile-time switch */ + return BAD_ENDIAN; + +#if VALIDATE_PARMS + #if ALIGN32 + if (((int)d) & 3) + return BAD_ALIGN32; + #endif +#endif + + for (i=0;i*32= '0') && (c <= '9')) + b=c-'0'; + else if ((c >= 'a') && (c <= 'f')) + b=c-'a'+10; + else if ((c >= 'A') && (c <= 'F')) + b=c-'A'+10; + else + return BAD_KEY_MAT; /* invalid hex character */ + /* works for big and little endian! */ + d[i/8] |= b << (4*((i^1)&7)); + } + + return 0; /* no error */ + } + + +/* ++***************************************************************************** +* +* Function Name: f32 +* +* Function: Run four bytes through keyed S-boxes and apply MDS matrix +* +* Arguments: x = input to f function +* k32 = pointer to key dwords +* keyLen = total key length (k32 --> keyLey/2 bits) +* +* Return: The output of the keyed permutation applied to x. +* +* Notes: +* This function is a keyed 32-bit permutation. It is the major building +* block for the Twofish round function, including the four keyed 8x8 +* permutations and the 4x4 MDS matrix multiply. This function is used +* both for generating round subkeys and within the round function on the +* block being encrypted. +* +* This version is fairly slow and pedagogical, although a smartcard would +* probably perform the operation exactly this way in firmware. For +* ultimate performance, the entire operation can be completed with four +* lookups into four 256x32-bit tables, with three dword xors. +* +* The MDS matrix is defined in TABLE.H. To multiply by Mij, just use the +* macro Mij(x). +* +-****************************************************************************/ +DWORD f32(DWORD x,CONST DWORD *k32,int keyLen) + { + BYTE b[4]; + + /* Run each byte thru 8x8 S-boxes, xoring with key byte at each stage. */ + /* Note that each byte goes through a different combination of S-boxes.*/ + + *((DWORD *)b) = Bswap(x); /* make b[0] = LSB, b[3] = MSB */ + switch (((keyLen + 63)/64) & 3) + { + case 0: /* 256 bits of key */ + b[0] = p8(04)[b[0]] ^ b0(k32[3]); + b[1] = p8(14)[b[1]] ^ b1(k32[3]); + b[2] = p8(24)[b[2]] ^ b2(k32[3]); + b[3] = p8(34)[b[3]] ^ b3(k32[3]); + /* fall thru, having pre-processed b[0]..b[3] with k32[3] */ + case 3: /* 192 bits of key */ + b[0] = p8(03)[b[0]] ^ b0(k32[2]); + b[1] = p8(13)[b[1]] ^ b1(k32[2]); + b[2] = p8(23)[b[2]] ^ b2(k32[2]); + b[3] = p8(33)[b[3]] ^ b3(k32[2]); + /* fall thru, having pre-processed b[0]..b[3] with k32[2] */ + case 2: /* 128 bits of key */ + b[0] = p8(00)[p8(01)[p8(02)[b[0]] ^ b0(k32[1])] ^ b0(k32[0])]; + b[1] = p8(10)[p8(11)[p8(12)[b[1]] ^ b1(k32[1])] ^ b1(k32[0])]; + b[2] = p8(20)[p8(21)[p8(22)[b[2]] ^ b2(k32[1])] ^ b2(k32[0])]; + b[3] = p8(30)[p8(31)[p8(32)[b[3]] ^ b3(k32[1])] ^ b3(k32[0])]; + } + + if (tabEnable) + { /* we could give a "tighter" bound, but this works acceptably well */ + tabUsed[b0(x)] |= (P_00 == 0) ? P0_USED : P1_USED; + tabUsed[b1(x)] |= (P_10 == 0) ? P0_USED : P1_USED; + tabUsed[b2(x)] |= (P_20 == 0) ? P0_USED : P1_USED; + tabUsed[b3(x)] |= (P_30 == 0) ? P0_USED : P1_USED; + + tabUsed[b[0] ] |= B0_USED; + tabUsed[b[1] ] |= B1_USED; + tabUsed[b[2] ] |= B2_USED; + tabUsed[b[3] ] |= B3_USED; + } + + /* Now perform the MDS matrix multiply inline. */ + return ((M00(b[0]) ^ M01(b[1]) ^ M02(b[2]) ^ M03(b[3])) ) ^ + ((M10(b[0]) ^ M11(b[1]) ^ M12(b[2]) ^ M13(b[3])) << 8) ^ + ((M20(b[0]) ^ M21(b[1]) ^ M22(b[2]) ^ M23(b[3])) << 16) ^ + ((M30(b[0]) ^ M31(b[1]) ^ M32(b[2]) ^ M33(b[3])) << 24) ; + } + +/* ++***************************************************************************** +* +* Function Name: RS_MDS_Encode +* +* Function: Use (12,8) Reed-Solomon code over GF(256) to produce +* a key S-box dword from two key material dwords. +* +* Arguments: k0 = 1st dword +* k1 = 2nd dword +* +* Return: Remainder polynomial generated using RS code +* +* Notes: +* Since this computation is done only once per reKey per 64 bits of key, +* the performance impact of this routine is imperceptible. The RS code +* chosen has "simple" coefficients to allow smartcard/hardware implementation +* without lookup tables. +* +-****************************************************************************/ +DWORD RS_MDS_Encode(DWORD k0,DWORD k1) + { + int i,j; + DWORD r; + + for (i=r=0;i<2;i++) + { + r ^= (i) ? k0 : k1; /* merge in 32 more key bits */ + for (j=0;j<4;j++) /* shift one byte at a time */ + RS_rem(r); + } + return r; + } + +/* ++***************************************************************************** +* +* Function Name: reKey +* +* Function: Initialize the Twofish key schedule from key32 +* +* Arguments: key = ptr to keyInstance to be initialized +* +* Return: TRUE on success +* +* Notes: +* Here we precompute all the round subkeys, although that is not actually +* required. For example, on a smartcard, the round subkeys can +* be generated on-the-fly using f32() +* +-****************************************************************************/ +int reKey(keyInstance *key) + { + int i,k64Cnt; + int keyLen = key->keyLen; + int subkeyCnt = ROUND_SUBKEYS + 2*key->numRounds; + DWORD A,B; + DWORD k32e[MAX_KEY_BITS/64],k32o[MAX_KEY_BITS/64]; /* even/odd key dwords */ + +#if VALIDATE_PARMS + #if ALIGN32 + if ((((int)key) & 3) || (((int)key->key32) & 3)) + return BAD_ALIGN32; + #endif + if ((key->keyLen % 64) || (key->keyLen < MIN_KEY_BITS)) + return BAD_KEY_INSTANCE; + if (subkeyCnt > TOTAL_SUBKEYS) + return BAD_KEY_INSTANCE; +#endif + + k64Cnt=(keyLen+63)/64; /* round up to next multiple of 64 bits */ + for (i=0;ikey32[2*i ]; + k32o[i]=key->key32[2*i+1]; + /* compute S-box keys using (12,8) Reed-Solomon code over GF(256) */ + key->sboxKeys[k64Cnt-1-i]=RS_MDS_Encode(k32e[i],k32o[i]); /* reverse order */ + } + + for (i=0;isubKeys[2*i ] = A+ B; /* combine with a PHT */ + key->subKeys[2*i+1] = ROL(A+2*B,SK_ROTL); + } + + DebugDumpKey(key); + + return TRUE; + } +/* ++***************************************************************************** +* +* Function Name: makeKey +* +* Function: Initialize the Twofish key schedule +* +* Arguments: key = ptr to keyInstance to be initialized +* direction = DIR_ENCRYPT or DIR_DECRYPT +* keyLen = # bits of key text at *keyMaterial +* keyMaterial = ptr to hex ASCII chars representing key bits +* +* Return: TRUE on success +* else error code (e.g., BAD_KEY_DIR) +* +* Notes: +* This parses the key bits from keyMaterial. No crypto stuff happens here. +* The function reKey() is called to actually build the key schedule after +* the keyMaterial has been parsed. +* +-****************************************************************************/ +int makeKey(keyInstance *key, BYTE direction, int keyLen,CONST char *keyMaterial) + { + int i; + +#if VALIDATE_PARMS /* first, sanity check on parameters */ + if (key == NULL) + return BAD_KEY_INSTANCE;/* must have a keyInstance to initialize */ + if ((direction != DIR_ENCRYPT) && (direction != DIR_DECRYPT)) + return BAD_KEY_DIR; /* must have valid direction */ + if ((keyLen > MAX_KEY_BITS) || (keyLen < 8)) + return BAD_KEY_MAT; /* length must be valid */ + key->keySig = VALID_SIG; /* show that we are initialized */ + #if ALIGN32 + if ((((int)key) & 3) || (((int)key->key32) & 3)) + return BAD_ALIGN32; + #endif +#endif + + key->direction = direction; /* set our cipher direction */ + key->keyLen = (keyLen+63) & ~63; /* round up to multiple of 64 */ + key->numRounds = numRounds[(keyLen-1)/64]; + for (i=0;ikey32[i]=0; + key->keyMaterial[MAX_KEY_SIZE]=0; /* terminate ASCII string */ + + if ((keyMaterial == NULL) || (keyMaterial[0]==0)) + return TRUE; /* allow a "dummy" call */ + + if (ParseHexDword(keyLen,keyMaterial,key->key32,key->keyMaterial)) + return BAD_KEY_MAT; + + return reKey(key); /* generate round subkeys */ + } + + +/* ++***************************************************************************** +* +* Function Name: cipherInit +* +* Function: Initialize the Twofish cipher in a given mode +* +* Arguments: cipher = ptr to cipherInstance to be initialized +* mode = MODE_ECB, MODE_CBC, or MODE_CFB1 +* IV = ptr to hex ASCII test representing IV bytes +* +* Return: TRUE on success +* else error code (e.g., BAD_CIPHER_MODE) +* +-****************************************************************************/ +int cipherInit(cipherInstance *cipher, BYTE mode,CONST char *IV) + { + int i; +#if VALIDATE_PARMS /* first, sanity check on parameters */ + if (cipher == NULL) + return BAD_PARAMS; /* must have a cipherInstance to initialize */ + if ((mode != MODE_ECB) && (mode != MODE_CBC) && (mode != MODE_CFB1)) + return BAD_CIPHER_MODE; /* must have valid cipher mode */ + cipher->cipherSig = VALID_SIG; + #if ALIGN32 + if ((((int)cipher) & 3) || (((int)cipher->IV) & 3) || (((int)cipher->iv32) & 3)) + return BAD_ALIGN32; + #endif +#endif + + if ((mode != MODE_ECB) && (IV)) /* parse the IV */ + { + if (ParseHexDword(BLOCK_SIZE,IV,cipher->iv32,NULL)) + return BAD_IV_MAT; + for (i=0;iIV)[i] = Bswap(cipher->iv32[i]); + } + + cipher->mode = mode; + + return TRUE; + } + +/* ++***************************************************************************** +* +* Function Name: blockEncrypt +* +* Function: Encrypt block(s) of data using Twofish +* +* Arguments: cipher = ptr to already initialized cipherInstance +* key = ptr to already initialized keyInstance +* input = ptr to data blocks to be encrypted +* inputLen = # bits to encrypt (multiple of blockSize) +* outBuffer = ptr to where to put encrypted blocks +* +* Return: # bits ciphered (>= 0) +* else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL) +* +* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits. +* If inputLen is not a multiple of BLOCK_SIZE bits in those modes, +* an error BAD_INPUT_LEN is returned. In CFB1 mode, all block +* sizes can be supported. +* +-****************************************************************************/ +int blockEncrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input, + int inputLen, BYTE *outBuffer) + { + int i,n,r; /* loop variables */ + DWORD x[BLOCK_SIZE/32]; /* block being encrypted */ + DWORD t0,t1,tmp; /* temp variables */ + int rounds=key->numRounds; /* number of rounds */ + BYTE bit,ctBit,carry; /* temps for CFB */ +#if ALIGN32 + BYTE alignDummy; /* keep 32-bit variable alignment on stack */ +#endif + +#if VALIDATE_PARMS + if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG)) + return BAD_CIPHER_STATE; + if ((key == NULL) || (key->keySig != VALID_SIG)) + return BAD_KEY_INSTANCE; + if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1)) + return BAD_KEY_INSTANCE; + if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE)) + return BAD_INPUT_LEN; + #if ALIGN32 + if ( (((int)cipher) & 3) || (((int)key ) & 3) || + (((int)input ) & 3) || (((int)outBuffer) & 3)) + return BAD_ALIGN32; + #endif +#endif + + if (cipher->mode == MODE_CFB1) + { /* use recursion here to handle CFB, one block at a time */ + cipher->mode = MODE_ECB; /* do encryption in ECB */ + for (n=0;nIV,BLOCK_SIZE,(BYTE *)x); + bit = 0x80 >> (n & 7);/* which bit position in byte */ + ctBit = (input[n/8] & bit) ^ ((((BYTE *) x)[0] & 0x80) >> (n&7)); + outBuffer[n/8] = (outBuffer[n/8] & ~ bit) | ctBit; + carry = ctBit >> (7 - (n&7)); + for (i=BLOCK_SIZE/8-1;i>=0;i--) + { + bit = cipher->IV[i] >> 7; /* save next "carry" from shift */ + cipher->IV[i] = (cipher->IV[i] << 1) ^ carry; + carry = bit; + } + } + cipher->mode = MODE_CFB1; /* restore mode for next time */ + return inputLen; + } + + /* here for ECB, CBC modes */ + for (n=0;nmode == MODE_CBC) + DebugDump(cipher->iv32,"",IV_ROUND,0,0,0,0); +#endif + for (i=0;isubKeys[INPUT_WHITEN+i]; + if (cipher->mode == MODE_CBC) + x[i] ^= Bswap(cipher->iv32[i]); + } + + DebugDump(x,"",0,0,0,0,0); + for (r=0;rsboxKeys,key->keyLen); + t1 = f32(ROL(x[1],8+(r+1)/2),key->sboxKeys,key->keyLen); + /* PHT, round keys */ + x[2]^= ROL(t0 + t1 + key->subKeys[ROUND_SUBKEYS+2*r ], r /2); + x[3]^= ROR(t0 + 2*t1 + key->subKeys[ROUND_SUBKEYS+2*r+1],(r+2) /2); + + DebugDump(x,"",r+1,2*(r&1),1,1,0); +#else + t0 = f32( x[0] ,key->sboxKeys,key->keyLen); + t1 = f32(ROL(x[1],8),key->sboxKeys,key->keyLen); + + x[3] = ROL(x[3],1); + x[2]^= t0 + t1 + key->subKeys[ROUND_SUBKEYS+2*r ]; /* PHT, round keys */ + x[3]^= t0 + 2*t1 + key->subKeys[ROUND_SUBKEYS+2*r+1]; + x[2] = ROR(x[2],1); + + DebugDump(x,"",r+1,2*(r&1),0,1,0);/* make format compatible with optimized code */ +#endif + if (r < rounds-1) /* swap for next round */ + { + tmp = x[0]; x[0]= x[2]; x[2] = tmp; + tmp = x[1]; x[1]= x[3]; x[3] = tmp; + } + } +#if FEISTEL + x[0] = ROR(x[0],8); /* "final permutation" */ + x[1] = ROL(x[1],8); + x[2] = ROR(x[2],8); + x[3] = ROL(x[3],8); +#endif + for (i=0;isubKeys[OUTPUT_WHITEN+i]); + if (cipher->mode == MODE_CBC) + cipher->iv32[i] = ((DWORD *)outBuffer)[i]; + } +#ifdef DEBUG + DebugDump(outBuffer,"",rounds+1,0,0,0,1); + if (cipher->mode == MODE_CBC) + DebugDump(cipher->iv32,"",IV_ROUND,0,0,0,0); +#endif + } + + return inputLen; + } + +/* ++***************************************************************************** +* +* Function Name: blockDecrypt +* +* Function: Decrypt block(s) of data using Twofish +* +* Arguments: cipher = ptr to already initialized cipherInstance +* key = ptr to already initialized keyInstance +* input = ptr to data blocks to be decrypted +* inputLen = # bits to encrypt (multiple of blockSize) +* outBuffer = ptr to where to put decrypted blocks +* +* Return: # bits ciphered (>= 0) +* else error code (e.g., BAD_CIPHER_STATE, BAD_KEY_MATERIAL) +* +* Notes: The only supported block size for ECB/CBC modes is BLOCK_SIZE bits. +* If inputLen is not a multiple of BLOCK_SIZE bits in those modes, +* an error BAD_INPUT_LEN is returned. In CFB1 mode, all block +* sizes can be supported. +* +-****************************************************************************/ +int blockDecrypt(cipherInstance *cipher, keyInstance *key,CONST BYTE *input, + int inputLen, BYTE *outBuffer) + { + int i,n,r; /* loop counters */ + DWORD x[BLOCK_SIZE/32]; /* block being encrypted */ + DWORD t0,t1; /* temp variables */ + int rounds=key->numRounds; /* number of rounds */ + BYTE bit,ctBit,carry; /* temps for CFB */ +#if ALIGN32 + BYTE alignDummy; /* keep 32-bit variable alignment on stack */ +#endif + +#if VALIDATE_PARMS + if ((cipher == NULL) || (cipher->cipherSig != VALID_SIG)) + return BAD_CIPHER_STATE; + if ((key == NULL) || (key->keySig != VALID_SIG)) + return BAD_KEY_INSTANCE; + if ((rounds < 2) || (rounds > MAX_ROUNDS) || (rounds&1)) + return BAD_KEY_INSTANCE; + if ((cipher->mode != MODE_CFB1) && (inputLen % BLOCK_SIZE)) + return BAD_INPUT_LEN; + #if ALIGN32 + if ( (((int)cipher) & 3) || (((int)key ) & 3) || + (((int)input) & 3) || (((int)outBuffer) & 3)) + return BAD_ALIGN32; + #endif +#endif + + if (cipher->mode == MODE_CFB1) + { /* use blockEncrypt here to handle CFB, one block at a time */ + cipher->mode = MODE_ECB; /* do encryption in ECB */ + for (n=0;nIV,BLOCK_SIZE,(BYTE *)x); + bit = 0x80 >> (n & 7); + ctBit = input[n/8] & bit; + outBuffer[n/8] = (outBuffer[n/8] & ~ bit) | + (ctBit ^ ((((BYTE *) x)[0] & 0x80) >> (n&7))); + carry = ctBit >> (7 - (n&7)); + for (i=BLOCK_SIZE/8-1;i>=0;i--) + { + bit = cipher->IV[i] >> 7; /* save next "carry" from shift */ + cipher->IV[i] = (cipher->IV[i] << 1) ^ carry; + carry = bit; + } + } + cipher->mode = MODE_CFB1; /* restore mode for next time */ + return inputLen; + } + + /* here for ECB, CBC modes */ + for (n=0;nsubKeys[OUTPUT_WHITEN+i]; + + for (r=rounds-1;r>=0;r--) /* main Twofish decryption loop */ + { + t0 = f32( x[0] ,key->sboxKeys,key->keyLen); + t1 = f32(ROL(x[1],8),key->sboxKeys,key->keyLen); + + DebugDump(x,"",r+1,2*(r&1),0,1,0);/* make format compatible with optimized code */ + x[2] = ROL(x[2],1); + x[2]^= t0 + t1 + key->subKeys[ROUND_SUBKEYS+2*r ]; /* PHT, round keys */ + x[3]^= t0 + 2*t1 + key->subKeys[ROUND_SUBKEYS+2*r+1]; + x[3] = ROR(x[3],1); + + if (r) /* unswap, except for last round */ + { + t0 = x[0]; x[0]= x[2]; x[2] = t0; + t1 = x[1]; x[1]= x[3]; x[3] = t1; + } + } + DebugDump(x,"",0,0,0,0,0);/* make final output match encrypt initial output */ + + for (i=0;isubKeys[INPUT_WHITEN+i]; + if (cipher->mode == MODE_CBC) + { + x[i] ^= Bswap(cipher->iv32[i]); + cipher->iv32[i] = ((DWORD *)input)[i]; + } + ((DWORD *)outBuffer)[i] = Bswap(x[i]); + } + DebugDump(outBuffer,"",-1,0,0,0,1); + } + + return inputLen; + } + + +#ifdef GetCodeSize +DWORD TwofishCodeSize(void) { return Here(0)-TwofishCodeStart(); }; +#endif diff --git a/twofish/aes.h b/twofish/aes.h new file mode 100644 index 0000000..570a95d --- /dev/null +++ b/twofish/aes.h @@ -0,0 +1,268 @@ +/* aes.h */ + +/* ---------- See examples at end of this file for typical usage -------- */ + +/* AES Cipher header file for ANSI C Submissions + Lawrence E. Bassham III + Computer Security Division + National Institute of Standards and Technology + + This sample is to assist implementers developing to the +Cryptographic API Profile for AES Candidate Algorithm Submissions. +Please consult this document as a cross-reference. + + ANY CHANGES, WHERE APPROPRIATE, TO INFORMATION PROVIDED IN THIS FILE +MUST BE DOCUMENTED. CHANGES ARE ONLY APPROPRIATE WHERE SPECIFIED WITH +THE STRING "CHANGE POSSIBLE". FUNCTION CALLS AND THEIR PARAMETERS +CANNOT BE CHANGED. STRUCTURES CAN BE ALTERED TO ALLOW IMPLEMENTERS TO +INCLUDE IMPLEMENTATION SPECIFIC INFORMATION. +*/ + +/* Includes: + Standard include files +*/ + +#include +#include "platform.h" /* platform-specific defines */ + +/* Defines: + Add any additional defines you need +*/ + +#define DIR_ENCRYPT 0 /* Are we encrpyting? */ +#define DIR_DECRYPT 1 /* Are we decrpyting? */ +#define MODE_ECB 1 /* Are we ciphering in ECB mode? */ +#define MODE_CBC 2 /* Are we ciphering in CBC mode? */ +#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */ + +#define TRUE 1 +#define FALSE 0 + +#define BAD_KEY_DIR -1 /* Key direction is invalid (unknown value) */ +#define BAD_KEY_MAT -2 /* Key material not of correct length */ +#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */ +#define BAD_CIPHER_MODE -4 /* Params struct passed to cipherInit invalid */ +#define BAD_CIPHER_STATE -5 /* Cipher in wrong state (e.g., not initialized) */ + +/* CHANGE POSSIBLE: inclusion of algorithm specific defines */ +/* TWOFISH specific definitions */ +#define MAX_KEY_SIZE 64 /* # of ASCII chars needed to represent a key */ +#define MAX_IV_SIZE 16 /* # of bytes needed to represent an IV */ +#define BAD_INPUT_LEN -6 /* inputLen not a multiple of block size */ +#define BAD_PARAMS -7 /* invalid parameters */ +#define BAD_IV_MAT -8 /* invalid IV text */ +#define BAD_ENDIAN -9 /* incorrect endianness define */ +#define BAD_ALIGN32 -10 /* incorrect 32-bit alignment */ + +#define BLOCK_SIZE 128 /* number of bits per block */ +#define MAX_ROUNDS 16 /* max # rounds (for allocating subkey array) */ +#define ROUNDS_128 16 /* default number of rounds for 128-bit keys*/ +#define ROUNDS_192 16 /* default number of rounds for 192-bit keys*/ +#define ROUNDS_256 16 /* default number of rounds for 256-bit keys*/ +#define MAX_KEY_BITS 256 /* max number of bits of key */ +#define MIN_KEY_BITS 128 /* min number of bits of key (zero pad) */ +#define VALID_SIG 0x48534946 /* initialization signature ('FISH') */ +#define MCT_OUTER 400 /* MCT outer loop */ +#define MCT_INNER 10000 /* MCT inner loop */ +#define REENTRANT 1 /* nonzero forces reentrant code (slightly slower) */ + +#define INPUT_WHITEN 0 /* subkey array indices */ +#define OUTPUT_WHITEN ( INPUT_WHITEN + BLOCK_SIZE/32) +#define ROUND_SUBKEYS (OUTPUT_WHITEN + BLOCK_SIZE/32) /* use 2 * (# rounds) */ +#define TOTAL_SUBKEYS (ROUND_SUBKEYS + 2*MAX_ROUNDS) + +/* Typedefs: + Typedef'ed data storage elements. Add any algorithm specific + parameters at the bottom of the structs as appropriate. +*/ + +typedef unsigned char BYTE; +typedef unsigned long DWORD; /* 32-bit unsigned quantity */ +typedef DWORD fullSbox[4][256]; + +/* The structure for key information */ +typedef struct + { + BYTE direction; /* Key used for encrypting or decrypting? */ +#if ALIGN32 + BYTE dummyAlign[3]; /* keep 32-bit alignment */ +#endif + int keyLen; /* Length of the key */ + char keyMaterial[MAX_KEY_SIZE+4];/* Raw key data in ASCII */ + + /* Twofish-specific parameters: */ + DWORD keySig; /* set to VALID_SIG by makeKey() */ + int numRounds; /* number of rounds in cipher */ + DWORD key32[MAX_KEY_BITS/32]; /* actual key bits, in dwords */ + DWORD sboxKeys[MAX_KEY_BITS/64];/* key bits used for S-boxes */ + DWORD subKeys[TOTAL_SUBKEYS]; /* round subkeys, input/output whitening bits */ +#if REENTRANT + fullSbox sBox8x32; /* fully expanded S-box */ + #if defined(COMPILE_KEY) && defined(USE_ASM) +#undef VALID_SIG +#define VALID_SIG 0x504D4F43 /* 'COMP': C is compiled with -DCOMPILE_KEY */ + DWORD cSig1; /* set after first "compile" (zero at "init") */ + void *encryptFuncPtr; /* ptr to asm encrypt function */ + void *decryptFuncPtr; /* ptr to asm decrypt function */ + DWORD codeSize; /* size of compiledCode */ + DWORD cSig2; /* set after first "compile" */ + BYTE compiledCode[5000]; /* make room for the code itself */ + #endif +#endif + } keyInstance; + +/* The structure for cipher information */ +typedef struct + { + BYTE mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */ +#if ALIGN32 + BYTE dummyAlign[3]; /* keep 32-bit alignment */ +#endif + BYTE IV[MAX_IV_SIZE]; /* CFB1 iv bytes (CBC uses iv32) */ + + /* Twofish-specific parameters: */ + DWORD cipherSig; /* set to VALID_SIG by cipherInit() */ + DWORD iv32[BLOCK_SIZE/32]; /* CBC IV bytes arranged as dwords */ + } cipherInstance; + +/* Function protoypes */ +int makeKey(keyInstance *key, BYTE direction, int keyLen, char *keyMaterial); + +int cipherInit(cipherInstance *cipher, BYTE mode, char *IV); + +int blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input, + int inputLen, BYTE *outBuffer); + +int blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input, + int inputLen, BYTE *outBuffer); + +int reKey(keyInstance *key); /* do key schedule using modified key.keyDwords */ + +/* API to check table usage, for use in ECB_TBL KAT */ +#define TAB_DISABLE 0 +#define TAB_ENABLE 1 +#define TAB_RESET 2 +#define TAB_QUERY 3 +#define TAB_MIN_QUERY 50 +int TableOp(int op); + + +#define CONST /* helpful C++ syntax sugar, NOP for ANSI C */ + +#if BLOCK_SIZE == 128 /* optimize block copies */ +#define Copy1(d,s,N) ((DWORD *)(d))[N] = ((DWORD *)(s))[N] +#define BlockCopy(d,s) { Copy1(d,s,0);Copy1(d,s,1);Copy1(d,s,2);Copy1(d,s,3); } +#else +#define BlockCopy(d,s) { memcpy(d,s,BLOCK_SIZE/8); } +#endif + + +#ifdef TEST_2FISH +/* ----- EXAMPLES ----- + +Unfortunately, the AES API is somewhat clumsy, and it is not entirely +obvious how to use the above functions. In particular, note that +makeKey() takes an ASCII hex nibble key string (e.g., 32 characters +for a 128-bit key), which is rarely the way that keys are internally +represented. The reKey() function uses instead the keyInstance.key32 +array of key bits and is the preferred method. In fact, makeKey() +initializes some internal keyInstance state, then parse the ASCII +string into the binary key32, and calls reKey(). To initialize the +keyInstance state, use a 'dummy' call to makeKey(); i.e., set the +keyMaterial parameter to NULL. Then use reKey() for all key changes. +Similarly, cipherInit takes an IV string in ASCII hex, so a dummy setup +call with a null IV string will skip the ASCII parse. + +Note that CFB mode is not well tested nor defined by AES, so using the +Twofish MODE_CFB it not recommended. If you wish to implement a CFB mode, +build it external to the Twofish code, using the Twofish functions only +in ECB mode. + +Below is a sample piece of code showing how the code is typically used +to set up a key, encrypt, and decrypt. Error checking is somewhat limited +in this example. Pseudorandom bytes are used for all key and text. + +If you compile TWOFISH2.C or TWOFISH.C as a DOS (or Windows Console) app +with this code enabled, the test will be run. For example, using +Borland C, you would compile using: + BCC32 -DTEST_2FISH twofish2.c +to run the test on the optimized code, or + BCC32 -DTEST_2FISH twofish.c +to run the test on the pedagogical code. + +*/ + +#include +#include +#include +#include + +#define MAX_BLK_CNT 4 /* max # blocks per call in TestTwofish */ +int TestTwofish(int mode,int keySize) /* keySize must be 128, 192, or 256 */ + { /* return 0 iff test passes */ + keyInstance ki; /* key information, including tables */ + cipherInstance ci; /* keeps mode (ECB, CBC) and IV */ + BYTE plainText[MAX_BLK_CNT*(BLOCK_SIZE/8)]; + BYTE cipherText[MAX_BLK_CNT*(BLOCK_SIZE/8)]; + BYTE decryptOut[MAX_BLK_CNT*(BLOCK_SIZE/8)]; + BYTE iv[BLOCK_SIZE/8]; + int i,byteCnt; + + if (makeKey(&ki,DIR_ENCRYPT,keySize,NULL) != TRUE) + return 1; /* 'dummy' setup for a 128-bit key */ + if (cipherInit(&ci,mode,NULL) != TRUE) + return 1; /* 'dummy' setup for cipher */ + + for (i=0;ikeyLen+63)/64; /* round up to next multiple of 64 bits */ + int subkeyCnt = ROUND_SUBKEYS + 2*key->numRounds; + + sprintf(line,";\n;makeKey: Input key --> S-box key [%s]\n", + (key->direction == DIR_ENCRYPT) ? "Encrypt" : "Decrypt"); + DebugIO(line); + for (i=0;i %08lX\n","", + key->key32[2*i+1],key->key32[2*i],key->sboxKeys[k64Cnt-1-i]); + DebugIO(line); + } + sprintf(line,";%11sSubkeys\n",""); + DebugIO(line); + for (i=0;isubKeys[2*i],key->subKeys[2*i+1], + (2*i == INPUT_WHITEN) ? " Input whiten" : + (2*i == OUTPUT_WHITEN) ? " Output whiten" : + (2*i == ROUND_SUBKEYS) ? " Round subkeys" : ""); + DebugIO(line); + } + DebugIO(";\n"); + } +#else +CONST int debugCompile = 0; +#define DebugDump(x,s,R,XOR,doRot,showT,needBswap) +#define DebugDumpKey(key) +#endif diff --git a/twofish/platform.h b/twofish/platform.h new file mode 100644 index 0000000..400ea28 --- /dev/null +++ b/twofish/platform.h @@ -0,0 +1,75 @@ +/*************************************************************************** + PLATFORM.H -- Platform-specific defines for TWOFISH code + + Submitters: + Bruce Schneier, Counterpane Systems + Doug Whiting, Hi/fn + John Kelsey, Counterpane Systems + Chris Hall, Counterpane Systems + David Wagner, UC Berkeley + + Code Author: Doug Whiting, Hi/fn + + Version 1.00 April 1998 + + Copyright 1998, Hi/fn and Counterpane Systems. All rights reserved. + + Notes: + * Tab size is set to 4 characters in this file + +***************************************************************************/ + +/* use intrinsic rotate if possible */ +#define ROL(x,n) (((x) << ((n) & 0x1F)) | ((x) >> (32-((n) & 0x1F)))) +#define ROR(x,n) (((x) >> ((n) & 0x1F)) | ((x) << (32-((n) & 0x1F)))) + +#if (0) && defined(__BORLANDC__) && (__BORLANDC__ >= 0x462) +#error "!!!This does not work for some reason!!!" +#include /* get prototype for _lrotl() , _lrotr() */ +#pragma inline __lrotl__ +#pragma inline __lrotr__ +#undef ROL /* get rid of inefficient definitions */ +#undef ROR +#define ROL(x,n) __lrotl__(x,n) /* use compiler intrinsic rotations */ +#define ROR(x,n) __lrotr__(x,n) +#endif + +#ifdef _MSC_VER +#include /* get prototypes for rotation functions */ +#undef ROL +#undef ROR +#pragma intrinsic(_lrotl,_lrotr) /* use intrinsic compiler rotations */ +#define ROL(x,n) _lrotl(x,n) +#define ROR(x,n) _lrotr(x,n) +#endif + +#if !defined(__i386__) && !defined(__x86_64__) +#ifdef __BORLANDC__ +#define __i386__ 300 /* make sure this is defined for Intel CPUs */ +#endif +#endif + +#if defined(__i386__) || defined(__x86_64__) || defined(__arm__) +#define LittleEndian 1 /* e.g., 1 for Pentium, 0 for 68K */ +#define ALIGN32 0 /* need dword alignment? (no for Pentium) */ +#else /* non-Intel platforms */ +#define LittleEndian 0 /* (assume big endian */ +#define ALIGN32 0 /* (assume need alignment for non-Intel) */ +#endif + +#if LittleEndian +#define Bswap(x) (x) /* NOP for little-endian machines */ +#define ADDR_XOR 0 /* NOP for little-endian machines */ +#else +#define Bswap(x) ((ROR(x,8) & 0xFF00FF00) | (ROL(x,8) & 0x00FF00FF)) +#define ADDR_XOR 3 /* convert byte address in dword */ +#endif + +/* Macros for extracting bytes from dwords (correct for endianness) */ +#define _b(x,N) (((BYTE *)&x)[((N) & 3) ^ ADDR_XOR]) /* pick bytes out of a dword */ + +#define b0(x) _b(x,0) /* extract LSB of DWORD */ +#define b1(x) _b(x,1) +#define b2(x) _b(x,2) +#define b3(x) _b(x,3) /* extract MSB of DWORD */ + diff --git a/twofish/table.h b/twofish/table.h new file mode 100644 index 0000000..5c3c590 --- /dev/null +++ b/twofish/table.h @@ -0,0 +1,228 @@ +/*************************************************************************** + TABLE.H -- Tables, macros, constants for Twofish S-boxes and MDS matrix + + Submitters: + Bruce Schneier, Counterpane Systems + Doug Whiting, Hi/fn + John Kelsey, Counterpane Systems + Chris Hall, Counterpane Systems + David Wagner, UC Berkeley + + Code Author: Doug Whiting, Hi/fn + + Version 1.00 April 1998 + + Copyright 1998, Hi/fn and Counterpane Systems. All rights reserved. + + Notes: + * Tab size is set to 4 characters in this file + * These definitions should be used in optimized and unoptimized + versions to insure consistency. + +***************************************************************************/ + +/* for computing subkeys */ +#define SK_STEP 0x02020202u +#define SK_BUMP 0x01010101u +#define SK_ROTL 9 + +/* Reed-Solomon code parameters: (12,8) reversible code + g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1 + where a = primitive root of field generator 0x14D */ +#define RS_GF_FDBK 0x14D /* field generator */ +#define RS_rem(x) \ + { BYTE b = (BYTE) (x >> 24); \ + DWORD g2 = ((b << 1) ^ ((b & 0x80) ? RS_GF_FDBK : 0 )) & 0xFF; \ + DWORD g3 = ((b >> 1) & 0x7F) ^ ((b & 1) ? RS_GF_FDBK >> 1 : 0 ) ^ g2 ; \ + x = (x << 8) ^ (g3 << 24) ^ (g2 << 16) ^ (g3 << 8) ^ b; \ + } + +/* Macros for the MDS matrix +* The MDS matrix is (using primitive polynomial 169): +* 01 EF 5B 5B +* 5B EF EF 01 +* EF 5B 01 EF +* EF 01 EF 5B +*---------------------------------------------------------------- +* More statistical properties of this matrix (from MDS.EXE output): +* +* Min Hamming weight (one byte difference) = 8. Max=26. Total = 1020. +* Prob[8]: 7 23 42 20 52 95 88 94 121 128 91 +* 102 76 41 24 8 4 1 3 0 0 0 +* Runs[8]: 2 4 5 6 7 8 9 11 +* MSBs[8]: 1 4 15 8 18 38 40 43 +* HW= 8: 05040705 0A080E0A 14101C14 28203828 50407050 01499101 A080E0A0 +* HW= 9: 04050707 080A0E0E 10141C1C 20283838 40507070 80A0E0E0 C6432020 07070504 +* 0E0E0A08 1C1C1410 38382820 70705040 E0E0A080 202043C6 05070407 0A0E080E +* 141C101C 28382038 50704070 A0E080E0 4320C620 02924B02 089A4508 +* Min Hamming weight (two byte difference) = 3. Max=28. Total = 390150. +* Prob[3]: 7 18 55 149 270 914 2185 5761 11363 20719 32079 +* 43492 51612 53851 52098 42015 31117 20854 11538 6223 2492 1033 +* MDS OK, ROR: 6+ 7+ 8+ 9+ 10+ 11+ 12+ 13+ 14+ 15+ 16+ +* 17+ 18+ 19+ 20+ 21+ 22+ 23+ 24+ 25+ 26+ +*/ +#define MDS_GF_FDBK 0x169 /* primitive polynomial for GF(256)*/ +#define LFSR1(x) ( ((x) >> 1) ^ (((x) & 0x01) ? MDS_GF_FDBK/2 : 0)) +#define LFSR2(x) ( ((x) >> 2) ^ (((x) & 0x02) ? MDS_GF_FDBK/2 : 0) \ + ^ (((x) & 0x01) ? MDS_GF_FDBK/4 : 0)) + +#define Mx_1(x) ((DWORD) (x)) /* force result to dword so << will work */ +#define Mx_X(x) ((DWORD) ((x) ^ LFSR2(x))) /* 5B */ +#define Mx_Y(x) ((DWORD) ((x) ^ LFSR1(x) ^ LFSR2(x))) /* EF */ + +#define M00 Mul_1 +#define M01 Mul_Y +#define M02 Mul_X +#define M03 Mul_X + +#define M10 Mul_X +#define M11 Mul_Y +#define M12 Mul_Y +#define M13 Mul_1 + +#define M20 Mul_Y +#define M21 Mul_X +#define M22 Mul_1 +#define M23 Mul_Y + +#define M30 Mul_Y +#define M31 Mul_1 +#define M32 Mul_Y +#define M33 Mul_X + +#define Mul_1 Mx_1 +#define Mul_X Mx_X +#define Mul_Y Mx_Y + +/* Define the fixed p0/p1 permutations used in keyed S-box lookup. + By changing the following constant definitions for P_ij, the S-boxes will + automatically get changed in all the Twofish source code. Note that P_i0 is + the "outermost" 8x8 permutation applied. See the f32() function to see + how these constants are to be used. +*/ +#define P_00 1 /* "outermost" permutation */ +#define P_01 0 +#define P_02 0 +#define P_03 (P_01^1) /* "extend" to larger key sizes */ +#define P_04 1 + +#define P_10 0 +#define P_11 0 +#define P_12 1 +#define P_13 (P_11^1) +#define P_14 0 + +#define P_20 1 +#define P_21 1 +#define P_22 0 +#define P_23 (P_21^1) +#define P_24 0 + +#define P_30 0 +#define P_31 1 +#define P_32 1 +#define P_33 (P_31^1) +#define P_34 1 + +#define p8(N) P8x8[P_##N] /* some syntax shorthand */ + +/* fixed 8x8 permutation S-boxes */ + +/*********************************************************************** +* 07:07:14 05/30/98 [4x4] TestCnt=256. keySize=128. CRC=4BD14D9E. +* maxKeyed: dpMax = 18. lpMax =100. fixPt = 8. skXor = 0. skDup = 6. +* log2(dpMax[ 6..18])= --- 15.42 1.33 0.89 4.05 7.98 12.05 +* log2(lpMax[ 7..12])= 9.32 1.01 1.16 4.23 8.02 12.45 +* log2(fixPt[ 0.. 8])= 1.44 1.44 2.44 4.06 6.01 8.21 11.07 14.09 17.00 +* log2(skXor[ 0.. 0]) +* log2(skDup[ 0.. 6])= --- 2.37 0.44 3.94 8.36 13.04 17.99 +***********************************************************************/ +CONST BYTE P8x8[2][256]= + { +/* p0: */ +/* dpMax = 10. lpMax = 64. cycleCnt= 1 1 1 0. */ +/* 817D6F320B59ECA4.ECB81235F4A6709D.BA5E6D90C8F32471.D7F4126E9B3085CA. */ +/* Karnaugh maps: +* 0111 0001 0011 1010. 0001 1001 1100 1111. 1001 1110 0011 1110. 1101 0101 1111 1001. +* 0101 1111 1100 0100. 1011 0101 0010 0000. 0101 1000 1100 0101. 1000 0111 0011 0010. +* 0000 1001 1110 1101. 1011 1000 1010 0011. 0011 1001 0101 0000. 0100 0010 0101 1011. +* 0111 0100 0001 0110. 1000 1011 1110 1001. 0011 0011 1001 1101. 1101 0101 0000 1100. +*/ + { + 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: */ +/* dpMax = 10. lpMax = 64. cycleCnt= 2 0 0 1. */ +/* 28BDF76E31940AC5.1E2B4C376DA5F908.4C75169A0ED82B3F.B951C3DE647F208A. */ +/* Karnaugh maps: +* 0011 1001 0010 0111. 1010 0111 0100 0110. 0011 0001 1111 0100. 1111 1000 0001 1100. +* 1100 1111 1111 1010. 0011 0011 1110 0100. 1001 0110 0100 0011. 0101 0110 1011 1011. +* 0010 0100 0011 0101. 1100 1000 1000 1110. 0111 1111 0010 0110. 0000 1010 0000 0011. +* 1101 1000 0010 0001. 0110 1001 1110 0101. 0001 0100 0101 0111. 0011 1011 1111 0010. +*/ + { + 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 + } + };