Tom7-byteselect stream cipher
This is a method of combining inline generators of any sort
(in the code below I use LFSR skipstate generators) in a way which increases
the complexity of the system.
The idea is to use eight inline generators to select a byte from a
key-dependent permutation of bytes. The output is used as the input to
the generators in the next round, and a 8-bit wraparound counter is also
xor'd with the output of the generators before entering the p-box.
Because the 8-bit counter ensures that the output from the generators
can select any byte, even if it remains constant, the generators can
have rather weak random properties without severely compromising the
device's effectiveness (ie, sending it into a short cycle). Clocked
LFSR's probably would not be too devastating.
Of course, it makes more sense to use proper generators. In the
implementation below I've used LFSR skipstate generators; anything else with
good random properties is candidate, and the generators do not have
to all be the same type (combining types, in fact, is a very sound idea).
The code below initializes the p-box in the same manner as RC4, and
initializes the generators as in Tom7-fselect.
Using my program stat, this produces
well-distributed pseudo random bits for a variety of keys (up to degree
7). This is by no means a thorough test, but it performs as expected,
at least.
The biggest weakness I see in this is that the P-Box does not change.
This seems to make a known-plaintext pretty reasonable.
The P-Box does not change. I tried to think of an elegant way to make
it change without totally ripping off RC4, but failed. It would greatly
increase security to have the P-Box change. Since the P-Box must change
by the key in this implementation anyway, this should not make hardware
implementations much more difficult or expensive.
The code below uses generators with periods which are not all
relatively prime. I highly recommend using generators which are; my source
of data Applied Cryptography did not have enough.
LFSRs are considered insecure and probably should not be used.
This implementation just spits out the bits in ascii notation as my other programs do, something like: while (EOF != (a=getc(stdin))) { ... get output byte ... putchar(a ^ output); } Would be a more appropriate main loop for a filter interface (note that DOS will not handle binary redirection well, but this will work under unix). /* C Implementation of Tom7-byteselect generator (using skipstate LFSRs). This code is distributed under the GNU public license; see http://www.gnu.org/copyleft/gpl.html. I can't make any claims about the security of this algorithm because I am not a trained cryptographer, though it produces (as far as I can tell) statistically random output. This code should be thought about, but not used unless you know more about this than me. If you implement this, use generators which have lengths that are relatively prime, and combine different types of generators. Tom 7 http://tom7.org/ */ #include <stdio.h> #include <stdlib.h> #define INPUT_SKIPSTATE 1 #define s(a,b,c) m=a[(b)];a[(b)]=a[(c)];a[(c)]=m; // swap bytes b and c in array a typedef struct { unsigned long data; unsigned long mask; unsigned char len; unsigned char inputs; } LFSR; unsigned char generator(LFSR * g); unsigned char skipstate_generator(LFSR * g); LFSR G[8] = { {0,(1<<31)|(1<<6)|(1<<4)|(1<<2)|(1<<1)|1,31,0}, {0,(1<<29)|(1<<5)|(1<<3)|1,29,0}, {0,(1<<30)|(1<<12),30,0}, {0,(1<<18)|(1<<4)|(1<<1)|1,18,0}, {0,(1<<16)|(1<<4),16,0}, {0,(1<<12)|(1<<3)|(1<<2)|1,12,0}, {0,(1<<31)|(1<<6)|(1<<2)|(1<<1)|1,31,0}, {0,(1<<22)|(1<<4),22,0} }; int main (int argc, char**argv) { int x,z,c,a,m,s; unsigned char output=0,counter=0; unsigned char P[256],K[256],j; char * key = argv[1]; if (argc < 2) { printf("%s key\n", argv[0]); exit(-1); } s = strlen(key); for (x=c=0;x<8;x++) { G[x].data |= key[c++%s] << 24; G[x].data |= key[c++%s] << 16; G[x].data |= key[c++%s] << 8 ; G[x].data |= key[c++%s] ; a = key[c++%s]; while (a--) generator(&G[x]); } for (x=0;x<256;x++) K[P[x]=x]=key[x%s]; for (x=j=0;x<256;x++) { j+=P[x]+K[x]; s(P,x,j); } /* Filled LFSR's, P-Box with key-dependent material */ if (argc>2) z = atoi(argv[2]); else z=1000; while (z--) { for (x=0;x<8;x++) G[x].inputs = (output>>x)&1; output = counter++; for (x=0;x<8;x++) output ^= skipstate_generator(&G[x])<<x; output = P[output]; for (x=0;x<8;x++) putchar('0' + ((output>>x)&1)); } return 0; } unsigned char skipstate_generator(LFSR * g) { if (g->inputs & INPUT_SKIPSTATE) generator(g); g->inputs &= ~INPUT_SKIPSTATE; return generator(g); } unsigned char generator(LFSR * g) { if (!g->data) g->data--; /* LFSR cannot hold 0, or it will cycle */ if (g->data & 1) { g->data = ((g->data ^ g->mask) >> 1) | (1<<g->len); /* g->len is already len-1 */ return 1; } else { g->data>>=1; return 0; } } Back to Tom's Cryptography Thingie.
|