/* nanoka-core.c - Random block cipher - Don Yang (uguu.org) 01/06/05 */ /*@ -mustfreeonly @*/ #include #include #include #include"nanoka-core.h" #ifdef _WIN32 #pragma warning(disable:4127) #endif static int RandomSeed[55], RandomIdx; static int GenerateFeistelNetwork(/*@out@*/Round *r, /*@out@*/int *m, int rounds, int blocksize); static void GenerateRoundFunction(/*@out@*/Func *f, int size); static void InitRandom(FILE *keyfile); static int RandomInt(void); static unsigned int RandomUInt(void); /************************************************************* FreeCipher */ void FreeCipher(/*@only@*/Cipher *c) /*@releases c@*/ { if( c->k_table != NULL ) free(c->k_table); if( c->r != NULL ) free(c->r); if( c->f != NULL ) free(c->f); free(c); } /********************************************************* GenerateCipher */ /*@null@*/Cipher *GenerateCipher(FILE *keyfile) { Cipher *c; int i; if( (c = (Cipher*)calloc(1, sizeof(Cipher))) == NULL ) return NULL; InitRandom(keyfile); c->blocksize = (RandomInt() % (MAX_BLK_SIZE-MIN_BLK_SIZE)) + MIN_BLK_SIZE; c->funcsize = (RandomInt() % (MAX_FUNC_SIZE-MIN_FUNC_SIZE)) + MIN_FUNC_SIZE; if( (c->rounds = c->blocksize) < MAX_ROUNDS ) c->rounds += (RandomInt() % (MAX_ROUNDS - c->rounds)); do { if( (c->r = (Round*)malloc(sizeof(Round) * c->rounds)) == NULL ) break; if( (c->f = (Func*)malloc(sizeof(Func) * c->funcsize)) == NULL ) break; if( GenerateFeistelNetwork( c->r, &(c->iter), c->rounds, c->blocksize) != 0 ) break; if( (c->k_table = (unsigned int*)malloc( c->iter * c->rounds * sizeof(unsigned int))) == NULL ) break; GenerateRoundFunction(c->f, c->funcsize); for(i = 0; i < 32; c->s_table[i++] = RandomUInt()); for(i = 0; i < c->rounds * c->iter; c->k_table[i++] = RandomUInt()); return c; } while(0); /*@i1@*/FreeCipher(c); return NULL; } /************************************************** GenerateFeistelNetwork */ static int GenerateFeistelNetwork( /*@out@*/Round *r, /*@out@*/int *m, int rounds, int blocksize) { int *coverage, i, j, k, t; Round *x; assert(rounds > blocksize); coverage = (int*)calloc((size_t)blocksize, sizeof(int)); if( coverage == NULL ) { *m = 0; return 1; } x = r; /* Random rounds */ for(i = 0; i < rounds - blocksize; i++) { x->in = RandomInt() % blocksize; do { x->out = RandomInt() % blocksize; } while( x->out == x->in ); k = ++coverage[x->out]; coverage[x->out] = coverage[x->in]; coverage[x->in] = k; x++->xor = RandomInt() & 1; } /* Selected rounds to cover missing outputs */ for(j = k = 0; i < rounds; i++) { x->out = k; for(j = 1; j < blocksize; j++) { k = (k + 1) % blocksize; if( coverage[k] < coverage[x->out] ) x->out = k; } do { x->in = RandomInt() % blocksize; } while( x->out == x->in ); t = ++coverage[x->out]; coverage[x->out] = coverage[x->in]; coverage[x->in] = t; x++->xor = RandomInt() & 1; } /* Duplicate network to reach minimum coverage */ k = coverage[0]; for(i = 1; i < blocksize; i++) { if( k > coverage[i] ) k = coverage[i]; } assert(k > 0); if( (*m = MIN_COVERAGE / k) < 2 ) *m = 2; free(coverage); return 0; } /*************************************************** GenerateRoundFunction */ static void GenerateRoundFunction(/*@out@*/Func *f, int size) { Func *x; int i; do { /* Generate function operators and terms */ x = f; for(i = 0; i < size; i++) { x->op = RandomInt() % OPCOUNT; x++->term = RandomInt() & 1; } /* Do it again if terms do not reference data */ x = f; for(i = 0; i < size; i++) { if( x++->term != 0 ) break; } } while( i >= size ); } /************************************************************** InitRandom */ static void InitRandom(FILE *keyfile) { int r, i, j, k; r = 12345 + fgetc(keyfile); for(i = 0; i < 55; RandomSeed[i++] = (r = r * 22695477 + 1)); for(i = 0; (k = fgetc(keyfile)) != EOF; i++) { for(j = 0; j < k; j++) r = r * 22695477 + 1; RandomSeed[i % 55] ^= r + k; } RandomIdx = 0; } /*************************************************************** RandomInt */ static int RandomInt(void) { RandomIdx = (RandomIdx + 1) % 55; return (RandomSeed[RandomIdx] += RandomSeed[(RandomIdx + 24) % 55]) & 0x3fffffff; } /************************************************************** RandomUInt */ static unsigned int RandomUInt(void) { RandomIdx = (RandomIdx + 1) % 55; return (unsigned int)(RandomSeed[RandomIdx] += RandomSeed[(RandomIdx + 24) % 55]); }