| /* |
| These are the Random Number Generator tests suggested by the |
| FIPS 140-1 spec section 4.11.1 (http://csrc.nist.gov/fips/fips1401.htm) |
| The Monobit, Poker, Runs, and Long Runs tests are implemented below. |
| */ |
| #define RNG_DEVICE "/dev/hwrandom" |
| #define RNG_LOOPS 25 |
| |
| |
| #include <stdio.h> |
| |
| FILE *dev; |
| |
| char read_rng_byte() { |
| char random; |
| fscanf(dev,"%c",&random); |
| return random; |
| } |
| |
| int do_test() { |
| |
| unsigned char rbyte = 0; |
| int poker[16],runs[12],i,j; |
| double pokertest; |
| int longrun = 0; |
| int current = 0; |
| int rlength = 0; |
| int ones = 0; |
| |
| for(i=0; i<16; i++) { |
| poker[i] = 0; |
| } |
| |
| for(i=0; i<12; i++) { |
| runs[i] = 0; |
| } |
| |
| rlength = 999; |
| ones = 0; |
| for(i=0; i<2500; i++) { |
| rbyte = read_rng_byte(); |
| |
| // printf("%d: %x\n",i,rbyte); |
| |
| ones += rbyte & 1; |
| ones += (rbyte & 2)>>1; |
| ones += (rbyte & 4)>>2; |
| ones += (rbyte & 8)>>3; |
| ones += (rbyte & 16)>>4; |
| ones += (rbyte & 32)>>5; |
| ones += (rbyte & 64)>>6; |
| ones += (rbyte & 128)>>7; |
| |
| poker[rbyte>>4] += 1; |
| poker[rbyte & 15] += 1; |
| |
| /* Trick to make sure current != the first bit so we don't screw |
| up the first runlength */ |
| if(rlength == 999) { |
| current = !((rbyte & 128)>>7); |
| rlength = 1; |
| } |
| for(j=7; j>=0; j--) { |
| // printf("%d %d %d\n",rlength,current,((rbyte & 1<<j)>>j) ); |
| if(((rbyte & 1<<j)>>j) == current) { |
| rlength++; |
| |
| } |
| else { |
| /* If runlength is 1-6 count it in correct bucket. 0's go in |
| runs[0-5] 1's go in runs[6-11] hence the 6*current below */ |
| if(rlength < 6) { |
| runs[rlength - 1 + (6*current)]++; |
| } |
| if(rlength >= 6) { |
| runs[5 + (6*current)]++; |
| } |
| /* Check if we just failed longrun test */ |
| if(rlength > longrun) { |
| longrun = rlength; |
| } |
| rlength=1; |
| /* flip the current run type */ |
| current = (rbyte & 1<<j)>>j; |
| } |
| } |
| } |
| |
| /* add in the last (possibly incomplete) run */ |
| if(rlength <= 6) { |
| runs[rlength - 1 + (6*current)]++; |
| } |
| if(rlength > longrun) { |
| longrun = rlength; |
| } |
| |
| /* To poker test */ |
| pokertest = 0; |
| for(i=0; i<16; i++) { |
| // printf("P%d: %d\n",i,poker[i]); |
| pokertest += (double)(poker[i] * poker[i]); |
| } |
| pokertest = (16.0/5000.0) * pokertest - 5000.0; |
| |
| /* Data is all gathered, do the tests */ |
| printf("Ones: %d\nPokertest: %f\nRuns: %d %d %d %d %d %d\n %d %d %d %d %d %d\nLong Run: %d\n\n",ones,(float)pokertest,runs[0],runs[1],runs[2],runs[3],runs[4],runs[5],runs[6],runs[7],runs[8],runs[9],runs[10],runs[11],longrun); |
| |
| |
| if(! ((ones < 10346) && (ones > 9654)) ){ |
| printf(" RNG failed Monobit test.\n"); |
| return 1; |
| } |
| |
| if(! ((pokertest < 57.4) && (pokertest > 1.03)) ){ |
| printf(" RNG failed Poker test.\n"); |
| return 1; |
| } |
| |
| if(! ((runs[0] >= 2267) && (runs[0] <= 2733) && |
| (runs[1] >= 1079) && (runs[1] <= 1421) && |
| (runs[2] >= 502) && (runs[2] <= 748) && |
| (runs[3] >= 223) && (runs[3] <= 402) && |
| (runs[4] >= 90) && (runs[4] <= 223) && |
| (runs[5] >= 90) && (runs[5] <= 223) && |
| (runs[6] >= 2267) && (runs[6] <= 2733) && |
| (runs[7] >= 1079) && (runs[7] <= 1421) && |
| (runs[8] >= 502) && (runs[8] <= 748) && |
| (runs[9] >= 223) && (runs[9] <= 402) && |
| (runs[10] >= 90) && (runs[10] <= 223) && |
| (runs[11] >= 90) && (runs[11] <= 223)) ) { |
| printf(" RNG failed Runs test.\n"); |
| return 1; |
| } |
| |
| if(longrun >= 34) { |
| printf(" RNG failed LongRun test.\n"); |
| return 1; |
| } |
| |
| return 0; |
| } |
| |
| int main(int argv,char **argc) { |
| unsigned char random; |
| int i=0; |
| |
| if(! (dev = fopen(RNG_DEVICE,"r"))) { |
| printf("Open of "RNG_DEVICE" failed\n"); |
| exit(1); |
| } |
| |
| for(i=0; i<RNG_LOOPS; i++){ |
| printf("Test: %d\n",(i+1)); |
| if(do_test()) { |
| printf("Failed on test %d\n",i); |
| } |
| } |
| printf("RNG correctly completed %d FIPS tests.\n",i); |
| return 0; |
| } |