--- pgp/src/idea.c 2018/04/24 16:38:49 1.1.1.2 +++ pgp/src/idea.c 2018/04/24 16:42:32 1.1.1.5 @@ -1,4 +1,5 @@ -/* idea.c - C source code for IDEA block cipher. +/* + * idea.c - C source code for IDEA block cipher. * IDEA (International Data Encryption Algorithm), formerly known as * IPES (Improved Proposed Encryption Standard). * Algorithm developed by Xuejia Lai and James L. Massey, of ETH Zurich. @@ -7,12 +8,12 @@ * Zero-based indexing added, names changed from IPES to IDEA. * CFB functions added. Random number routines added. * - * Optimized for speed 21 Oct 92 by Colin Plumb + * Extensively optimized and restructured by Colin Plumb. * * There are two adjustments that can be made to this code to * speed it up. Defaults may be used for PCs. Only the -DIDEA32 - * pays off significantly if selectively set or not set. - * Experiment to see what works better for you. + * pays off significantly if selectively set or not set. + * Experiment to see what works best for your machine. * * Multiplication: default is inline, -DAVOID_JUMPS uses a * different version that does not do any conditional @@ -26,13 +27,14 @@ * necessary. On a SPARC, for example, this boosts * performace by 30%. * - * The IDEA(tm) block cipher is covered by a patent held by ETH and a + * The IDEA(tm) block cipher is covered by patents held by ETH and a * Swiss company called Ascom-Tech AG. The Swiss patent number is - * PCT/CH91/00117. International patents are pending. IDEA(tm) is a - * trademark of Ascom-Tech AG. There is no license fee required for - * noncommercial use. Commercial users may obtain licensing details - * from Dieter Profos, Ascom Tech AG, Solothurn Lab, Postfach 151, 4502 - * Solothurn, Switzerland, Tel +41 65 242885, Fax +41 65 235761. + * PCT/CH91/00117, the European patent number is EP 0 482 154 B1, and + * the U.S. patent number is US005214703. IDEA(tm) is a trademark of + * Ascom-Tech AG. There is no license fee required for noncommercial + * use. Commercial users may obtain licensing details from Dieter + * Profos, Ascom Tech AG, Solothurn Lab, Postfach 151, 4502 Solothurn, + * Switzerland, Tel +41 65 242885, Fax +41 65 235761. * * The IDEA block cipher uses a 64-bit block size, and a 128-bit key * size. It breaks the 64-bit cipher block into four 16-bit words @@ -40,30 +42,20 @@ * arithmetic. It likewise breaks the 128-bit cipher key into eight * 16-bit words. * - * For further information on the IDEA cipher, see these papers: - * 1) Xuejia Lai, "Detailed Description and a Software Implementation of - * the IPES Cipher", Institute for Signal and Information - * Processing, ETH-Zentrum, Zurich, Switzerland, 1991 - * 2) Xuejia Lai, James L. Massey, Sean Murphy, "Markov Ciphers and - * Differential Cryptanalysis", Advances in Cryptology- EUROCRYPT'91 + * For further information on the IDEA cipher, see the book: + * Xuejia Lai, "On the Design and Security of Block Ciphers", + * ETH Series on Information Processing (ed. J.L. Massey) Vol 1, + * Hartung-Gorre Verlag, Konstanz, Switzerland, 1992. ISBN + * 3-89191-573-X. * - * This code assumes that each pair of 8-bit bytes comprising a 16-bit - * word in the key and in the cipher block are externally represented - * with the Most Significant Byte (MSB) first, regardless of the - * internal native byte order of the target CPU. + * This code runs on arrays of bytes by taking pairs in big-endian + * order to make the 16-bit words that IDEA uses internally. This + * produces the same result regardless of the byte order of the + * native CPU. */ #include "idea.h" - -#ifdef TEST -#include -#include -#endif - -#define ROUNDS 8 /* Don't change this value, should be 8 */ -#define KEYLEN (6*ROUNDS+4) /* length of key schedule */ - -typedef word16 IDEAkey[KEYLEN]; +#include "randpool.h" #ifdef IDEA32 /* Use >16-bit temporaries */ #define low16(x) ((x) & 0xFFFF) @@ -75,64 +67,58 @@ typedef word16 uint16; #ifdef _GNUC_ /* __const__ simply means there are no side effects for this function, - * which is useful info for the gcc optimizer */ + * which is useful info for the gcc optimizer + */ #define CONST __const__ #else #define CONST #endif -static void en_key_idea(word16 userkey[8], IDEAkey Z); -static void de_key_idea(IDEAkey Z, IDEAkey DK); -static void cipher_idea(word16 in[4], word16 out[4], CONST IDEAkey Z); - /* * Multiplication, modulo (2**16)+1 - * Note that this code is structured like this on the assumption that - * untaken branches are cheaper than taken branches, and the compiler - * doesn't schedule branches. + * Note that this code is structured on the assumption that + * untaken branches are cheaper than taken branches, and the + * compiler doesn't schedule branches. */ #ifdef SMALL_CACHE -CONST static uint16 mul(register uint16 a, register uint16 b) +CONST static uint16 +mul(register uint16 a, register uint16 b) { register word32 p; - if (a) - { if (b) - { p = (word32)a * b; - b = low16(p); - a = p>>16; - return b - a + (b < a); - } - else - { return 1-a; - } - } - else - { return 1-b; + p = (word32)a * b; + if (p) { + b = low16(p); + a = p>>16; + return (b - a) + (b < a); + } else if (a) { + return 1-b; + } else { + return 1-a; } -} /* mul */ +} /* mul */ #endif /* SMALL_CACHE */ /* - * Compute multiplicative inverse of x, modulo (2**16)+1, - * using Euclid's GCD algorithm. It is unrolled twice to - * avoid swapping the meaning of the registers each iteration, - * and some subtracts of t have been changed to adds. + * Compute the multiplicative inverse of x, modulo 65537, using Euclid's + * algorithm. It is unrolled twice to avoid swapping the registers each + * iteration, and some subtracts of t have been changed to adds. */ -CONST static uint16 inv(uint16 x) +CONST static uint16 +mulInv(uint16 x) { uint16 t0, t1; uint16 q, y; if (x <= 1) return x; /* 0 and 1 are self-inverse */ - t1 = 0x10001 / x; /* Since x >= 2, this fits into 16 bits */ - y = 0x10001 % x; + t1 = 0x10001L / x; /* Since x >= 2, this fits into 16 bits */ + y = 0x10001L % x; if (y == 1) return low16(1-t1); t0 = 1; - do - { q = x / y; + do { + q = x / y; x = x % y; t0 += q * t1; if (x == 1) @@ -142,481 +128,517 @@ CONST static uint16 inv(uint16 x) t1 += q * t0; } while (y != 1); return low16(1-t1); -} /* inv */ +} /* mukInv */ -/* Compute IDEA encryption subkeys Z */ -static void en_key_idea(word16 *userkey, word16 *Z) +/* + * Expand a 128-bit user key to a working encryption key EK + */ +static void +ideaExpandKey(byte const *userkey, word16 *EK) { int i,j; - /* - * shifts - */ - for (j=0; j<8; j++) - Z[j] = *userkey++; - - for (i=0; j> 7; - Z += i & 8; + for (j=0; j<8; j++) { + EK[j] = (userkey[0]<<8) + userkey[1]; + userkey += 2; + } + for (i=0; j < IDEAKEYLEN; j++) { + i++; + EK[i+7] = EK[i & 7] << 9 | EK[i+1 & 7] >> 7; + EK += i & 8; i &= 7; } -} /* en_key_idea */ +} /* ideaExpandKey */ -/* Compute IDEA decryption subkeys DK from encryption subkeys Z */ -/* Note: these buffers *may* overlap! */ -static void de_key_idea(IDEAkey Z, IDEAkey DK) +/* + * Compute IDEA decryption key DK from an expanded IDEA encryption key EK + * Note that the input and output may be the same. Thus, the key is + * inverted into an internal buffer, and then copied to the output. + */ +static void +ideaInvertKey(word16 const *EK, word16 DK[IDEAKEYLEN]) { - int j; + int i; uint16 t1, t2, t3; - IDEAkey T; - word16 *p = T + KEYLEN; + word16 temp[IDEAKEYLEN]; + word16 *p = temp + IDEAKEYLEN; - t1 = inv(*Z++); - t2 = -*Z++; - t3 = -*Z++; - *--p = inv(*Z++); + t1 = mulInv(*EK++); + t2 = -*EK++; + t3 = -*EK++; + *--p = mulInv(*EK++); *--p = t3; *--p = t2; *--p = t1; - for (j = 1; j < ROUNDS; j++) - { - t1 = *Z++; - *--p = *Z++; + for (i = 0; i < IDEAROUNDS-1; i++) { + t1 = *EK++; + *--p = *EK++; *--p = t1; - t1 = inv(*Z++); - t2 = -*Z++; - t3 = -*Z++; - *--p = inv(*Z++); + t1 = mulInv(*EK++); + t2 = -*EK++; + t3 = -*EK++; + *--p = mulInv(*EK++); *--p = t2; *--p = t3; *--p = t1; } - t1 = *Z++; - *--p = *Z++; + t1 = *EK++; + *--p = *EK++; *--p = t1; - t1 = inv(*Z++); - t2 = -*Z++; - t3 = -*Z++; - *--p = inv(*Z++); + t1 = mulInv(*EK++); + t2 = -*EK++; + t3 = -*EK++; + *--p = mulInv(*EK++); *--p = t3; *--p = t2; *--p = t1; /* Copy and destroy temp copy */ - for (j = 0, p = T; j < KEYLEN; j++) - { - *DK++ = *p; - *p++ = 0; - } -} /* de_key_idea */ + memcpy(DK, temp, sizeof(temp)); + burn(temp); +} /* ideaInvertKey */ /* * MUL(x,y) computes x = x*y, modulo 0x10001. Requires two temps, - * t16 and t32. x must me a side-effect-free lvalue. y may be - * anything, but unlike x, must be strictly 16 bits even if low16() - * is #defined. + * t16 and t32. x is modified, and must me a side-effect-free lvalue. + * y may be anything, but unlike x, must be strictly 16 bits even if + * low16() is #defined. * All of these are equivalent - see which is faster on your machine */ #ifdef SMALL_CACHE #define MUL(x,y) (x = mul(low16(x),y)) -#else +#else /* !SMALL_CACHE */ #ifdef AVOID_JUMPS #define MUL(x,y) (x = low16(x-1), t16 = low16((y)-1), \ - t32 = (word32)x*t16+x+t16+1, x = low16(t32), \ - t16 = t32>>16, x = x-t16+(x>16, \ - x = x-t16+(x>16, x = (x-t16) + (x>16, \ + x = (x-t16)+(x>8) | (x1<<8); + x2 = (x2>>8) | (x2<<8); + x3 = (x3>>8) | (x3<<8); + x4 = (x4>>8) | (x4<<8); +#endif + do { + MUL(x1,*key++); + x2 += *key++; + x3 += *key++; + MUL(x4, *key++); + + s3 = x3; + x3 ^= x1; + MUL(x3, *key++); + s2 = x2; + x2 ^= x4; + x2 += x3; + MUL(x2, *key++); + x3 += x2; + + x1 ^= x2; x4 ^= x3; + + x2 ^= s3; x3 ^= s2; } while (--r); - MUL(x1, *Z++); + MUL(x1, *key++); + x3 += *key++; + x2 += *key++; + MUL(x4, *key); + + out = (word16 *)outbuf; +#ifdef HIGHFIRST *out++ = x1; - *out++ = x3 + *Z++; - *out++ = x2 + *Z++; - MUL(x4, *Z); + *out++ = x3; + *out++ = x2; *out = x4; -} /* cipher_idea */ +#else /* !HIGHFIRST */ + x1 = low16(x1); + x2 = low16(x2); + x3 = low16(x3); + x4 = low16(x4); + *out++ = (x1>>8) | (x1<<8); + *out++ = (x3>>8) | (x3<<8); + *out++ = (x2>>8) | (x2<<8); + *out = (x4>>8) | (x4<<8); +#endif +} /* ideaCipher */ /*-------------------------------------------------------------*/ #ifdef TEST + +#include +#include /* * This is the number of Kbytes of test data to encrypt. * It defaults to 1 MByte. */ +#ifndef BLOCKS #ifndef KBYTES #define KBYTES 1024 #endif +#define BLOCKS (64*KBYTES) +#endif -void main(void) -{ /* Test driver for IDEA cipher */ - int i, j, k; - IDEAkey Z, DK; - word16 XX[4], TT[4], YY[4]; - word16 userkey[8]; +int +main(void) +{ /* Test driver for IDEA cipher */ + int i, j, k; + byte userkey[16]; + word16 EK[IDEAKEYLEN], DK[IDEAKEYLEN]; + byte XX[8], YY[8], ZZ[8]; clock_t start, end; long l; /* Make a sample user key for testing... */ - for(i=0; i<8; i++) + for(i=0; i<16; i++) userkey[i] = i+1; /* Compute encryption subkeys from user key... */ - en_key_idea(userkey,Z); + ideaExpandKey(userkey, EK); printf("\nEncryption key subblocks: "); - for(j=0; jiv, iv, 8); + else + fill0(context->iv, 8); + context->bufleft = 0; +} + +void +ideaCfbInit(struct IdeaCfbContext *context, byte const (key[16])) +{ + ideaExpandKey(key, context->key); + ideaCfbReinit(context,0); +} + +void +ideaCfbDestroy(struct IdeaCfbContext *context) +{ + burn(*context); +} + +/* + * Okay, explanation time: + * Phil invented a unique way of doing CFB that's sensitive to semantic + * boundaries within the data being encrypted. One way to phrase + * CFB en/decryption is to say that you XOR the current 8 bytes with + * IDEA(previous 8 bytes of ciphertext). Normally, you repeat this + * at 8-byte intervals, but Phil decided to resync things on the + * boundaries between elements in the stream being encrypted. + * + * That is, the last 4 bytes of a 12-byte field are en/decrypted using + * the first 4 bytes of IDEA(previous 8 bytes of ciphertext), but then + * the last 4 bytes of that IDEA computation are thrown away, and the + * first 8 bytes of the next field are en/decrypted using + * IDEA(last 8 bytes of ciphertext). This is equivalent to using a + * shorter feedback length (if you're familiar with the general CFB + * technique) briefly, and doesn't weaken the cipher any (using shorter + * CFB lengths makes it stronger, actually), it just makes it a bit unusual. + * + * Anyway, to accomodate this behaviour, every time we do an IDEA + * encrpytion of 8 bytes of ciphertext to get 8 bytes of XOR mask, + * we remember the ciphertext. Then if we have to resync things + * after having processed, say, 2 bytes, we refill the iv buffer + * with the last 6 bytes of the old ciphertext followed by the + * 2 bytes of new ciphertext stored in the front of the iv buffer. + */ +void +ideaCfbSync(struct IdeaCfbContext *context) +{ + int bufleft = context->bufleft; -/* - * xorbuf - change buffer via xor with random mask block - * Used for Cipher Feedback (CFB) or Cipher Block Chaining - * (CBC) modes of encryption. - * Can be applied for any block encryption algorithm, - * with any block size, such as the DES or the IDEA cipher. - */ -static void xorbuf(register byteptr buf, register byteptr mask, - register int count) -/* count must be > 0 */ -{ - if (count) - do - *buf++ ^= *mask++; - while (--count); -} /* xorbuf */ - + if (bufleft) { + memmove(context->iv+bufleft, context->iv, 8-bufleft); + memcpy(context->iv, context->oldcipher+8-bufleft, bufleft); + context->bufleft = 0; + } +} /* - * cfbshift - shift bytes into IV for CFB input - * Used only for Cipher Feedback (CFB) mode of encryption. - * Can be applied for any block encryption algorithm with any - * block size, such as the DES or the IDEA cipher. - */ -static void cfbshift(register byteptr iv, register byteptr buf, - register int count, int blocksize) -/* iv is the initialization vector. - * buf is the buffer pointer. - * count is the number of bytes to shift in...must be > 0. - * blocksize is 8 bytes for DES or IDEA ciphers. - */ -{ - int retained; - if (count) - { - retained = blocksize-count; /* number bytes in iv to retain */ - /* left-shift retained bytes of IV over by count bytes to make room */ - while (retained--) - { - *iv = *(iv+count); - iv++; + * Encrypt a buffer of data, using IDEA in CFB mode. + * There are more compact ways of writing this, but this is + * written for speed. + */ +void +ideaCfbEncrypt(struct IdeaCfbContext *context, byte const *src, + byte *dest, int count) +{ + int bufleft = context->bufleft; + byte *bufptr = context->iv + 8-bufleft; + + /* If there are no more bytes to encrypt that there are bytes + * in the buffer, XOR them in and return. + */ + if (count <= bufleft) { + context->bufleft = bufleft - count; + while (count--) { + *dest++ = *bufptr++ ^= *src++; } - /* now copy count bytes from buf to shifted tail of IV */ - do *iv++ = *buf++; - while (--count); + return; + } + count -= bufleft; + /* Encrypt the first bufleft (0 to 7) bytes of the input by XOR + * with the last bufleft bytes in the iv buffer. + */ + while (bufleft--) { + *dest++ = (*bufptr++ ^= *src++); } -} /* cfbshift */ + /* Encrypt middle blocks of the input by cranking the cipher, + * XORing 8-byte blocks, and repeating until the count + * is 8 or less. + */ + while (count > 8) { + bufptr = context->iv; + memcpy(context->oldcipher, bufptr, 8); + ideaCipher(bufptr, bufptr, context->key); + bufleft = 8; + count -= 8; + do { + *dest++ = (*bufptr++ ^= *src++); + } while (--bufleft); + } + /* Do the last 1 to 8 bytes */ + bufptr = context->iv; + memcpy(context->oldcipher, bufptr, 8); + ideaCipher(bufptr, bufptr, context->key); + context->bufleft = 8-count; + do { + *dest++ = (*bufptr++ ^= *src++); + } while (--count); +} +/* + * Decrypt a buffer of data, using IDEA in CFB mode. + * There are more compact ways of writing this, but this is + * written for speed. + */ +void +ideaCfbDecrypt(struct IdeaCfbContext *context, byte const *src, + byte *dest, int count) +{ + int bufleft = context->bufleft; + static byte *bufptr; + byte t; + + bufptr = context->iv + (8-bufleft); + if (count <= bufleft) { + context->bufleft = bufleft - count; + while (count--) { + t = *bufptr; + *dest++ = t ^ (*bufptr++ = *src++); + } + return; + } + count -= bufleft; + while (bufleft--) { + t = *bufptr; + *dest++ = t ^ (*bufptr++ = *src++); + } + while (count > 8) { + bufptr = context->iv; + memcpy(context->oldcipher, bufptr, 8); + ideaCipher(bufptr, bufptr, context->key); + bufleft = 8; + count -= 8; + do { + t = *bufptr; + *dest++ = t ^ (*bufptr++ = *src++); + } while (--bufleft); + } + bufptr = context->iv; + memcpy(context->oldcipher, bufptr, 8); + ideaCipher(bufptr, bufptr, context->key); + context->bufleft = 8-count; + do { + t = *bufptr; + *dest++ = t ^ (*bufptr++ = *src++); + } while (--count); +} -/* Key schedules for IDEA encryption and decryption */ -static IDEAkey Z, DK; -static word16 *iv_idea; /* pointer to IV for CFB or CBC */ -static boolean cfb_dc_idea; /* TRUE iff CFB decrypting */ +/********************************************************************/ +/* + * Cryptographically strong pseudo-random-number generator. + * The design is from Appendix C of ANSI X9.17, "Financial + * Institution Key Management (Wholesale)", with IDEA + * substituted for the DES. + */ -/* initkey_idea initializes IDEA for ECB mode operations */ -void initkey_idea(byte key[16], boolean decryp) +/* + * Initialize a cryptographic random-number generator. + * key and seed should be arbitrary. + */ +void +ideaRandInit(struct IdeaRandContext *context, byte const (key[16]), + byte const (seed[8])) { - word16 userkey[8]; /* IDEA key is 16 bytes long */ int i; - /* Assume each pair of bytes comprising a word is ordered MSB-first. */ - for (i=0; i<8; i++) - { - userkey[i] = (key[0]<<8) + key[1]; - key++; key++; - } - en_key_idea(userkey,Z); - if (decryp) - { - de_key_idea(Z,Z); /* compute inverse key schedule DK */ - } - for (i=0; i<8; i++) /* Erase dangerous traces */ - userkey[i] = 0; -} /* initkey_idea */ - - -/* Run a 64-bit block thru IDEA in ECB (Electronic Code Book) mode, - using the currently selected key schedule. -*/ -void idea_ecb(word16 *inbuf, word16 *outbuf) -{ - /* Assume each pair of bytes comprising a word is ordered MSB-first. */ -#ifndef HIGHFIRST /* If this is a least-significant-byte-first CPU */ - word16 x; - - /* Invert the byte order for each 16-bit word for internal use. */ - x = inbuf[0]; outbuf[0] = x >> 8 | x << 8; - x = inbuf[1]; outbuf[1] = x >> 8 | x << 8; - x = inbuf[2]; outbuf[2] = x >> 8 | x << 8; - x = inbuf[3]; outbuf[3] = x >> 8 | x << 8; - cipher_idea(outbuf, outbuf, Z); - x = outbuf[0]; outbuf[0] = x >> 8 | x << 8; - x = outbuf[1]; outbuf[1] = x >> 8 | x << 8; - x = outbuf[2]; outbuf[2] = x >> 8 | x << 8; - x = outbuf[3]; outbuf[3] = x >> 8 | x << 8; -#else /* HIGHFIRST */ - /* Byte order for internal and external representations is the same. */ - cipher_idea(inbuf, outbuf, Z); -#endif /* HIGHFIRST */ -} /* idea_ecb */ - -/* - * initcfb - Initializes the IDEA key schedule tables via key, - * and initializes the Cipher Feedback mode IV. - * References context variables cfb_dc_idea and iv_idea. - */ -void initcfb_idea(word16 iv0[4], byte key[16], boolean decryp) -/* iv0 is copied to global iv_idea, buffer will be destroyed by ideacfb. - key is pointer to key buffer. - decryp is TRUE if decrypting, FALSE if encrypting. -*/ -{ - iv_idea = iv0; - cfb_dc_idea = decryp; - initkey_idea(key,FALSE); -} /* initcfb_idea */ + ideaExpandKey(key, context->key); + context->bufleft = 0; + memcpy(context->internalbuf, seed, 8); +} /* - * ideacfb - encipher a buffer with IDEA enciphering algorithm, - * using Cipher Feedback (CFB) mode. - * - * Assumes initcfb_idea has already been called. - * References context variables cfb_dc_idea and iv_idea. - */ -void ideacfb(byteptr buf, int count) -/* buf is input, output buffer, may be more than 1 block. - * count is byte count of buffer. May be > IDEABLOCKSIZE. + * Read out the RNG's state. */ +void +ideaRandState(struct IdeaRandContext *context, byte key[16], byte seed[8]) { - int chunksize; /* smaller of count, IDEABLOCKSIZE */ - word16 temp[IDEABLOCKSIZE/2]; - - while ((chunksize = min(count,IDEABLOCKSIZE)) > 0) - { - idea_ecb(iv_idea,temp); /* encrypt iv_idea, making temp. */ - - if (cfb_dc_idea) /* buf is ciphertext */ - /* shift in ciphertext to IV... */ - cfbshift((byte *)iv_idea,buf,chunksize,IDEABLOCKSIZE); - - /* convert buf via xor */ - xorbuf(buf,(byte *)temp,chunksize); /* buf now has enciphered output */ - - if (!cfb_dc_idea) /* buf was plaintext, is now ciphertext */ - /* shift in ciphertext to IV... */ - cfbshift((byte *)iv_idea,buf,chunksize,IDEABLOCKSIZE); + int i; - count -= chunksize; - buf += chunksize; + memcpy(seed, context->internalbuf, 8); + for (i = 0; i < 8; i++) { + key[2*i] = context->key[i] >> 8; + key[2*i+1] = context->key[i]; } -} /* ideacfb */ - -/* - close_idea function erases all the key schedule information when - we are all done with a set of operations for a particular IDEA key - context. This is to prevent any sensitive data from being left - around in memory. -*/ -void close_idea(void) /* erase current key schedule tables */ -{ - short i; - for (i = 0; i < KEYLEN; i++) - Z[i] = 0; -} /* close_idea() */ - -/********************************************************************/ +} /* - * These buffers are used by init_idearand, idearand, and close_idearand. - */ -static word16 dtbuf_idea[4] = {0}; /* buffer for enciphered timestamp */ -static word16 randseed_idea[4] = {0}; /* seed for IDEA random # generator */ -static word16 randbuf_idea[4] = {0}; /* buffer for IDEA random # generator */ -static byte randbuf_idea_counter = 0; /* # of random bytes left in randbuf_idea */ - -/* - * init_idearand - initialize idearand, IDEA random number generator. - * Used for generating cryptographically strong random numbers. - * Much of the design comes from Appendix C of ANSI X9.17. - * key is pointer to IDEA key buffer. - * seed is pointer to random number seed buffer. - * tstamp is a 32-bit timestamp + * Encrypt the RNG's state with the given CFB encryptor. */ -void init_idearand(byte key[16], byte seed[8], word32 tstamp) +void +ideaRandWash(struct IdeaRandContext *context, struct IdeaCfbContext *cfb) { + byte keyseed[16+8]; int i; - initkey_idea(key, FALSE); /* initialize IDEA */ - for (i=0; i<4; i++) /* capture timestamp material */ - { dtbuf_idea[i] = tstamp; /* get bottom word */ - tstamp = tstamp >> 16; /* drop bottom word */ - /* tstamp has only 4 bytes-- last 4 bytes will always be 0 */ - } - /* Start with enciphered timestamp: */ - idea_ecb(dtbuf_idea,dtbuf_idea); - - /* initialize seed material */ - for (i=0; i<8; i++) - ((byte *)randseed_idea)[i] = seed[i]; - - randbuf_idea_counter = 0; /* # of random bytes left in randbuf_idea */ - -} /* init_idearand */ + ideaRandState(context, keyseed, keyseed+16); + ideaCfbEncrypt(cfb, keyseed, keyseed, 16+8); + ideaRandInit(context, keyseed, keyseed+16); + memset(keyseed, 0, 16+8); +} /* - * idearand - IDEA pseudo-random number generator - * Used for generating cryptographically strong random numbers. - * Much of the design comes from Appendix C of ANSI X9.17. + * Cryptographic pseudo-random-number generator, used for generating + * session keys. */ -byte idearand(void) +byte +ideaRandByte(struct IdeaRandContext *c) { int i; - if (randbuf_idea_counter==0) /* if random buffer is spent...*/ - { /* Combine enciphered timestamp with seed material: */ - for (i=0; i<4; i++) - randseed_idea[i] ^= dtbuf_idea[i]; - idea_ecb(randseed_idea,randbuf_idea); /* fill new block */ - - /* Compute new seed vector: */ - for (i=0; i<4; i++) - randseed_idea[i] = randbuf_idea[i] ^ dtbuf_idea[i]; - idea_ecb(randseed_idea,randseed_idea); /* fill new seed */ - - randbuf_idea_counter = 8; /* reset counter for full buffer */ - } - /* Take a byte from randbuf_idea: */ - return(((byte *)randbuf_idea)[--randbuf_idea_counter]); -} /* idearand */ - -void close_idearand(void) -{ /* Erase random IDEA buffers and wipe out IDEA key info */ - int i; - for (i=0; i<4; i++) - { randbuf_idea[i] = 0; - randseed_idea[i] = 0; - dtbuf_idea[i] = 0; + if (!c->bufleft) { + byte timestamp[8]; + + /* Get some true-random noise to help */ + randPoolGetBytes(timestamp, sizeof(timestamp)); + + /* Compute next 8 bytes of output */ + for (i=0; i<8; i++) + c->outbuf[i] = c->internalbuf[i] ^ timestamp[i]; + ideaCipher(c->outbuf, c->outbuf, c->key); + /* Compute new seed vector */ + for (i=0; i<8; i++) + c->internalbuf[i] = c->outbuf[i] ^ timestamp[i]; + ideaCipher(c->internalbuf, c->internalbuf, c->key); + burn(timestamp); + c->bufleft = 8; } - close_idea(); /* erase current key schedule tables */ -} /* close_idearand */ + return c->outbuf[--c->bufleft]; +} /* end of idea.c */