[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: IPG algorithim





I have translated the IPG algorithim's "engine" to C, to generate
some random values from it for testing purposes.  It does not
look very random in either the xnoisesph program or the DIEHARD
test battery.   However I may well have misinterprested Mr. Wood's
description (his writing is, as Mr. Chudov points out, difficult to
understand) or written my code incorrectly.  Here it is, play
with it yourself.  To my untrained eye the lack of randomness
in what's essentially a stream cipher would be disturbing.
However I am not a cryptoanalysist so I do not know to
what extent this weakens the cipher.


The IPG description does not say (but implies to me) that
the various tables that are to be filled in by "random" values must
be filled in by PRNGs that are seeded with the same seeds by
each of the party that knows the key.  Otherwise the "encryptor
streams" that are generated will be unrelated and decryption will not
be possible.  To make my test work I have used the simple rand()
function to fill in the tables.


Corrections are welcome.



#include <stdio.h>

/* a C translation of the IPG "EUREKA" algorithim's "engine".
** This is supposed to produce random numbers for the IPG
** "encryptor stream".
** See http://www.netprivacy.com/ for the original description.
** Eric Murray  [email protected]  This code placed under GNU copyleft.  */

/* machine-dependent stuff, change to suit different platforms: */
typedef unsigned char byte;
typedef unsigned short uint16;


/* tables: */
uint16 A[53];
uint16 B[53];
uint16 C[53];


int init_table(uint16*table, uint16 min, uint16 max)
{
	/* IPG specifies no algorithim for producing the "random"
	** initial values in the ABC tables, but it's obvious that
	** it requires a PRNG that's somehow seeded from the "key".
	** I've just used rand() here.  In UNIX rand() called with no
	** seed is supposed to seed itself with 0. */
	int i;
	int count, r;

	for(i = 0; i < 53; i++) {
		table[i] = min + (rand() % (max - min));
	}
}

main(int argc, char **argv)
{
	uint16 jv;
	int argcnt, i, n, count, diehard, nelem;

	diehard = 0;
	argcnt = 1;
	if (argc >= 2) {
		if (strncmp(argv[argcnt],"-d") == 0) {
			diehard++;
			argcnt++;
		}
	}
	if (argc > argcnt - 1 ) {
		n = atoi(argv[argcnt]);
		fprintf(stderr,"Generating %d values\n",n);
	}
	else {
		n = 2000;
	}

	/* seed tables: */
	fprintf(stderr,"Seeding:  A");  fflush(stderr);
	init_table(A,0,65535);
	fprintf(stderr," B");  fflush(stderr);
	init_table(B,0,12227);
	fprintf(stderr," C");  fflush(stderr);
	init_table(C,16384,20361);
	fprintf(stderr,"\n");  fflush(stderr);

	/* generate n values: */
	for(; n > 0; n--) {
		/* jv is "random" (where's it seeded from?) */
		jv = (uint16)(rand() % 53);

		/* count limits the number of traverses to 53^2 so we don't get stuck */
		for(count = 0; count < 2809; count++) {
			jv++;
			if (jv == 53) jv = 0;
			A[jv] = (A[jv] + B[jv]) % C[jv];
			if (A[jv] < 16384) break;
		}
		if (count == 2809) fprintf(stderr,"Oops.\n");
		else {
			if (!diehard) {
				printf("%d\n",A[jv]);
			}
			else {
				/* print output in DIEHARD required format:
				** actually since we have 16-bit ints and DIEHARD
				** wants 32-bit ints, we print 20 per line instead of 10 */
				if (nelem++ > 19) {printf("\n"); nelem = 0;}
				printf("%4.4x",(unsigned int)A[jv]);
			}
		}
	}
}



-- 
Eric Murray  [email protected]  [email protected]  http://www.lne.com/ericm
PGP keyid:E03F65E5 fingerprint:50 B0 A2 4C 7D 86 FC 03  92 E8 AC E6 7E 27 29 AF