home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Hacker Chronicles 2
/
HACKER2.BIN
/
1200.BASSLIB.C
< prev
next >
Wrap
Text File
|
1991-05-22
|
35KB
|
990 lines
/* basslib.c -- BassOmatic encipherment functions in C.
Version 1.0 25 Jun 89 - Last revised 22 May 91
(c) Copyright 1988 by Philip Zimmermann. All rights reserved.
This software may not be copied without the written permission of
Philip Zimmermann. The author assumes no liability for damages
resulting from the use of this software, even if the damage results
from defects in this software. No warranty is expressed or implied.
Boulder Software Engineering
3021 Eleventh Street
Boulder, CO 80304 USA
Tel. (303) 444-4541
FAX (303) 444-4541 ext. 10
BassOmatic is a conventional block cipher with a 256-byte
block size for the plaintext and the ciphertext. It also
uses a key size of up to 256 bytes. It runs fairly quickly
on a computer, faster than most simple DES implementations.
Like the DES, it can be used in cipher feedback and cipher block
chaining modes. It is based in part on Charles W. Merritt's
algorithms which have been used in secure military communications.
Merritt's original designs were refined by Zhahai Stewart and
Philip Zimmermann to improve security and to improve performance
in a portable C implementation. BassOmatic has not yet (in 1989)
been through a formal security review and has had only limited peer
review. The initial version was implemented in Microsoft C for the
IBM PC, and it has been ported to MPW C on the Apple Macintosh
and to Unix C without significant modification.
BassOmatic gets its name from an old Dan Aykroyd Saturday Night Live
skit involving a blender and a whole fish. The BassOmatic algorithm
does to data what the original BassOmatic did to the fish.
*/
/* Define STATIC as blank to assist execution performance profiling. */
#define STATIC static /* define STATIC as static for normal use */
#include <stdio.h> /* for printf */
#include "memmgr.h" /* memory manager headers */
#include "lfsr.h" /* Linear Feedback Shift Register headers */
#include "basslib.h" /* BassOmatic headers */
/* on many CPUs, using 16 bits for bytecounter is actually faster: */
#define bytecounter word16 /* byte, or word16 for speed */
#ifdef DEBUG
#define DEBUGprintf1(x) fprintf(stderr,x)
#define DEBUGprintf2(x,y) fprintf(stderr,x,y)
#else
#define DEBUGprintf1(x) /* null macro */
#define DEBUGprintf2(x,y) /* null macro */
#endif
#define NCONTEXTS 3 /* number of key contexts allowed at once */
/* NUMBLOX is number of memory blocks in partition */
#define NUMBLOX (NCONTEXTS*(NTABLES+3)+8)
/* declare memory partition buffer space */
static byte part[partsize(256,NUMBLOX)]; /* memory partition */
/* We could just call calloc() for this space, instead of declaring it here. */
/* The following variables comprise the keyed context information for the
** BassOmatic machine. If the BassOmatic is rekeyed, these variables
** will be affected. If more than one BassOmatic key context is needed
** concurrently, these variables must be saved and restored for each
** context change.
*/
static boolean initialized = FALSE; /* determines whether key context is defined */
static byteptr tlist[NTABLES] = {nil}; /* list of permutation table pointers */
static byte bitmasks[NTABLES]; /* bitshredder bitmasks with 50% bits set */
static byteptr iv = nil; /* CFB Initialization Vector used by initcfb and basscfb */
static boolean cfbuncryp = FALSE; /* TRUE means decrypting (in CFB mode) */
static boolean uncryp = FALSE; /* TRUE means decrypting (in ECB mode) */
/* The following parameters are computed from the key control byte...*/
static char nrounds = 0; /* specifies number of rounds thru BassOmatic */
static boolean hardrand = FALSE; /* means regenerate tables with BassOmatic */
static boolean shred8ways = FALSE; /* means use 8-way bit shredding */
static boolean rerand = FALSE; /* means replenish tables with every block */
static byteptr lfsr = nil; /* it would help to align LFSR on 256-byte boundary */
/* rtail is an index into LFSR buffer */
static byte rtail = 0; /* points to 256, which is same as 0 */
/* End of BassOmatic keyed context variables */
/*
** fillbuf(dst,count,c) - fill byte buffer dst with byte c
** dst is destination buffer pointer.
** count is nonzero byte count.
** c is fill byte.
*/
void fillbuf(register byteptr dst, register short count, register byte c)
{ do *dst++ = c; while (--count);
} /* fillbuf */
/*
** CRC routines are purely for debugging purposes...
*/
#define CRCDEBUG /* enables CRC debugging code */
#ifdef CRCDEBUG
/*
** updcrc - updates CRC 16-bit accumulator with ch,
** uses CCITT polynomial: X^16 + X^12 + X^5 + 1
*/
static word16 updcrc(byte ch, word16 crcaccum)
{ word16 shifter,flag,data;
data = ((word16) ch) & 0xff;
for (shifter = 0x80; shifter; shifter >>= 1)
{ flag = (crcaccum & 0x8000);
crcaccum <<= 1;
crcaccum |= ((shifter & data) ? 1 : 0);
if (flag) crcaccum ^= 0x1021;
}
return (crcaccum & 0xffff);
} /* updcrc() */
/*
** crc() - compute crc of buffer
** Used for diagnostic purposes.
*/
word16 crc(register byteptr buf, int count)
{ word16 crcaccum; /* CRC accumulator */
crcaccum = 0; /* clear crc accumulator */
do crcaccum = updcrc(*buf++,crcaccum);
while (--count); /* loop 256 times */
crcaccum = updcrc(0,crcaccum); /* finish up crc */
crcaccum = updcrc(0,crcaccum); /* have to do it twice */
return(crcaccum); /* return 16-bit CRC */
} /* crc */
#define dumpcrc(msg,buf) printf("%s CRC=%04x ",msg,crc(buf,256))
/*
** dumpblock - dump 256-byte buffer in hex
*/
static void dumpblock(byteptr buf)
{ bytecounter i;
i = 256;
printf(" Memory block at %04X: ",buf);
do
{ if ((i & 15)==0)
putchar('\n');
printf("%02X ",*buf++);
} while (--i); /* loop 256 times */
dumpcrc("",buf-256);
putchar('\n');
} /* dumpblock */
#endif /* end of CRC debugging routines */
/*
** randbuf and randbuf_counter are used by initbassrand, initbrand,
** bassrand, and closebrand. They are not directly used by the BassOmatic
** routines except by initkey(), and thus are not considered part of a
** lasting key context.
*/
static byteptr randbuf = nil; /* buffer for BassOmatic random # generator */
static byte randbuf_counter = 0; /* # of random bytes left in randbuf */
/*
** initbrand - initialize bassrand, BassOmatic random number generator
** For internal use by initkey() only.
** seed is pointer to random number seed buffer.
** seedlen is length of seed buffer, must be <= 256.
*/
static void initbrand(byteptr seed, short seedlen)
{ short i;
if (randbuf==nil)
randbuf = (byteptr) gblock(part); /* allocate block */
if (seedlen > 256) seedlen=256;
for (i=0; i<seedlen; i++) /* copy original seed material to randbuf */
randbuf[i] = seed[i];
/* fill rest of randbuf with randomly modified key material */
for (; i<256; i++) /* pick up where we left off */
randbuf[i] = getlfsr(lfsr,rtail); /* macro gets LFSR byte */
randbuf_counter = 0; /* # of random bytes left in randbuf */
} /* initbrand */
/*
** initbassrand - initialize bassrand, BassOmatic random number generator
** This can be used for generating cryptographically strong random
** numbers by any external application code outside the BassOmatic.
** key is pointer to BassOmatic key buffer.
** keylen is length of key buffer, must be < 256.
** seed is pointer to random number seed buffer.
** seedlen is length of seed buffer, must be <= 256.
**
** NOTE: Because this routine calls initkey(), this generator
** must be closed by calling closebass(), NOT closebrand().
*/
void initbassrand(byteptr key, short keylen, byteptr seed, short seedlen)
{ short i;
if (randbuf==nil) /* prevents multiple initialization */
{ initkey(key, keylen, FALSE); /* initialize BassOmatic */
randbuf = (byteptr) gblock(part); /* allocate block */
}
fillbuf(randbuf,256,0); /* get a clean start */
if (seedlen > 256) seedlen=256;
for (i=0; i<seedlen; i++) /* copy original seed material to randbuf */
randbuf[i] = seed[i];
randbuf_counter = 0; /* # of random bytes left in randbuf */
} /* initbassrand */
/*
** bassrand - BassOmatic pseudo-random number generator
** This can be used for generating cryptographically strong random
** numbers by any external application code outside the BassOmatic.
*/
byte bassrand(void)
{ byteptr tmp;
if (randbuf_counter==0) /* if random buffer is spent...*/
{ tmp = (byteptr) gblock(part); /* allocate new block */
bassomatic(randbuf,tmp); /* fill new block */
rblock(part,randbuf); /* release old spent block */
randbuf = tmp; /* start on new block */
}
return(randbuf[--randbuf_counter]); /* take a byte from randbuf */
} /* bassrand */
/*
** closebrand - deallocate storage used by bassrand
** For internal use by initkey() only.
*/
static void closebrand(void)
{ if (randbuf!=nil)
randbuf = rblock(part,randbuf); /* release block */
} /* closebrand */
/*
** buildtbl - build a random byte permutation vector
**
** References context variables lfsr, rtail, and part.
**
** A permutation vector is a table of 256 bytes containing the
** values 0-255 in random order. Each of the values 0-255 appears
** exactly once in the table, with no duplicates and no omissions.
**
** The appropriate way to build such a table for cryptographic
** applications is to do the following:
** 1) Start with an empty table, meaning its length is zero.
** 2) Use a pseudo-random number generator to generate random bytes
** that are appended to the table if and only if they are not
** already in the table. If the random byte is already in the
** table, it is discarded and another one is generated from the
** pseudo-random number generator. As the table gets nearly full,
** more and more random bytes are discarded as duplicate entries.
** This is continued until 256 bytes have been inserted in the table.
**
** While this approach seems computationally wasteful, it makes it harder
** for a cryptanalyst to infer the properties of the pseudo-random number
** generator, because so many of its output bytes are discarded.
**
** Permutation vectors such as these are useful for byte substitution
** tables and byte transposition tables. These are also referred to
** herein as key schedule tables.
*/
STATIC void buildtbl(register byteptr table, boolean rselect)
/* table is pointer to table to build.
rselect is to select which of 2 random number generators to use.
*/
{ register byteptr notdup; /* scratchpad bitmap */
register byte c;
register short tlen; /* current accumulated table length */
register short randtics; /* counts LFSR tics */
#define MAXTICS 16383 /* lose patience with LFSR after this long */
notdup = (byteptr) gblock(part); /* we could use local stack array instead. */
fillbuf(notdup,256,TRUE); /* initialize scratchpad bitmap */
tlen = 0; /* start new table with length 0 */
/* To fill one table, we can expect to have to tic the LFSR
typically about 1000-2500 times, on the average. */
randtics = MAXTICS; /* countdown maximum LFSR tics */
do
{ /* get pseudo-random byte from either LFSR or BassOmatic... */
c = rselect ?
bassrand() : /* get a hard random byte */
getlfsr(lfsr,rtail); /* macro gets LFSR byte */
if (notdup[c]) /* not in table already? */
{ table[tlen++] = c; /* append it */
notdup[c] = FALSE; /* indicate it's now in table */
}
if (--randtics == 0) /* detects bogus random generator */
{ /* Must be an LFSR problem, because the bassrand
generator will probably always run OK, so we
won't even check rselect. */
DEBUGprintf1("\007Adjusting weak LFSR. ");
stomplfsr(lfsr); /* hit unruly LFSR upside the head */
randtics=MAXTICS; /* reset countdown counter */
} /* randtics alarm */
} while (tlen<256); /* do until table is full */
if (!rselect)
/* "discard" current contents of lfsr buffer. Causes
steplfsr256 to be called the next time getlfsr is called. */
rtail=0; /* dump some LFSR output, confuse attacker */
rblock(part,notdup); /* deallocate storage */
} /* buildtbl */
/*
** Some notes--
**
** With some sacrifice of performance due to bit packing and unpacking,
** it would be possible to modify the whole BassOmatic algorithm to use
** a smaller block size. This would require using smaller key schedule
** tables with smaller entries. For example, you could use a table of
** 16 4-bit entries instead of 256 8-bit entries. The number of bits in
** each table entry exponentialy determines the number of entries in the
** key schedule table, and those two dimensions together determine the
** size of the plaintext or ciphertext block. The following chart
** summarizes the relationship between table entry width and cipher
** block size.
**
** ENTRY TABLE BLOCK
** WIDTH LENGTH SIZE
** ----- ------ -----
** 8 bits 256 entries 2048 bits, or 256 bytes
** 7 bits 128 entries 896 bits, or 112 bytes
** 6 bits 64 entries 384 bits, or 48 bytes
** 5 bits 32 entries 160 bits, or 20 bytes
** 4 bits 16 entries 64 bits, or 8 bytes
**
**
** Other questions--
** How many of the key bits are actually effective in producing the
** key schedule tables? Are any key bits wasted?
**
** There are 256! permutation tables possible. With 8 tables made
** from a single key, there are (256!)**8 sets of tables possible.
** If there are n bytes in a key (with n<=256), there are 256**n
** keys possible.
**
** In theory, more than one of these keys can produce the same table
** or set of tables, since a different selection of random output
** bytes from the pseudorandom number generator may be discarded to
** produce the same table.
*/
/*
** invert - invert a random permutation table
** Called from bldtbls.
*/
STATIC void invert(register byteptr intable, register byteptr outtable)
{ register byte i;
i = 0; /* byte loop index i = 0,255,254,...2,1 */
do outtable[intable[i]] = i; /* invert table */
while (--i); /* loop 256 times */
} /* invert */
/*
** transpose - transpose input via table to output
** Called from bldtbls.
*/
STATIC void transpose(register byteptr in, register byteptr out, register byteptr table)
/* in and out are the input, output blocks, 256 bytes each.
table contains random permutation of 256 bytes.
*/
{ register byte i;
i = 256; /* byte loop counter */
do *out++ = in[*table++]; /* table transpose */
while (--i); /* loop 256 times */
} /* transpose */
/*
** halfmask(c) - returns TRUE iff 50% of the bits in c are set.
** Called only from getmask.
*/
STATIC boolean halfmask(byte c)
{ byte bitmask,nbits;
nbits=0; bitmask=0x80;
do
{ if (c & bitmask)
nbits++; /* count the # of 1 bits */
bitmask >>= 1;
} while (bitmask);
return(nbits==4); /* are 4 out of 8 bits set? */
} /* halfmask */
/*
** getmask - search table for a suitable random mask byte.
** Finds a random mask byte with 50% of its bits set.
** Called from bldtbls.
*/
STATIC byte getmask(register byteptr table)
/* table contains random permutation of 256 bytes. */
{ byte i;
i = 0; /* byte loop index i = 0,255,254,...2,1 */
do
{ if (halfmask(table[i]))
return(table[i]); /* returns 1st 50% bitmask found */
} while (--i); /* loop 256 times */
return (0x0f); /* never gets here */
} /* getmask */
#define ptrswap(p1,p2) { register byteptr p3; p3=p1; p1=p2; p2=p3; }
/*
** bldtbls - generate all the permutation tables for the BassOmatic
**
** References context variables tlist, shred8ways, bitmasks, and part.
*/
STATIC void bldtbls(boolean hardrand, boolean decryp)
/* hardrand specifies which random number generator to use.
decryp determines whether to invert the tables.
*/
{ byteptr tmp; /* scratchpad table pointers */
byteptr mixer; /* table transposer */
byte i;
tmp = (byteptr) gblock(part); /* allocate new block */
mixer = (byteptr) gblock(part); /* allocate transposer table */
buildtbl(mixer,hardrand);
for (i=0; i<NTABLES; i++) /* for each key schedule table */
{ /* build a random byte permutation vector... */
buildtbl(tmp,hardrand);
if (!shred8ways) /* need bitmasks for 2-way bitshredding */
bitmasks[i] = getmask(tmp);
/* currently, tmp is the table we just built */
transpose(tmp,tlist[i],mixer); /* mix up the table */
/* now tlist[i] is the table we just built */
} /* for each table */
rblock(part,mixer); /* deallocate transposer table */
/* For decryption, it's not safe to invert any tables until they've
all been built, in case hardrand is set. Use separate loop... */
if (decryp) /* decryption uses inverted tables */
for (i=0; i<NTABLES; i++) /* for each table */
{ invert(tlist[i],tmp);
ptrswap(tlist[i],tmp); /* swap/replace block ptrs */
} /* for each table */
rblock(part,tmp); /* deallocate block */
DEBUGprintf1("*");
} /* bldtbls */
/*
** bass_save - saves BassOmatic key context in context structure
*/
void bass_save(KEYCONTEXT *context)
{ int i;
context->initialized = initialized;
for (i=0; i<NTABLES; i++)
context->tlist[i] = tlist[i];
for (i=0; i<NTABLES; i++)
context->bitmasks[i] = bitmasks[i];
context->iv = iv; /* note that iv was passed to initcfb by caller */
context->cfbuncryp = cfbuncryp;
context->uncryp = uncryp;
context->nrounds = nrounds;
context->hardrand = hardrand;
context->shred8ways = shred8ways;
context->rerand = rerand;
context->lfsr = lfsr;
context->rtail = rtail;
} /* bass_save */
/*
** bass_restore - restore BassOmatic key context from context structure
*/
void bass_restore(KEYCONTEXT *context)
{ int i;
initialized = context->initialized;
for (i=0; i<NTABLES; i++)
tlist[i] = context->tlist[i];
for (i=0; i<NTABLES; i++)
bitmasks[i] = context->bitmasks[i];
iv = context->iv; /* note that iv was passed to initcfb by caller */
cfbuncryp = context->cfbuncryp;
uncryp = context->uncryp;
nrounds = context->nrounds;
hardrand = context->hardrand;
shred8ways = context->shred8ways;
rerand = context->rerand;
lfsr = context->lfsr;
rtail = context->rtail;
} /* bass_restore */
/*
** closebass - end the current BassOmatic key context, freeing its buffers
*/
void closebass(void)
{ int i;
if (initialized)
{
/* Close BassOmatic random number generator, in case it's open: */
closebrand();
for (i=0; i<NTABLES; i++)
if (tlist[i]!=nil)
tlist[i] = rblock(part,tlist[i]);
/* Note that iv is not allocated from memory manager,
and thus should not be deallocated */
if (lfsr!=nil)
lfsr = rblock(part,lfsr);
initialized = FALSE;
}
} /* closebass */
static char *copyright_notice(void)
/* force linker to include copyright notice in the executable object image. */
{ return ("(c)1988 Philip Zimmermann"); } /* copyright_notice */
/*
** initkey - Initializes the BassOmatic key schedule tables via key.
**
** References context variables from key context structure, all of them.
**
** Uses several bits from the first byte of the key to select
** how exhaustivly to run the BassOmatic. The key control bits
** specify what tradeoff to make between speed and security.
** These bits in the first byte of the key have these meanings:
** bits 0-2: Number of rounds thru BassOmatic (0-7 means 1-8
** times through). The greater the number, the slower
** it runs.
** bit 3: Set to 1 if we should use slower 8-way bit shredding,
** Set to 0 if we should use faster 50% bitmask shredding.
** bit 4: Set to 1 means use BassOmatic to build its own tables.
** bit 5: Set to 1 iff we should rebuild tables with every block.
** This implicitly disables bit 4, above.
** bits 6-7: Reserved.
**
** Key control bit 4 enables a two-tiered key schedule table
** generation. The first set of tables are generated in the usual
** way with a linear feedback shift register (LFSR). Then, a new
** set of tables is regenerated with a far better pseudo-random
** number generator--namely, the BassOmatic running off the first
** set of tables. The BassOmatic pseudo-random number generator
** feeds its output back into itself to generate a stream of
** random blocks. It is seeded with the same raw key that
** seeded the LFSR. When the new set of tables are built, they
** replace the first set as the working tables.
**
** Key control bit 5 keeps running the pseudorandom number generator
** to continuously rebuild the key schedule tables for each block of text.
** It automatically turns off key control bit 4. Continuously replenishing
** the tables greatly slows down everything, but it improves security
** significantly. This mode unfortunately also makes using the BassOmatic
** in the DES-like cipher block chaining (CBC) and cipher feedback (CFB)
** modes non-self-synchronizing.
*/
int initkey(byteptr key, short keylen, boolean decryp)
/* key is pointer to key buffer, up to 256 bytes long.
keylen is length of key buffer, including key control byte.
decryp is TRUE if decrypting, FALSE if encrypting.
*/
{ byte i;
/* initialize BassOmatic data structures */
static boolean partition_initialized = FALSE;
if (!partition_initialized)
{ /* if already initialized, skip these steps. */
partition_initialized = TRUE;
pcreat2(part,256,NUMBLOX); /* initialize memory partition */
#ifdef DEBUG2
dumpfree(part); /* dump memory free list */
#endif
}
if (key == nil) /* initkey(nil,0,0) only initializes partition */
return(0);
if (keylen < 2)
{ /* key must have control byte and nonzero body length */
fprintf(stderr,"\nError: BassOmatic key too short.\n\007");
return(-1); /* error return */
}
closebass(); /* deallocate any previously allocated buffers */
initialized = TRUE; /* set already initialized flag */
for (i=0; i<NTABLES; i++) /* for each table */
{ /* get memory block from partition */
tlist[i] = (byteptr) gblock(part);
} /* for each table */
nrounds = (*key & 0x07) + 1; /* specifies number of rounds */
shred8ways = ((*key & 0x08) != 0); /* use 8-way bit shredding? */
rerand = ((*key & 0x20) != 0); /* replenish tables with every block */
/* hardrand means use BassOmatic table generator... */
hardrand = ((*key & 0x10) != 0) && !rerand;
uncryp = FALSE; /* initially assume encrypt, in case of hardrand */
#ifdef DEBUG3
if (decryp) /* use inverted tables for decryption */
fprintf(stderr,"Decrypt, ");
else /* use non-inverted tables for encryption */
fprintf(stderr,"Encrypt, ");
fprintf(stderr,"%x rounds, ",nrounds);
if (hardrand) /* BassOmatic random number generator */
fprintf(stderr,"hard ");
else /* LFSR random number generator */
fprintf(stderr,"LFSR ");
if (rerand) /* rebuild tables for every block */
fprintf(stderr,"dynamic ");
else /* keep same tables throughout message */
fprintf(stderr,"static ");
fprintf(stderr,"tables, ");
if (shred8ways)
fprintf(stderr,"8-way bitshred.\n");
else
fprintf(stderr,"2-way bitshred.\n");
#endif /* DEBUG3 */
/* init LFSR random number generator with key seed */
if (lfsr==nil)
lfsr = (byteptr) gblock(part); /* allocate LFSR buffer */
if (keylen > 255) keylen=255;
/* Assume actual key starts after 1st byte, which is control byte */
initlfsr(key+1,keylen-1,lfsr,&rtail);
/* dumpblock(lfsr); */
buildtbl(tlist[0],FALSE); /* build throwaway table to prime the LFSR */
/* generate all the permutation tables for the key schedule */
if (!rerand) /* don't do it now if it's going to be redone anyway */
bldtbls(FALSE,decryp && !hardrand);
/* if hardrand, rebuild tables again, this time with BassOmatic */
if (hardrand) /* rebuild tables with BassOmatic */
{ /* form progressivly better bassrand function. */
/* init BassOmatic pseudo-random generator */
initbrand(key+1,keylen-1); /* skip 1st key byte */
bldtbls(hardrand,decryp);/* generate all the tables again */
closebrand(); /* deallocate scratch buffers for bassrand */
} /* if (hardrand) */
uncryp = decryp; /* specifies BassOmatic decrypt or encrypt */
if (!rerand) /* if we don't need lfsr buffer anymore, then free it. */
lfsr=rblock(part,lfsr); /* sure hope we don't use lfsr again */
/* Do an explicit reference to the copyright notice so that the linker
will be forced to include it in the executable object image... */
copyright_notice(); /* has no real effect at run time */
return(0); /* normal return */
} /* initkey */
/* Now for the primitives called directly from the BassOmatic algorithm...*/
/*
** shred1bit - 8-way random bit shred
**
** Tears each byte into 8 bits, and randomly distributes the bits.
** Uses 8 different permutation vectors from tlist.
** Unfortunately, it always uses the same 8 tables.
*/
STATIC void shred1bit(register byteptr in, register byteptr out)
/* in and out are input, output blocks, 256 bytes each. */
{ register byte bitmask; /* byte has 1 of its bits set */
register bytecounter i;
register byteptr table; /* permutation vector */
byteptr insave; /* for saving input buffer pointer */
byte j;
bitmask = 0x80; /* initialize bitmask at highest bit */
fillbuf(out,256,0); /* make sure output buffer is clean */
/* We could run faster by skipping the fillbuf step, and
using "=" instead of "|=" the first time thru the j loop below. */
insave = in; /* save input buffer pointer */
for (j=0; j<=7; j++) /* for each of 8 bits per byte */
{ i = 256; /* byte loop counter */
table = tlist[j]; /* select a permutation vector */
in = insave; /* recover input buffer pointer */
do /* permute a single bit from each byte */
out[*table++] |= (*in++ & bitmask);
while (--i); /* loop 256 times */
bitmask >>= 1; /* select next bit for isolation */
}
} /* shred1bit */
/*
** shred4bit - 2-way random bit shred
**
** Tears each byte in half, and randomly distributes the halves.
*/
STATIC void shred4bit(register byteptr in, register byteptr out,
register byteptr t1, register byteptr t2, register byte bitmask)
/* in and out are input, output blocks, 256 bytes each.
t1 and t2 each contain random permutation of 256 bytes.
bitmask is byte which has 50% of its bits set.
*/
{ register bytecounter i;
byteptr insave; /* for saving input buffer pointer */
insave = in; /* save input buffer pointer */
i = 256; /* byte loop counter */
do /* isolate half the bits */
out[*t1++] = *in++ & bitmask;
while (--i); /* loop 256 times */
in = insave; /* recover input buffer pointer */
bitmask = ~bitmask; /* invert bitmask for other half */
i = 256; /* byte loop counter */
do /* isolate other half and combine the two halfs */
out[*t2++] |= *in++ & bitmask;
while (--i); /* loop 256 times */
} /* shred4bit */
/*
** multilookup - change input via multiple substitution tables
*/
STATIC void multilookup(register byteptr in, register byteptr out, byte ti)
/* in and out are input, output blocks, 256 bytes each.
ti contains index into starting point of tlist.
*/
{ register byteptr table;
register byte i;
byte j;
j=8;
do
{ table = tlist[ti++ & 7]; /* assumes 8 tables */
i=32;
do *out++ = table[*in++]; /* multi-table substitute */
while (--i); /* loop 32 times */
}
while (--j); /* loop 8 times */
} /* multilookup */
/*
** xortable - change block via xor with random table
**
** This function would serve as its own inverse, if the table is the
** same each time. For use with an inverted table, call ixortable.
** This function inverts 50% of the bits.
*/
STATIC void xortable(register byteptr block, register byteptr table)
/* block is a 256 byte block.
table contains random permutation of 256 bytes.
*/
{ register bytecounter i;
i = 256; /* byte loop counter */
do *block++ ^= *table++; /* table xor */
while (--i); /* loop 256 times */
} /* xortable */
/*
** ixortable - change block via xor with inverted random table
**
** This function inverts 50% of the bits. It is the inverse function
** for xortable, if the table is inverted. Used for decryption.
*/
STATIC void ixortable(register byteptr block, register byteptr table)
/* block is a 256 byte block.
table contains random permutation of 256 bytes.
*/
{ register byte i;
i = 0; /* byte loop index i = 0,255,254,...2,1 */
do block[table[i]] ^= i; /* inverted table xor */
while (--i); /* loop 256 times */
} /* ixortable */
/*
** rake - rake forwards and backwards with xor and add
**
** This is not a keyed operation. It is only useful for increasing
** the intersymbol dependencies between the plaintext and the ciphertext,
** not the key and the ciphertext. Its inverse is function unrake.
*/
STATIC void rake(register byteptr block)
{ register byte i;
register byteptr block1;
block1 = block++;
/* now block1 = 0, block = 1, relatively speaking */
i = 255; /* loop 255 times */
/* first do forward raking with cumulative xor */
do /* from *1++ ^= *0++; thru *255++ ^= *254++; */
*block++ ^= *block1++;
while (--i);
/* now block1 = 255, block = 256 */
i = 255; /* loop 255 times */
/* now do backward raking with cumulative add */
do /* from *(--255) += *(--256); thru *(--1) += *(--2); */
*(--block1) += *(--block);
while (--i);
/* now block1 = 0, block = 1 */
} /* rake */
/*
** unrake - unrake forwards and backwards with subtract and xor
**
** This is the inverse function of rake. Used for decryption.
*/
STATIC void unrake(register byteptr block)
{ register byte i;
register byteptr block1;
block1 = block++;
/* now block1 = 0, block = 1, relatively speaking */
i = 255; /* loop 255 times */
/* first do forward unraking with cumulative subtract */
do /* from *0++ -= *1++; thru *254++ -= *255++; */
*block1++ -= *block++;
while (--i);
/* now block1 = 255, block = 256 */
i = 255; /* loop 255 times */
/* now do backward unraking with cumulative xor */
do /* from *(--256) ^= *(--255); thru *(--2) ^= *(--1); */
*(--block) ^= *(--block1);
while (--i);
/* now block1 = 0, block = 1 */
} /* unrake */
/*
** copy256(dst,src) - copy 256-byte buffer src to dst
*/
void copy256(register byteptr dst, register byteptr src)
{ register bytecounter size;
size = 256; /* loop 256 times */
do *dst++ = *src++; while (--size);
} /* copy256 */
#define f(i,j) (((i)+(j)) & 7) /* used for circular addressing mod 8 */
#define tl(i,j) tlist[f(i,j)] /* assumes 8 tables */
/*
** bassomatic - encipher 1 block with BassOmatic enciphering algorithm
**
** Assumes initkey has already been called.
** References context variables tlist, nrounds, shred8ways,
** bitmasks, uncryp, rerand, and part.
*/
void bassomatic(byteptr in, byteptr out)
/* in and out are input, output blocks, 256 bytes each. */
{ char i; /* signed char */
byteptr tmp;
if (rerand) /* dynamic replenishment of tables? */
bldtbls(FALSE,uncryp);
tmp = (byteptr) gblock(part); /* get memory block */
copy256(out,in); /* copy in to out */
if (uncryp)
{ /* do decryption */
for (i=nrounds-1; i>=0; i--) /* repeat a few rounds */
{ multilookup(out,tmp,f(i,2));
unrake(tmp); /* not effective if last step */
if (shred8ways) /* use 8-way bit shredding */
shred1bit(tmp,out);
else /* use faster 2-way bit shredding */
shred4bit(tmp,out,tl(i,1),tl(i,5),
bitmasks[f(i,3)]);
ixortable(out,tl(i,0)); /* inverts 50% of bits */
} /* for loop */
} /* if decryption */
else /* do encryption */
{ for (i=0; i<nrounds; i++) /* repeat a few rounds */
{ xortable(out,tl(i,0)); /* inverts 50% of bits */
if (shred8ways) /* use 8-way bit shredding */
shred1bit(out,tmp);
else /* use faster 2-way bit shredding */
shred4bit(out,tmp,tl(i,1),tl(i,5),
bitmasks[f(i,3)]);
rake(tmp); /* not effective if last step */
multilookup(tmp,out,f(i,2));
} /* for loop */
} /* else encryption */
rblock(part,tmp); /* release block */
} /* bassomatic */
/*
** xorbuf - change buffer via xor with random mask block
** Used for Cipher Feedback (CFB) or Cipher Block Chaining
** (CBC) modes of encryption.
** Can be applied for any block encryption algorithm,
** such as the DES or the BassOmatic.
*/
STATIC void xorbuf(register byteptr buf, register byteptr mask, register int count)
/* count must be > 0 */
{ do
*buf++ ^= *mask++;
while (--count);
} /* xorbuf */
/*
** cfbshift - shift bytes into IV for CFB input
** Used only for Cipher Feedback (CFB) mode of encryption.
** Can be applied for any block encryption algorithm,
** such as the DES or the BassOmatic.
*/
STATIC void cfbshift(register byteptr iv, register byteptr buf,
register int count, int blocksize)
/* iv is the initialization vector.
buf is the buffer pointer.
count is the number of bytes to shift in...must be > 0.
blocksize is 8 for DES, 256 for BassOmatic.
*/
{ int retained;
retained = blocksize-count; /* number bytes in iv to retain */
/* left-shift retained bytes of IV over by count bytes to make room */
while (retained--)
{ *iv = *(iv+count);
iv++;
}
/* now copy count bytes from buf to shifted tail of IV */
do *iv++ = *buf++;
while (--count);
} /* cfbshift */
#define BLOCKSIZE 256 /* encryption block size for CFB mode. */
/*
** initcfb - Initializes the BassOmatic key schedule tables via key,
** and initializes the Cipher Feedback mode IV.
** References context variables cfbuncryp and iv.
*/
int initcfb(byteptr iv0, byteptr key, short keylen, boolean decryp)
/* iv0 is copied to global iv, buffer will be destroyed by basscfb.
key is pointer to key buffer, up to 256 bytes long.
keylen is length of key buffer.
decryp is TRUE if decrypting, FALSE if encrypting.
*/
{ iv = iv0; /* iv is not allocated from memory manager */
cfbuncryp = decryp;
return (initkey(key,keylen,FALSE));
} /* initcfb */
/*
** basscfb - encipher 1 block with BassOmatic enciphering algorithm,
** using Cipher Feedback (CFB) mode.
**
** Assumes initcfb has already been called.
** References context variables cfbuncryp and iv.
*/
void basscfb(byteptr buf, int count)
/* buf is input, output buffer, may be more than 1 block.
count is byte count of buffer. May be > BLOCKSIZE.
*/
{ int chunksize; /* smaller of count, BLOCKSIZE */
byte temp[BLOCKSIZE];
while ((chunksize = min(count,BLOCKSIZE)) > 0)
{ bassomatic(iv,temp); /* encrypt iv. */
if (cfbuncryp) /* buf is ciphertext */
/* shift in ciphertext to IV... */
cfbshift(iv,buf,chunksize,BLOCKSIZE);
/* convert buf via xor */
xorbuf(buf,temp,chunksize); /* buf now has enciphered output */
if (!cfbuncryp) /* buf was plaintext, is now ciphertext */
/* shift in ciphertext to IV... */
cfbshift(iv,buf,chunksize,BLOCKSIZE);
count -= chunksize;
buf += chunksize;
}
} /* basscfb */