Tom7-ecrypt stream cipher
This is a stream cipher using a 256 byte array, which
is operated on by an (imaginary) processor using it as both code and
data. This is a very appropriate scheme to be implemented in hardware.
A counter steps through the 256 bytes and the value is xor'd with
the plaintext to produce the ciphertext. Between each byte, 127 iterations
of the evolve() function are run on the array.
The evolve function (which probably makes much more sense in source
code form; see below) uses another separate instruction pointer ip
pointing somewhere in the array. It calculates a value size equal
to 1 plus the lowest 3 bits of the byte at ip. The most significant
bit selects between two operations plus (0) and xor (1), and
the second most significant sets whether a binary complement will be
performed or not.
Then, the operator combines size bytes pointed to by the byte
at ip+1 with the bytes following it one at a time, using the
operator determined above. The bytes pointed to are replaced, and
ip is moved to the byte after the last byte used in this
operation (ip+size+1).
All values wrap around, and the array is initialized through the key,
in the manner of RC4. This makes a maximum key length of 2048 bits.
Using my program stat, this produces
well-distributed pseudo random bits for a variety of keys. This is by no
means a thorough test, but it performs as expected, at least.
Unlike RC4, the array does not remain a permutation of the bytes
0-255. This means that its distribution and contents are less predictable,
which is good and bad. Good because there are 2^(256*8) * 256^2
(about 2.12 x 10^621) states that the device can be in, but bad because
the device is not guaranteed to remain well-distributed and random. For
instance, an array of all zeros will remain an array of all zeros, though
this arrangement seems extremely unlikely. Plus and Xor should retain
a good distribution of bits, and the complementation helps to keep it
from snowballing in either direction. Through six hundred billion evolve()'s
on all the keys I tried, the ratio of 1's to 0's showed no significant
change from 1:1.
The first byte is always used for the first xor. If the initialization
of the array is not secure (and I suspect it isn't really) then a
chosen- or known-plaintext attack could reveal information about the
key.
The evolve function does not use all the bits of the byte used to pick
the operator and size. It would probably improve things to have it use
the three bits in the middle that it doesn't use. (Direction flag?)
This implementation acts as a filter -- it will work fine under unix
but MS-DOS does not handle binary pipes very well, so it will drop
characters (nulls, I think). In MS-DOS you'll need to set source and
dest to actual files.
or
Here is an implementation in C.
/* C Implementation of Tom7-ecrypt stream cipher as a filter. 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. Tom 7 http://tom7.org/ */ #include <stdio.h> #define uchar unsigned char #define s(a,b,c) m=a[(b)];a[(b)]=a[(c)];a[(c)]=m; void evolve(uchar*box); void printbox(uchar*box); int iter=-1; int main (int argc, char ** argv) { int z,x,c,m; uchar box[256], K[256],j=0,IP=0; FILE * source = stdin, * dest = stdout; /* source = fopen("test.in","rb+"); dest = fopen("test.out","wb+"); */ if (argc != 2) { printf("%s key\n", argv[0]); exit(-1); } z = strlen(argv[1]); for (x=0;x<256;x++) K[box[x]=x]=argv[1][x%z]; for (x=0;x<256;x++) { j+=box[x]+K[x]; s(box,x,j); } while (EOF != (c=fgetc(source))) { fputc(c ^ box[IP++],dest); x=127; while (x--) evolve(box); } if (source != stdin ) fclose(source); if (dest != stdout) fclose(dest); return 0; } #define BOX(c) box[(c)&255] int ip; void evolve(uchar*box) { int size,x; ip &= 255; size = 1 + (box[ip]&7); switch (box[ip] >>6) { case 0: for (x=0;x<size;x++) BOX(BOX(ip)+x) += BOX(ip+x); break; case 1: for (x=0;x<size;x++) BOX(BOX(ip)+x) += ~BOX(ip+x); break; case 2: for (x=0;x<size;x++) BOX(BOX(ip)+x) ^= BOX(ip+x); break; case 3: for (x=0;x<size;x++) BOX(BOX(ip)+x) ^= ~BOX(ip+x); break; } ip+=size+1; } Back to Tom's Cryptography Thingie.
5 June 1998 |