#include #include #include #include #include #include #include #include #include #include /* Not required, optimizes x86-64 ASM */ /*#include */ /* * If you make an experimental changes to the code, you want to rename * the program, then change you must the program name everywhere it * appears, both in comments, and in code. Search and replace everything * up * to the period in the filename. Then there is one hardcoded filename * length that needs to be exactly the length of the new filename. * * if (strncmp(line, "testecbs8.c", 11) != 0) { * * That line is the only place you need to change anything other than * search and replace filename. That's in the "read config file" section * of code that goes through the argv CLI arguments. That's assuming you * aren't changing the bitsize of the componenets. If you convert from * 64 bit version to 32 bit version or 16 to 64, or whatever, you have * to adjust the sprintf's and printfs in the logstate and dump functions. * Also, the read state from dump file CLI processing has to be adjusted, * and all the variables pertaining to state and setting state have to * be adjusted. But for just using the same bit size, and adding printfs * or hardcoding values or changing #defines and whatnot, all you have * to change is the name where it appears as described above. * * * To rebuild the helptext do this. Use your new filename if its renamed. * You could just do testecbs8 -h > helptext.txt but there are quoted * strings that will cause syntax errors if not escaped when moving * back to C code. Therefor you need to extract the HELPLINEs text, then * edit, preverving and using backslashed quotes when wanted for output * of the -h option. And then surround each line with quotes, and end * each line with a comma to make it C source code. Then use wc -l to * find the helpline count to update in the source code. I always have * at least two spaces before each line of helptext, even blank lines * in the help output are really two spaces followed by a newline. That * makes iut easy to grep and modify, and easy to read on the screen for * the user. * grep '^" ' testecbs8.c > testecbs8.helptext * Next, I remove all the open double quotes, and the close quote and * comma at EOL. Then edit the document and make it look pretty, * * If you have snip, you can strip off the C syntax in one step, like this * grep '^" ' testecbs8.c | snip "\"" | snip "\",$" > helptext.txt * Otherwise, just use search and delete in vi or do whatever. Then, * edit and make it match reality or whatever you want. * When finished, add the C syntax back like this. * cat helptext.txt | snip "^" "\" " | snip "$" "\"," > helptext.c * Or, just use vi and insert '" ' (doublequote space space), and at * the end of line add '",' (doublequote comma). * Find the number of lines with wc -l helptext.c * Then include it in this file by deleting HELPCOUNT lins below the * helplines declaration and read in the new file. * DONT FORGET TO UPDATE HELPLINECOUNT with the new value. * DONT FORGET TO ESCAPE QUOTEs as needed. */ #define HELPLINECOUNT 347 char *helplines[HELPLINECOUNT] = { " ", " testecbs8 is a Pseudo Random Number Generator, (PRNG).", " By default, testecbs8 will simply print out pseudo random numbers", " to stdout forever. It is meant for testing the algorithm and showing", " that the algorithm can pass statistical tests even with some features", " disabled.", " ", " Usage: testecbs8 -ffilename -d -dd -n[0-9.+BKMGTP] -r[0-9]+ -s[0-9]+ -c[1-4] -l -t -z|Z -E -D -C1n -C2n -T -ss \"string\" filename . . . ", " ", " Command line arguments are optional. There are program control", " arguments, and there are PRNG seed arguments. Anything that starts", " with \"-\" is a control option. Control options are never used for", " seed data. Anything that does NOT start with \"-\" is used as seed", " data.", " ", " The program control options have two varieties that may or may not", " require some numeric argument. The output CLI options are about", " controling output, how many numbers to output, logfile or not,", " dump the state and so on. The configuration options turn off parts", " of the algorithm or set specific values for parts of the state.", " ", " -d ", " -dd dump the state to STDOUT. They first intialize with", " any other CLI options or default, then print the state and exit.", " The single -d omits the LFSR element values. The double -dd", " includes the LFSR elements, and that can be saved to a file", " and used for the -f option to set the state from a file. ", " ", " -l saves the starting state like -dd, to a logfile named", " testecbs8.log, and continues on, outputting pseudo random", " numbers. -l creates a new file named testecbs8.log if it does", " not exist, otherwise it appends to the existing file.", " ", " -E encrypts data read from STDIN and writes to STDOUT.", " No Fiestel structure, just a couple of XORs and intermmediate", " feedback into the LFSR state. ", " ", " -D Decrypts data read from STDIN and writes to STDOUT.", " ", " -ss causes single step output of the state variables for every", " pseudo random number generated. -ss also turns off stdout of the", " binary pseudorandom numbers, only the single step output is seen.", " ", " -T turns off the tapa1 and tapa5 rotates.", " ", " These CLI options require a numeric argument consisting of ascii", " digits specify the value of the parameter you are setting.", " ", " -n specifies how many numbers to output. The digit string can be", " ended with an upper case units specifier, B = bytes, K = kilobytes,", " and so on. These are base 2 units K = 1024, NOT 1000.", " ", " -s sets the LFSR length (size) and turns off resizing. -S allows", " for later resizing but will start with the initially specified", " size.", " ", " ", " -r sets the ressize interval in powers of 2 where the setsize", " function will be called pseudorandomly, approximately once in", " every 2^resetpower output numbers. -R allows the resize function", " to be used even if the -s option is used to set the initial size.", " ", " -e sets the entropyflag which cuases the resize function to add", " entropy in the form of a call to gettime() using CLOCK_MONOTONIC.", " Adding entropy will generate pseudo random numbers that cannot be", " predicted forwards or backwards even given the complete state.", " ", " -f filename, requires a file name which may immediately follow", " or follow whitespace as the next CLI argument, and reads state", " configuration from that file if it's a valid dump file.", " ", " All the above options are used to configure the normal algorithm.", " The ones below, disable some algorithm functions so it can be", " tested with various incomplete implementations in a single program.", " ", " -c specifies the number of counters to REMOVE from the algorithm.", " -c also requires a digit from 1 to 4. 4 disables all counters, 3", " leaves one counter, and it starts from the last counter, so the", " least used counters are removed first.", " ", " -t disables tap swapping. This is just a binary toggle.", " ", " -z sets all state values to 0. This also disables resizing and", " sets the LFSR length to MINVAL+1 which is currently 9. -s can", " be used to set the size to any other value. The upper case", " switches can override the -z option and allow resizing.", " ", " -Z sets all LFSR element values to 0 but randomizes tap positions.", " ", " -S = Allow resizing after starting from specified LFSR length.", " ", " -C1n", " -C2n sets constant1 and constant2 and uses ecbs8const function", " instead of ecbs8. The ecbs8const function is identical to", " ecbs8 except the two formula lines are replaces with constant", " value updates.", " ", " All other CLI provided input is checked for being a readable", " file and if so, opened and read for seed input. If the CLI", " argument is not a valid control option and not a readable file,", " then the ascii values are used as seed data.", " ", " ", " Below is more detailed explanation", " of each CLI option and arguments", " ", " -d = dump the config state (except LFSR elements), to STDOUT", " and exit. Regardless of any other options, dump config", " except the LFSR element values. Use this to see maximum", " and minimum compiled LFSR sizes.", " ", " -dd = Dump the config state plus LFSR state to STDOUT and exit.", " Like -d, this will dump and exit regardless of any other ", " CLI otptions. lower case -dd also prints out every element", " of the LFSR in addition to adders and taps. Redirect this", " output to a file and you can use that file with -f switch", " to set the state to exactly those same values. You can edit", " the file to set whatever numbers you want, just keep the", " same format and make sure the values are in the proper", " range. No negative numbers for example.", " ", " -l = Log initial state in a logfile. This option will log the", " full state of the LFSR, exactly like -dd, but to a logfile", " named testecbs8.log. Sections of the logfile can be used", " as configuration file, but they must be split out into", " separate, standalone files.", " ", " -E = Encrypt data from STDIN. All the algorithm controls will", " still work, and its just toy encryption. But it can be", " used for testing. -E and -D require a file piped through", " the program to encrypt the data from. The user seed is", " not hashed in any way and some of it may be skipped or", " ignored. See the tesetecbs8.readme file for details.", " Encrypt and Decrypt ignore single step and outputlimit.", " ", " -D = Decrypt data from STDIN. All the algorithm controls will", " still work, and its just toy encryption. But it can be", " used for testing.", " ", " -ss = single step output of the state variables for every pseudo", " random number generated. -ss also turns off stdout of the", " binary pseudorandom numbers, so only the single step output", " is seen. Each number generated produces three lines of", " output similar to these for LFSR of size 16 elements.", " ", " 154 36 184 14 RETVAL 246 A", " 153 141 206 107 129 113 110 45 227 133 250 115 118 77 58 12 S", " 6 2 4 7 3 5 8 1 T", " ", " The position of the taps in the T line indicates the LFSR", " element they currently point to. Single step cannot be used ", " with -E or -D", " ", " -T = disable rotates on tapa1 and tapa5. These taps are normally", " rotated the amount specified by shift just before the formula", " that updates them. The shift variable is normally decremented", " and reset when reaching 0. The -T flag disables the shift", " variable by skipping the rotate if shift == 0.", " ", " -f = Read state config from previously dumped data file. The", " file must be exactly the same format as a file created", " using the -dd option. It will include all LFSR values. If a", " file is specified for state initialization, then the setsize", " option \"-s\" can still be used, but will also reset all the", " state data. Edit the file rather tha using CLI option.", " ", " -z = Zero out all LFSR state and set taps to 0-7. This initially", " sets lfsralen to MINLEN+1 but it may be reset by the resize", " function. The -z switch does not affect other program", " control options, it just removes the seed step and starts", " the lfsr with all zero's in the state, except the tap values", " which have to be unique. The tap values are set to elements", " 0 - 7 of the LFSR. Since seeding is skipped, the lfsr", " length is never set, so it defaults to MINLEN-1 unless", " overridden by the -S option. The resize function turns off", " resizing unless the special CLI option -S (upper case) is", " used for the size, OR -R (upper case), is used to set the", " resetpower value. ", " ", " -Z = Zero out LFSR state and counters, but randomizes the taps.", " Otherwise its the same as -z. The uppercase -Z option calls", " the setsize function, but zero's out everything except", " the tap positions.", " ", " -s = Set the lfsrlength. This sets the LFSR length if possible.", " The -s option also turns of resizing completely because", " it makes no sense to set a length and have it randomly", " changed. If no seed bytes are provided, then the size can", " be any value between MINLEN and MAXLEN. But if seed bytes", " are provided, then the ecbs8seed function sets the LFSR", " length to number of seed bytes recieved. The -s switch can", " set the length greater than number of seed bytes recieved,", " if some are also provided. If setsize is used with -f to", " read from a dump file, then resetpower will be set to zero", " if not zero and the resize function will be called. This", " will change the LFSR taps and LFSR element values.", " ", " -S = Allow resizing after starting from specified LFSR length.", " Normally the lower case -s option turns off reszing. The", " upper case option allows for a specified initial LFSR length,", " and resizing thereafter. The -z option also normally turns", " off resizing and sets minimal length. Either -S or -R can", " be used to allow the resize function when it would normally", " be ignored with the lower case switches.", " ", " -r = Set the reset interval. The -r option requires a number", " from 9 to 63 be provided. The number can be a separate", " CLI argument or immediately follow the -r. By default the", " LFSR resets it's size and taps pseudorandomly every 16", " million calls or so. The reset interval is a power of 2,", " from 9 to 63 which is used to set the reset frequency.", " We set the reset value to (2^reset) -1 and if a certain", " state value & reset == 0, then we call the resize function.", " This means, we are calling based on the number of 1 bits", " in a row on the small end of the state value. The reset", " interval is stored as variable resetpower. If resetpower = 0,", " then resetting and resizing the LFSR is completely turned", " off. Otherwise, the value is used to set the AND value to", " that many one bits in a row from small end. Values less than", " 17 can cause extra inefficient CPU usage, because ecbs8()", " might try to call ecbs8setsize) while ecbs8setsize() is", " calling ecbs8(). These calls are ignored. The default", " value is 24. Any value < 9 is treated same as zero and", " turns off resizing altogether.", " ", " -R = Set the resetpower when using -s or -z. The -z option", " normally turns off resizing, even with the -s switch.", " The -s switch normally turns off resizing. Upper case", " R can be used to force the resize function. Either -S", " or -R can be used to force the resize function when it", " would normally be ignored with the lower case switches.", " ", " -e = Add entropy in the ecbs8setsize function. This causes setsize", " to add current seconds and nanoseconds from", " gettime(CLOCK_MONOTONIC, &curtime) system call. The values", " returned are mixed and stored in variables seconds and ns,", " and also the previous values are stored in lastseconds and", " lastns. Those last values are used to update the LFSR elements", " determined by the value of the shift variable. The use of the ", " last values introduces a delay, and adding to LFSR elements", " will also introduce an amount of delay. This output cannot", " be reproduced. The best you can do is start from the same", " initial seed. The delay is intentional but you can simply", " call ecbs8setsize() a second time before obtaining any numbers.", " ", " -t = Turn off tap swapping. This causes the taps to be fixed in", " position, like most other LFSRs where the LFSR is defined", " by the tap values. By default, (without the -t switch), one", " tap is randomly selected to be swpped with its neighbor to", " the right on each call to ecbs8.", " ", " -c = Cripple the adders by removing the last n adders. The", " number n may follow the -c without a space or may be given", " as the following CLI argument. The value ranges from 1 to 4", " inclusive. 0 does not make sense, that would do nothing.", " Adders are removed in order, adder4, adder3, adder2 and adder1.", " They are simply not used anymore.", " 1 is the leaset extreme, 4 removes ALL adders.", " 1 = dont use adder4", " 2 = dont use adder4 adder3", " 3 = dont use adder4 adder3 adder2", " 4 = dont use adder4 adder3 adder2 adder1", " ", " -n = Output exactly n 8 bit numbers. Output bytes will be same", " as n. The -n option requires a number and optionally, a", " Units tag consisting of one of the following letters:", " B = Bytes", " K = Kilobytes", " M = Megabytes", " G = Gigabytes", " T = Terabytes", " P = Petabytes", " The optional Units specifier, must be appended to the last", " digit of the number given. It cannot be a seprate CLI", " argument. This will output exactly that many numbers unless", " overriden by a dump switch, (-d or -dd. Source of seed data", " makes no difference, if numbers will be output, then it will", " be this many, if specified. The outputlimit is ignored when", " using -D and -E.", " ", " -C1n", " -C2n sets constant1 and constant2 repectively where n may", " follow immediately or separated by a space. Defaults", " are constant1 = 170, constant2 = 85. They are always", " used together so if only one is set the other will use", " its default value. When either of these are set from CLI,", " a flag is set that uses a modified ecbs8 PRNG algorithm", " which is identical to the real ecbs8, EXCEPT, instead of", " using the two formula lines, ecbs8const function returns", " a constant value where the formulas would have been. This", " simulates a formula with period length of 1. The real ecbs8", " function does not use constant1 and constant2, they are", " replacements for the formula lines in ecbs8const() only.", " ", " None of the program control options are used as seed data or", " counted as seed bytes used, regardless whether they are used or", " rejected as out of bounds.", " ", " Any other CLI arguments not used to control the program are used", " as seed data, applied byte by byte as recieved into the LFSR state.", " ", " The numbers for -n , -s, -c, -r, -C1, -C2 and the filename", " for -f may follow immediately after the name or number, or", " separated by a space.", " ", " Later CLI arguments may override earlier CLI arugments, as you", " would expect. The -D and -E options cause any -ss or -n to be", " ignored regardless of position in argument list", " ", " If a seed option is a readable file greater then 0 bytes in", " size, then the file is opened and all bytes are read in and", " added to the LFSR state. If the option is a file but its not", " readable or it doesn't exist, then the filename is used as seed", " data and counted as bytes read in. If the file is opened and read,", " then the filename itself is not used as seed data. All CLI seed", " options are tested for being a file that can be opend and read.", " ", " Seed data is added to the counters first, and then the LFSR", " elements in order until finally wrapping back to the counters", " and then LFSR elements again if enough seed data is provided.", " If no seed data is provided and no dump file, then /dev/urandom", " is used to fill in the state. This defaults to MAXLEN-1 initial", " size. If user seed input is provided, then the lfsrlen is first", " set to MAXLEN-1 and setsize is called fill all lfsr elements.", " After this, the adders are updated by ecbs8 and then ecbs8setsize", " is called a second time with user specifiied or determined by", " totalseedchars lfsrlen. This becomes the initial lfsralen.", " By this method, the adders are always randomized with lfsr", " elements and taps.", " ", " The ecbs8setsize function does not alter the adders, only", " the taps and lfara elements. Thats why we update them", " initially here. That could all be in a seed function, but", " you can seed and initialize any way you want. Nobody will", " ever want to use my CLI processing but it doesn't matter", " much, the ecbs8setsize function is really all you need, and", " a few seed bytes in lfsra.", " ", " This is the 8 bit version. The maximum LFSR length can only be", " 127 bytes long. I use MINLEN 8 and MAXLEN 127 for simulating", " the algorithm on something like a 6502 chip. ", " ", " See the readme file, testecbs8.readme for more algorithm", " discussion.", " ", " Last Update: Fri Apr 15 02:10:35 PDT 2022", " ", }; /*#### END char *helplines[HELPLINECOUNT] = { ####*/ /* This is here so you can just grep ^comp and cut and paste to recompile I found out the -lrt is needed for clock_gettime on older Linux. compile gcc -o testecbs8 -Wall -O3 -lrt testecbs8.c */ struct timeval tv; /* Used to print the time for -d and -D output */ /* All these must be powers of 2. MAXLEN must be >= MINLEN * 2. You could use different hardcoded values really, but for ease of debugging I can check these and know that things are fairly normal after all the typo's and off by one errors. These restrictions are just a convenience, all you really need for the algorithm is the data structures and fairly random data. For integrity of the output, I restrict the minimum lfsr length to MINLEN+1 to ensure it is always at least one greater than a power of 2. This will introduce a slight bias towards lfsralen = MINLEN+1 twice as often as any other length. I take steps to counter that bias below. Any length from MINLEN+1 to MAXLEN-1 is valid. MINLEN and MAXLEN are not allowed as lfsralen values. Thats to avoid needing one extra byte for the single largest possible length if MAXLEN were 256 or 65536. The larger the state the longer the period and the longer it takes to diffuse. The shortest state is the fastest diffusion but the period will not be long enough. In the 8 bit version we could use length = 9. But that will be too easy for the cryptographer. So I allow much longer lengths to make the state just that much harder to crack. MAXINP and MAXOUT technically don't have to be powers of 2, but for ease of programming and efficiency, I force the requirement arbitrarily. If you want to change that, you would have to review the code for all power of 2 dependencies, and there are quite a few. My preferred values are #define MAXINP 65536 #define MAXOUT 65536 #define MAXLEN 128 #define MINLEN 32 */ /* This is the 8 bit version */ /* MAXLEN can't be more than 128 because we use unsigned char */ /* values based on these. It's already considered too big anyway. */ #define MAXINP 65536 #define MAXOUT 65536 #define MAXLEN 32 #define MINLEN 8 /* functions */ void ecbs8entropy (void); void ecbs8setsize(unsigned char thenewsize); unsigned char ecbs8 (void); unsigned char ecbs8const (void); void singlestep(unsigned char output); void singlestepinit(void); /* * STATE STORAGE variables. These need file scope * so all functions can see them. These are all used by ecbs8(), so * we want them to be as small as possible to fit into cache. */ unsigned char adder1 = 0; /* These are the counters. */ unsigned char adder2 = 0; unsigned char adder3 = 0; unsigned char adder4 = 0; unsigned char reset = 3; /* number of 8 bit bytes in (2^resetpower)-1 */ unsigned int resetpower = 24; /* Must be 9 - 64 */ unsigned char power = 255; /* remainder bits in last byte */ unsigned char lfsralen = MINLEN+1; /* length to be strictly controlled */ unsigned char shift = 7; /* Must be initialized correctly */ unsigned char maxtap = MINLEN; /* always set to lfsralen - 1 */ unsigned char lfsra[MAXLEN]; /* This is the main state storage */ unsigned char tapa1 = 0; /* Each tap has to be unique. */ unsigned char tapa2 = 1; /* No two taps can have the same value */ unsigned char tapa4 = 2; /* we have to start with known values */ unsigned char tapa3 = 3; /* We use unsigned 8bit integers */ unsigned char tapa5 = 4; /* We could use signed ints too */ unsigned char tapa6 = 5; /* I used unsigned and maxtap for */ unsigned char tapa7 = 6; /* easy to understand code. */ unsigned char tapa8 = 7; /* */ unsigned char taps[MAXLEN]; /* Shuffle tap values in ecbs8setsize(n)*/ struct timespec curtime; /* Get entropy from getttime() */ long ns = 0; /* nanoseconds for adding entropy */ long seconds = 0; /* seconds - poor mans entropy */ long lastns = 0; /* use last results for current update */ long lastseconds = 0; /* gives us a delay in adding endrypy */ int entropyflag = 0;; /* flag to add entropy */ /* Below are for testing seeding, not really part of the algorithm. */ unsigned char sindex = 0; /* index when filling lfsra from CLI */ unsigned char resetflag = 0; /* For use with zeroflag only */ unsigned char constant1 = 170; /* For ecbs8const() function which */ unsigned char constant2 = 85; /* replaces each formula with a constant*/ unsigned int rconstant1 = 0; /* For reading file with fscanf() */ unsigned int rconstant2 = 0; /* For reading file with fscanf() */ unsigned int constantflag = 0; /* Flag to use ecbs8const */ unsigned int resetrestore = 0; /* Temp turn off setsize during init */ /* * All these are just for testing ecbs8. They have nothing to do with * the algorithm. These are global for convenience, so you can put a * logstate() anywhere, and things like that. ecbs8 function is modified * to use these where it needs to be. All the 0 or 1 flags are as you * expect, 0 means off, and 1 means on. I try to avoid things like * if (!done) but sometimes its the easiest and clearest way with * restpect to the surrounding code. */ unsigned int adders[4]; /* For sscanf to read < 8 bit numbers */ int32_t dumpstate (void); /* Dumps full or partial state to STDOUT */ int32_t logstate(void); /* Dumps full state to file testecbs8.log */ unsigned int totalseedchars; /* How much seed data we got in bytes */ unsigned int dump = 0; /* Dump level, 0 is minimal. */ unsigned int logging = 0; /* Default is to never log state */ unsigned int cripple = 0; /* Removes n adders from service */ unsigned int tapswap = 1; /* binary flag to override tap swaps */ unsigned int setsize = 0; /* binary flag and value > 0 is length */ unsigned char zeroflag = 0; /* Tells us to zero out adders and lfsra */ unsigned char encrypt = 0; /* Encrypt data flag, needs to read stdin */ unsigned char decrypt = 0; /* Decrypt data flag, requires stdin */ unsigned char lastchar = 0; /* Needed by encrypt and decrypt */ int tapsint[MAXLEN]; /* Used to read values from dump file */ /* Everything above has to be global file scope for the logstate and dump */ /* functions. */ /***************************************************************************/ int32_t main(int32_t argc, char ** argv) { int32_t i = 0; /* primary loop counter */ int32_t j = 0; /* secondary loop counter */ int32_t readcount = 0; /* bytes read from last input file or CLI string */ unsigned int tmp = 0; /* used to calculate CLI params */ unsigned int tshift = 0; /* used to calculate CLI params */ int32_t done = 0; /* used to indicate final success or failure */ int32_t binaryfileflag = 0; /* Indicates non-ascii data in config file */ char curargv[MAXINP]; /* for reading in CLI arguments */ int32_t curargc = 1; /* The current CLI argument we are working on */ FILE *INP; /* For reading files */ unsigned char seedbuffer[MAXINP]; /* buffer for urandom seed data */ unsigned char outbuffer[MAXOUT]; /* for binay output data */ uint32_t maxbytesok = 0; /* for self test that #defines are valid */ uint32_t maxoutok = 0; /* for self test that #defines are valid */ uint32_t maxlenok = 0; /* for self test that #defines are valid */ uint32_t minlenok = 0; /* for self test that #defines are valid */ char filename[256]; /* for reading in config files, not data */ uint32_t readflag = 0; /* binary flag for read in config file */ char line[1024]; /* used to read in the config file line by line */ char junk1[64]; /* used to ignore junk strings with scanf() */ char junk2[64]; /* used to ignore junk strings with scanf() */ unsigned long long int outputlimit = 0; /* number of numbers to output */ char limitunits = 'B'; /* units to count outputlimit in. B K M G T P */ int singlestepflag = 0; /* Set to 1 calls singelstep state output func. */ /* Quick check to make sure the defined sizes are powers of 2 */ j = 1; for (i=3; i<24; i++) { if (MAXINP == (j<= MINLEN*2 %u\n", MAXLEN, (MINLEN*2)); exit(1); } for (i=0; i 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Cripple requested but level not given, Last CLI.\n"); printf(" Cripple level must be > 0 and < 4\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ( (line[0] < 48) || (line[0] > 57) ) { printf("Error: Cripple requested but level not given.\n"); printf(" Cripple level must be > 0 and < 4\n"); return(0); } } cripple = 0; i = 0; if ((line[0] >= 48) && (line[0] <= 57)) { cripple = line[i]-48; ++i; } if (cripple > 4) { cripple = 4; } if (cripple < 1) { cripple = 0; } ++curargc; continue; } if (strncmp(curargv, "-t", 2) == 0) { tapswap = 0; ++curargc; continue; } if (strncmp(curargv, "-T", 2) == 0) { shift = 0; ++curargc; continue; } if ((strncmp(curargv, "-d", 2) == 0) && (strlen(curargv) == 2)) { dump = 1; ++curargc; continue; } if ((strncmp(curargv, "-dd", 3) == 0) && (strlen(curargv) == 3)) { dump = 2; ++curargc; continue; } if (strncmp(curargv, "-z", 2) == 0) { zeroflag = 1; ++curargc; continue; } if (strncmp(curargv, "-n", 2) == 0) { readcount = strlen(curargv); if (readcount > 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Specified number requested but amount not given.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) && (line[0] > 57)) { printf("Error: Specified number requested but amount not given.\n"); return(0); } } i = 0; outputlimit = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { outputlimit = (outputlimit*10) + (line[i]-48); ++i; } if (line[i] == 0) { limitunits = 'B'; } else { limitunits = line[i]; } switch (limitunits) { case 'K': outputlimit *= 1024LLU; break; case 'M': outputlimit *= 1048576LLU; break; case 'G': outputlimit *= 1073741824LLU; break; case 'T': outputlimit *= 1099511627776LLU; break; case 'P': outputlimit *= 1125899906842624LLU; break; default: break; } limitunits = 'S'; /* this is now used as a flag that says Set. */ ++curargc; continue; } /* Check for reset interval option. */ if ( (strncmp(curargv, "-r", 2) == 0 ) || (strncmp(curargv, "-R", 2) == 0) ) { if ( strncmp(curargv, "-R", 2) == 0 ) { resetflag = 1; } readcount = strlen(curargv); if (readcount > 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Resize power of 2 interval not given. Last CLI\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Resize power of 2 interval not given.\n"); return(0); } } i = 0; resetpower = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { resetpower = (resetpower*10) + (line[i]-48); ++i; } if (resetpower > 63) { resetpower = 0; } if (resetpower < 9) { resetpower = 0; } if (resetpower) { /* reset is the total number of unsigned chars used to store 2^resetpower */ reset = (resetpower)/8; power = resetpower % 8; power = ((1< 2) { memccpy(filename, &curargv[2], 0, 80); } else { /* If the filename was provided with a space after the "-f" then we have to */ /* get the next CLI argument and check that its a valid filename. If we are */ /* already on the last CLI argument then the filename is missing. */ ++curargc; if (curargc > argc) { printf("Error: Config file name not specified for -f CLI option.\n"); return(0); } memccpy(filename, argv[curargc-1], 0, 80); } /* Now we have the filename, or there was an error and we aborted above. */ errno = 0; INP = fopen(filename, "r"); if (errno == 0) { done = 0; /* * We won't be done until the last LFSR value is read in. But if it doesn't * exist for some reason, then we have to use some other way of setting the * done flag. If the input file ends, thats a good check. I could also * add a line counter because if we get millions of lines, thats obviously * wrong. * * If the very first line does NOT start with testecbs8.c then we * know this is not a config file. But we will try to find a clue for * the user before we exit. */ fgets(line, 80, INP); if (strncmp(line, "testecbs8.c", 11) != 0) { i = 0; binaryfileflag = 0; while ((line[i] != ' ') && (line[i] != '\n') && (line[i] != 0) && (i < 40)) { if (line[i] > 126) { binaryfileflag = 1; } ++i; }; line[i] = 0; /* If we get any non-ascii character we know this is not a valid config file */ if (binaryfileflag) { printf(" Error: File \"%s\" is not a config file for testecbs8\nI found gibberish instead of \"testecbs8.c\"\n", filename); } else { /* If it was a text file, show them what we got so they know what went wrong */ printf("Error: File \"%s\" is not a config file for testecbs8\nI found \"%s\" instead of \"testecbs8.c\"\n",filename, line); } return(0); } while ((!done) && (fgets(line, 256, INP))) { if ( (strncmp(line, "#", 1) == 0) || (strncmp(line, " ", 1) == 0) ) { continue; } if (strncmp(line, "constantflag = ", 15) == 0) { sscanf(line, "%s %s %u %s %s %d %s %s %d", junk1, junk2, &constantflag, junk2, junk1, &rconstant1, junk1, junk2, &rconstant2); constant1 = (unsigned char) rconstant1; constant2 = (unsigned char) rconstant2; continue; } if (strncmp(line, "totalseedchars = ", 17) == 0) { sscanf(line, "%s %s %u %s %s %u %s %s %u", junk1, junk2, &totalseedchars, junk2, junk1, &cripple, junk1, junk2, &tapswap); /*fprintf(stderr, "GETOPTS totalseedchars = %u\n", totalseedchars);*/ continue; } if (strncmp(line, "adders = ", 9) == 0) { sscanf(line, "%s %s %d %d %d %d %s %s %d", junk1, junk2, &adders[0], &adders[1], &adders[2], &adders[3], junk1, junk2, &resetpower); adder1 = (unsigned char) adders[0]; adder2 = (unsigned char) adders[1]; adder3 = (unsigned char) adders[2]; adder4 = (unsigned char) adders[3]; /* The adder values don't much matter, as long as they fit in 8 bytes. * But the lfsrlen must be accurate and it must fit within our builtin * #defines for MINLEN and MAXLEN. The tap values should also be checked. * The only thing we can really check is that we are getting 8 bit values. * Since we are reading and storing them into 8 bit chars, they can't be * out of range, but if they are out of range in the file they will be * truncated modulo 2 to 8 bit values so they will fit without error. * Thats why you might want to use -D with the -f flag, to confirm that * it reads the exact same thing it output before. */ /*fprintf(stderr, "GETOPTS reset %d resetpower %d lfsralen %d setsize %d\n", reset, resetpower, lfsralen, setsize);*/ if (resetpower > 63) { resetpower = 0; } if (resetpower < 9) { resetpower = 0; } if (resetpower) { /* reset is the total number of unsigned chars used to store 2^resetpower */ reset = (resetpower)/8; power = resetpower % 8; power = ((1<= MAXLEN)) { printf("Error: Config file \"%s\" LFSR length %d is out of range.\n", filename, lfsralen); printf(" LFSR length must be > %u and < %u\n", MINLEN, MAXLEN); return(0); } for (i=0; i<8; i++) { if (fgets(line, 80, INP) != NULL) { sscanf(line, "%s %s %u", junk1, junk2, &tapsint[i]); } else { printf("Error: Config file \"%s\" Only got %d taps\n", filename, i); printf(" 8 taps are required for ecbs8\n"); return(0); } } for (i=0; i<(8); i++) { taps[i] = (short int) tapsint[i]; } /* ##ec */ for (i=0; i<(8-1); i++) { for (j=i+1; j<8; j++) { if (taps[i] >= lfsralen) { printf("Error: Config file \"%s\" tap %d =%d is > lfsralen %d\n", filename, (i+1), taps[i], lfsralen); printf(" The 8 taps must be unique and < lfsralen\n"); return(0); } if (taps[i] == taps[j]) { printf("Error: Config file \"%s\" tap %d == tap %d = %d\n", filename, (i+1), (j+1), taps[i] ); printf(" The 8 taps must be unique and < lfsralen\n"); return(0); } } } if (taps[7] >= lfsralen) { printf("Error: Config file \"%s\" tap 8 = %d is > lfsralen %d\n", filename, taps[7], lfsralen); printf(" The 8 taps must be unique and < lfsralen\n"); return(0); } tapa1 = (unsigned char) taps[0]; tapa2 = (unsigned char) taps[1]; tapa3 = (unsigned char) taps[2]; tapa4 = (unsigned char) taps[3]; tapa5 = (unsigned char) taps[4]; tapa6 = (unsigned char) taps[5]; tapa7 = (unsigned char) taps[6]; tapa8 = (unsigned char) taps[7]; for (i=0; i 3) { memccpy(line, &curargv[3], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Constant1 requested but value not given last CLI argv.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Constant1 requested but size not given.\n"); return(0); } } i = 0; constant1 = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { constant1 = (constant1*10) + (line[i]-48); ++i; } ++curargc; continue; } if (strncmp(curargv, "-C2", 3) == 0) { constantflag = 1; readcount = strlen(curargv); if (readcount > 3) { memccpy(line, &curargv[3], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Constant2 requested but value not given last CLI argv.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Constant2 requested but size not given.\n"); return(0); } } i = 0; constant2 = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { constant2 = (constant2*10) + (line[i]-48); ++i; } ++curargc; continue; } /* * Here we check for a string of digits to indicate a LFSR length. * But if its already set, or if readflag is set, then we already got * the length from the config file or previous -s. */ if ( ((strncmp(curargv, "-s", 2) == 0) || (strncmp(curargv, "-S", 2) == 0)) && (setsize == 0) ) { /* * First check if resetflag is already set, or if not, is it S or * little s? Little s does NOT set resetflag, and turns off reset. * But big S allows resetpower, and thus reset to be non zero. This * means we need a resetflag to indicate this later on so we know that * setsize calls are allowed. This is to be able to change the default * where setsize turns off resizing. */ if ((strncmp(curargv, "-s", 2) == 0) && (!resetflag)) { reset = 0; power = 0; resetpower = 0; } else { if (strncmp(curargv, "-S", 2) == 0) { resetflag = 1; } } readcount = strlen(curargv); if (readcount > 2) { memccpy(line, &curargv[2], 0, 80); } else { ++curargc; if (curargc > argc) { printf("Error: Specified LFSR size requested but size not given last CLI argv.\n"); return(0); } memccpy(line, argv[curargc-1], 0, 80); if ((line[0] < 48) || (line[0] > 57)) { printf("Error: Specified LFSR size requested but size not given.\n"); return(0); } } i = 0; while ((line[i] >= 48) && (line[i] <= 57) && (line[i] != 0)) { setsize = (setsize*10) + (line[i]-48); ++i; } /* It has to be within our defined range. */ if (setsize <= MINLEN) { setsize = MINLEN+1; } if (setsize >= MAXLEN) { setsize = MAXLEN-1; } ++curargc; continue; } /* * If the readflag is not set then anything that gets down here is not a * program control option so its either CLI seed data or a file to * read in for seed data. */ if (!readflag) { errno = 0; INP = fopen(curargv, "r"); if (errno == 0) { /* If the file is readable, read in a chunk and add it to the LFSR. */ readcount = fread(seedbuffer, 1, (MAXINP), INP); if (readcount > 0) { while (readcount > 0) { /*fprintf(stderr, "readount = %d sindex = %d\n", readcount, sindex);*/ totalseedchars += readcount; for (i=0; i 0) && (!readflag)) { printf("Error: Only got %d seed bytes. I need at least %d bytes.\n", totalseedchars, MINLEN); return(0); } /* printf("DEBUG01 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); dumpstate(); */ /* * Now in this section, if we dont get any seed data and no config file, * then its all strictly the system PRNG to seed the LFSR. */ if ((totalseedchars == 0) && (!readflag)) { readcount = 0; errno = 0; INP = fopen("/dev/urandom", "r"); if (errno == 0) { readcount = fread(lfsra, sizeof(unsigned char), 5, INP); if (readcount != 5) { printf("You should never see this but I couldn't read 5 bytes from dev/urandom.\n"); printf("Exiting on error. Can't read /dev/urandom to get seed values.\n"); exit(0); } else { adder1 = lfsra[0]; adder2 = lfsra[1]; adder3 = lfsra[2]; adder4 = lfsra[3]; lfsralen = lfsra[4]; lfsralen |= (MINLEN+1); lfsralen &= (MAXLEN-1); } readcount = fread(lfsra, sizeof(unsigned char), MAXLEN-1, INP); fclose(INP); if (readcount != (MAXLEN-1)) { printf("You should never see this but I couldn't read 5 bytes from dev/urandom.\n"); printf("Exiting on error. Can't read /dev/urandom to get seed values.\n"); exit(0); } } else { printf("You should never see this but I couldn't open /dev/urandom for reading.\n"); printf("Exiting on error. Can't read /dev/urandom to get seed values.\n"); exit(0); } if (resetpower > 63) { resetpower = 0; } if (resetpower < 9) { resetpower = 0; } if (resetpower) { /* reset is the total number of unsigned chars used to store 2^resetpower */ reset = (resetpower)/8; power = resetpower % 8; power = ((1< MINLEN) && (setsize < MAXLEN)) { if ((!zeroflag) && (!resetflag)) { reset = 0; power = 0; resetpower = 0; } resetrestore = reset; reset = 0; ecbs8setsize(setsize); reset = resetrestore; } else { resetrestore = reset; reset = 0; ecbs8setsize(lfsralen); reset = resetrestore; } } if (readflag) { if ((setsize > MINLEN) && (setsize < MAXLEN)) { if (!resetflag) { reset = 0; power = 0; resetpower = 0; } resetrestore = reset; reset = 0; ecbs8setsize(setsize); reset = resetrestore; } } /* printf("DEBUG02 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); dumpstate(); */ /* * This is where we seed from the user's CLI inputs. There * is nothing but user input used here so this is always * repeatable exacty. Notice that we are starting out with LFSR data * read in from the user seed input, but taps and lfsrlen are still * set to default. NOTE I call it lfsra in case there is an lfsrb or lfsrc. * If no readflag, we are clear to use the input seed data. If readflag is * set, then everything is already initialized. * First thing is check if we have wrapped around the LFSR MAXLEN. * If we have.then the random length selection can be anything, unless * the user specified a length. But if the totalseedchars is less than * MAXLEN-1, and no length is specified, then use the number of seed chars * as the length. This simply provides an easy way to implicitly set the * length. I could set a random length, always smaller than the input count, * but I don't see the point. But, since we can have resetflag, we always * initially call ecbs8setsize with MAXLEN-1. This will cause it to cycle * through the full length, regardless of user selected size. That fills * in the unused lfsra elements with values from the initial seed, * regardless how many bytes are provided. That means if we ever do * call ecbs8setsize, any new elements added will already have some * non initial value. * The user provided all the seed values on CLI. */ /* * If setsize is set, then it doesn't matter if user provided * CLI seed data or it was obtained by /dev/urandom, we just * do this stuff either way. */ if ((setsize > MINLEN) && (setsize < MAXLEN) && (!readflag)) { if ((!resetflag) && (!zeroflag) ) { reset = 0; power = 0; resetpower = 0; } resetrestore = reset; reset = 0; ecbs8setsize(MAXLEN-1); reset = resetrestore; adder1 += ecbs8(); adder2 += ecbs8(); adder3 += ecbs8(); adder4 += ecbs8(); resetrestore = reset; reset = 0; ecbs8setsize(setsize); reset = resetrestore; } else { /* * If setsize is NOT set, then if totalchars > 0, then that means * user provided seed data. If either readflag or zeroflag is set * then just ignore any user seed data. It would get wiped out * by zeroflag anyway, and readflag means we already have everything. */ /* printf("DEBUG03 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); dumpstate(); */ setsize = 0; if ((totalseedchars > 0) && (!readflag) && (!zeroflag)) { if (totalseedchars < (MINLEN+1)) { resetrestore = reset; reset = 0; ecbs8setsize(MAXLEN-1); reset = resetrestore; adder1 += ecbs8(); adder2 += ecbs8(); adder3 += ecbs8(); adder4 += ecbs8(); resetrestore = reset; reset = 0; ecbs8setsize(MINLEN+1); reset = resetrestore; /* printf("DEBUG04 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); dumpstate(); */ } if (totalseedchars >= (MAXLEN-1)) { resetrestore = reset; reset = 0; ecbs8setsize(MAXLEN-1); reset = resetrestore; adder1 += ecbs8(); adder2 += ecbs8(); adder3 += ecbs8(); adder4 += ecbs8(); resetrestore = reset; reset = 0; ecbs8setsize(MAXLEN-1); reset = resetrestore; /* printf("DEBUG05 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); dumpstate(); */ } if ((totalseedchars < (MAXLEN-1)) && (totalseedchars > (MINLEN+1))) { resetrestore = reset; reset = 0; ecbs8setsize(MAXLEN-1); reset = resetrestore; adder1 += ecbs8(); adder2 += ecbs8(); adder3 += ecbs8(); adder4 += ecbs8(); resetrestore = reset; reset = 0; ecbs8setsize(totalseedchars); reset = resetrestore; /* printf("DEBUG06 readflag = %d totalseedchars = %d\n", readflag, totalseedchars); dumpstate(); */ } } } /* Zero out everything except lfsralen and maxtap, and set taps to 0-7. */ if (zeroflag) { if (zeroflag == 1) { tapa1 = 0; tapa2 = 1; tapa3 = 2; tapa4 = 3; tapa5 = 4; tapa6 = 5; tapa7 = 6; tapa8 = 7; } for (i=0; i<(MAXLEN-1); i++) { lfsra[i] = 0; } adder1 = 0; adder2 = 0; adder3 = 0; adder4 = 0; if ((setsize > MINLEN) && (setsize < MAXLEN) && ((zeroflag >1) || (resetflag))) { lfsralen = setsize; } else { lfsralen = (MINLEN+1); } maxtap = lfsralen - 1; if ((!resetflag) || (zeroflag < 1)) { reset = 0; power = 0; resetpower = 0; } } /* * Regardless how we seeded or for what purpose, the entropyflag says * add entropy to make it unpredictable and unrepeatable. This means we * have to call the ecbs8entropy() function at least once, and cycle * lfsralen times to guarantee we start with unpredictable output, * regardless of seed. This randomizes any seed so the output cannot * ever be reproduced. Also, this means ecbs8entropy() must be called * periodically. We just call ecbs8entropyI) every time we call * ecbs8setsize(). Because ecbs8setsize is randomized, entropy calls * are also randomized but get mixed by the ecbs8setsize() which * immediately follows. * NOTE: Since we initialize the seconds and lastseconds and lastns * and ns variables to zero, the first call uses 0 for both values * on the first call. This does nothing. The first call merely populates * the lastseconds and lastns variables which are used for the update * before they themselves are updated. This means we always have to make * two initial calls in order to cause immediate effects. See the * ecbs8.readme file for discussion of the gettime() method. */ if (entropyflag) { ecbs8entropy(); ecbs8entropy(); resetrestore = reset; reset = 0; ecbs8setsize(lfsralen); reset = resetrestore; } /* * Finally we are all done with initialization. Check for dump commands. * If dump == 1, just the adders, length and taps are printed. If > 1, * then the LFSR elements are also dumped. Logstate does the same as * dumpsate except to a logfile. */ if (dump) { if (logging) { logstate(); } dumpstate(); return(0); } /* * The value 3 is used so that I know where it was called from. If I add * logstate commands for testing, I can use different numbers to identify * the calling code. */ dump = 3; if (logging) { logstate(); } /* fprintf(stderr, "INITFINIT reset %d resetpower %d lfsralen %d setsize %d\n", reset, resetpower, lfsralen, setsize); */ /* These are only used for the toy encrypt and decrypt functions. */ unsigned char tmp1 = 0; unsigned char tmp2 = 0; if (constantflag) { if (encrypt) { lastchar = adder3; readcount = fread(seedbuffer, 1, MAXLEN, stdin); while (readcount > 0) { for (i=0; i 0) { for (i=0; i 0) { for (i=0; i 0) { for (i=0; ist_size; if (logfilesize < 1) { printf("Error: problem with file spec logfile\n"); } logfile = fopen(logfilename, "a"); sprintf(line, "%s %s", filename, timestring); fputs(line, logfile); sprintf(line, "MAXINP = %6u ( Input buffer size)\n", MAXINP); fputs(line, logfile); sprintf(line, "MAXOUT = %6u (Output buffer size)\n", MAXOUT); fputs(line, logfile); sprintf(line, "MAXLEN - 1 = %6u (Maximum LFSR size)\n", MAXLEN-1); fputs(line, logfile) ; sprintf(line, "MINLEN + 1 = %6u (Minimum LFSR size)\n", MINLEN+1); fputs(line, logfile); sprintf(line, "constantflag = %u constant1 = %u constant2 = %u\n", constantflag, constant1, constant2); fputs(line, logfile); sprintf(line, "totalseedchars = %u cripple = %u tapswap = %u dump = %u\n", totalseedchars, cripple, tapswap, dump); fputs(line, logfile); sprintf(line, "adders = %d %d %d %d resetpower = %u\n", adder1, adder2, adder3, adder4, resetpower); fputs(line, logfile); if (dump) { sprintf(line, "lfsralen = %d shift = %d\n", lfsralen, shift); fputs(line, logfile); sprintf(line, "tapa1 = %d\n", tapa1); fputs(line, logfile); sprintf(line, "tapa2 = %d\n", tapa2); fputs(line, logfile); sprintf(line, "tapa3 = %d\n", tapa3); fputs(line, logfile); sprintf(line, "tapa4 = %d\n", tapa4); fputs(line, logfile); sprintf(line, "tapa5 = %d\n", tapa5); fputs(line, logfile); sprintf(line, "tapa6 = %d\n", tapa6); fputs(line, logfile); sprintf(line, "tapa7 = %d\n", tapa7); fputs(line, logfile); sprintf(line, "tapa8 = %d\n", tapa8); fputs(line, logfile); } if (dump > 1) { for (i=0; i MINLEN) && (thenewsize < MAXLEN)) { newsize = thenewsize; busy = 1; /* Now we assign the taps array their index values to be shuffled */ for (i=0; i= newsize */ x = 1; while (x <= (newsize)) { x <<= 1; } x -= 1; /* Now swap the tmp taps array for a few cycles */ /* We are still using the previous lfsra and taps and adders */ for (i=0; i<(MAXLEN+lfsralen); i++) { swapa = ecbs8() & x; swapb = ecbs8() & x; while (swapa >= newsize) { swapa = (swapa + ecbs8()) & x; } while (swapb >= newsize) { swapb = (swapb + ecbs8()) & x; } tmp = taps[swapa]; taps[swapa] = taps[swapb]; taps[swapb] = tmp; } /* Still setting things with the values collected above. */ tapa1 = taps[0]; tapa2 = taps[1]; tapa3 = taps[2]; tapa4 = taps[3]; tapa5 = taps[4]; tapa6 = taps[5]; tapa7 = taps[6]; tapa8 = taps[7]; lfsralen = newsize; maxtap = lfsralen - 1; for (i=0; i<(MAXLEN+lfsralen); i++) { swapa = ecbs8() & x; swapb = ecbs8() & x; while (swapa >= newsize) { swapa = (swapa + ecbs8()) & x; } while (swapb >= newsize) { swapb = (swapb + ecbs8()) & x; } tmp = taps[swapa]; taps[swapa] = taps[swapb]; taps[swapb] = tmp; } tapa1 = taps[0]; tapa2 = taps[1]; tapa3 = taps[2]; tapa4 = taps[3]; tapa5 = taps[4]; tapa6 = taps[5]; tapa7 = taps[6]; tapa8 = taps[7]; busy = 0; } /*fprintf(stderr, "SETSIZE RETURNING lfsralen %d\n", lfsralen);*/ } /* END ecbs8setsize */ /* * This is the main PRNG. It requires the adders to work, but even so * may run into short periods. Short is relative. I don't know * how short they might be because I can't find them in a reasonable * time. But I strongly suspect they exist. But regardless, the * adders guarantee minimum 2**32 period because they essentially * amount to stepping into a different cycle each time. So if you * do hit a short cyle, you'll most likely be out of it on the next * call. If not, probably the next one, but in any case, sooner or * later, and thats not more than a few calls at most. * */ /* function implementation */ unsigned char ecbs8 (void) { unsigned char swap; unsigned char tmp; --tapa1; if (tapa1 > maxtap) { tapa1 = maxtap; } --tapa2; if (tapa2 > maxtap) { tapa2 = maxtap; } --tapa3; if (tapa3 > maxtap) { tapa3 = maxtap; } --tapa4; if (tapa4 > maxtap) { tapa4 = maxtap; } --tapa5; if (tapa5 > maxtap) { tapa5 = maxtap; } --tapa6; if (tapa6 > maxtap) { tapa6 = maxtap; } --tapa7; if (tapa7 > maxtap) { tapa7 = maxtap; } --tapa8; if (tapa8 > maxtap) { tapa8 = maxtap; } switch (cripple) { case 0: ++adder1; if (adder1 == 0) { ++adder2; if (adder2 == 0) { ++adder3; if (adder3 == 0) { ++adder4; } } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; lfsra[tapa7] += adder4; break; case 1: ++adder1; if (adder1 == 0) { ++adder2; if (adder3 == 0) { ++adder3; } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; break; case 2: ++adder1; if (adder1 == 0) { ++adder2; } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; break; case 3: ++adder1; lfsra[tapa2] += adder1; break; case 4: break; default: break; } lfsra[tapa1] = ((lfsra[tapa1] ^ (lfsra[tapa2] * (lfsra[tapa3]|1))) + lfsra[tapa4]); if (shift) { --shift; if (shift == 0) { shift = (lfsra[6] & 7); if (shift == 0) { shift = 7; } } lfsra[tapa1] = ((lfsra[tapa1] >> shift) | (lfsra[tapa1] << (8-shift))); } if (tapswap) { swap = (lfsra[tapa2] ^ lfsra[tapa3]) & 7; switch (swap) { case 0: tmp = tapa1; tapa1 = tapa2; tapa2 = tmp; break; case 1: tmp = tapa2; tapa2 = tapa3; tapa3 = tmp; break; case 2: tmp = tapa3; tapa3 = tapa4; tapa4 = tmp; break; case 3: tmp = tapa4; tapa4 = tapa5; tapa5 = tmp; break; case 4: tmp = tapa5; tapa5 = tapa6; tapa6 = tmp; break; case 5: tmp = tapa6; tapa6 = tapa7; tapa7 = tmp; break; case 6: tmp = tapa7; tapa7 = tapa8; tapa8 = tmp; break; case 7: tmp = tapa8; tapa8 = tapa1; tapa1 = tmp; break; default: break; } } lfsra[tapa5] = ((lfsra[tapa5] ^ (lfsra[tapa6] * (lfsra[tapa7]|1))) + lfsra[tapa8]); if (shift) { --shift; if (shift == 0) { shift = (lfsra[1] & 7); if (shift == 0) { shift = 7; } } lfsra[tapa5] = ((lfsra[tapa5] >> shift) | (lfsra[tapa5] << (8-shift))); } /* fprintf(stderr, "reset = %d restpower = %d power = %d lfsralen = %d lfsra[tapa1] %d lfsra[tapa2] = %d \n", reset, resetpower, power, lfsralen, lfsra[tapa1], lfsra[tapa2] ); */ if (reset) { switch (reset) { case 1 : if ((lfsra[tapa1] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 2 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 3 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 4 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 5 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 6 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && (lfsra[tapa6] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 7 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && (lfsra[tapa6] == 255) && (lfsra[tapa7] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = ((adder1+adder2+adder3+adder4) + MINLEN + 1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 8 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && (lfsra[tapa6] == 255) && (lfsra[tapa7] == 255) && (lfsra[tapa8] == 255) && ((adder1 & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = ((adder1+adder2+adder3+adder4) + MINLEN + 1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; default : break; } } return(lfsra[tapa1] ^ lfsra[tapa5]); } /* END ecbs8 */ /* function implementation */ unsigned char ecbs8const (void) { unsigned char swap; unsigned char tmp; --tapa1; if (tapa1 > maxtap) { tapa1 = maxtap; } --tapa2; if (tapa2 > maxtap) { tapa2 = maxtap; } --tapa3; if (tapa3 > maxtap) { tapa3 = maxtap; } --tapa4; if (tapa4 > maxtap) { tapa4 = maxtap; } --tapa5; if (tapa5 > maxtap) { tapa5 = maxtap; } --tapa6; if (tapa6 > maxtap) { tapa6 = maxtap; } --tapa7; if (tapa7 > maxtap) { tapa7 = maxtap; } --tapa8; if (tapa8 > maxtap) { tapa8 = maxtap; } switch (cripple) { case 0: ++adder1; if (adder1 == 0) { ++adder2; if (adder2 == 0) { ++adder3; if (adder3 == 0) { ++adder4; } } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; lfsra[tapa7] += adder4; break; case 1: ++adder1; if (adder1 == 0) { ++adder2; if (adder3 == 0) { ++adder3; } } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; lfsra[tapa6] += adder3; break; case 2: ++adder1; if (adder1 == 0) { ++adder2; } lfsra[tapa2] += adder1; lfsra[tapa3] += adder2; break; case 3: ++adder1; lfsra[tapa2] += adder1; break; case 4: break; default: break; } lfsra[tapa1] += constant1; if (shift) { --shift; if (shift == 0) { shift = 7; } lfsra[tapa1] = ((lfsra[tapa1] >> shift) | (lfsra[tapa1] << (8-shift))); } if (tapswap) { swap = (lfsra[tapa2] ^ lfsra[tapa3]) & 7; switch (swap) { case 0: tmp = tapa1; tapa1 = tapa2; tapa2 = tmp; break; case 1: tmp = tapa2; tapa2 = tapa3; tapa3 = tmp; break; case 2: tmp = tapa3; tapa3 = tapa4; tapa4 = tmp; break; case 3: tmp = tapa4; tapa4 = tapa5; tapa5 = tmp; break; case 4: tmp = tapa5; tapa5 = tapa6; tapa6 = tmp; break; case 5: tmp = tapa6; tapa6 = tapa7; tapa7 = tmp; break; case 6: tmp = tapa7; tapa7 = tapa8; tapa8 = tmp; break; case 7: tmp = tapa8; tapa8 = tapa1; tapa1 = tmp; break; default: break; } } lfsra[tapa5] += constant2; if (shift) { --shift; if (shift == 0) { shift = 7; } lfsra[tapa5] = ((lfsra[tapa5] >> shift) | (lfsra[tapa5] << (8-shift))); } /* fprintf(stderr, "reset = %d restpower = %d power = %d lfsralen = %d lfsra[tapa1] %d lfsra[tapa2] = %d \n", reset, resetpower, power, lfsralen, lfsra[tapa1], lfsra[tapa2] ); */ if (reset) { switch (reset) { case 1 : if ((lfsra[tapa1] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 2 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 3 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 4 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 5 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 6 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && (lfsra[tapa6] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = (lfsra[tapa8] + MINLEN + 1) & (MAXLEN-1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 7 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && (lfsra[tapa6] == 255) && (lfsra[tapa7] == 255) && ((lfsra[tapa2] & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = ((adder1+adder2+adder3+adder4) + MINLEN + 1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; case 8 : if ((lfsra[tapa1] == 255) && (lfsra[tapa2] == 255) && (lfsra[tapa3] == 255) && (lfsra[tapa4] == 255) && (lfsra[tapa5] == 255) && (lfsra[tapa6] == 255) && (lfsra[tapa7] == 255) && (lfsra[tapa8] == 255) && ((adder1 & power) == power) ) { if (entropyflag) { ecbs8entropy(); } setsize = ((adder1+adder2+adder3+adder4) + MINLEN + 1); setsize |= (MAXLEN/2); ecbs8setsize(setsize); } break; default : break; } } return(lfsra[tapa1] ^ lfsra[tapa5]); } /* END ecbs8const */ void singlestepinit(void) { int pflag = 0; int j; fprintf(stdout, " %3d %3d %3d %3d RETVAL INIT A\n", adder1, adder2, adder3, adder4); for (j=0; j