--- pgp/src/idea.c 2018/04/24 16:38:49 1.1.1.2 +++ pgp/src/idea.c 2018/04/24 16:44:46 1.1.1.7 @@ -1,622 +1,635 @@ -/* 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. - * This implementation modified and derived from original C code - * developed by Xuejia Lai. - * Zero-based indexing added, names changed from IPES to IDEA. - * CFB functions added. Random number routines added. +/* + * 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. + * This implementation modified and derived from original C code + * developed by Xuejia Lai. + * 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. + * 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 best for your machine. * - * Multiplication: default is inline, -DAVOID_JUMPS uses a - * different version that does not do any conditional - * jumps (a few percent worse on a SPARC), while - * -DSMALL_CACHE takes it out of line to stay - * within a small on-chip code cache. - * Variables: normally, 16-bit variables are used, but some - * machines (notably RISCs) do not have 16-bit registers, - * so they do a great deal of masking. -DIDEA32 uses "int" - * register variables and masks explicitly only where - * necessary. On a SPARC, for example, this boosts - * performace by 30%. + * Multiplication: default is inline, -DAVOID_JUMPS uses a + * different version that does not do any conditional + * jumps (a few percent worse on a SPARC), while + * -DSMALL_CACHE takes it out of line to stay + * within a small on-chip code cache. + * Variables: normally, 16-bit variables are used, but some + * machines (notably RISCs) do not have 16-bit registers, + * so they do a great deal of masking. -DIDEA32 uses "int" + * register variables and masks explicitly only where + * 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 - * 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. + * 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, 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 - * because all of the primitive inner operations are done with 16-bit - * arithmetic. It likewise breaks the 128-bit cipher key into eight - * 16-bit words. + * 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 + * because all of the primitive inner operations are done with 16-bit + * 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" +#include "randpool.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]; - -#ifdef IDEA32 /* Use >16-bit temporaries */ +#ifdef IDEA32 /* Use >16-bit temporaries */ #define low16(x) ((x) & 0xFFFF) typedef unsigned int uint16; /* at LEAST 16 bits, maybe more */ #else -#define low16(x) (x) /* this is only ever applied to uint16's */ +#define low16(x) (x) /* this is only ever applied to uint16's */ typedef word16 uint16; #endif #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. + * Multiplication, modulo (2**16)+1 + * 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; + 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; - } -} /* 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. - */ -CONST static uint16 inv(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; - if (y == 1) - return low16(1-t1); - t0 = 1; - do - { q = x / y; - x = x % y; - t0 += q * t1; - if (x == 1) - return t0; - q = y / x; - y = y % x; - t1 += q * t0; - } while (y != 1); - return low16(1-t1); -} /* inv */ - -/* Compute IDEA encryption subkeys Z */ -static void en_key_idea(word16 *userkey, word16 *Z) -{ - int i,j; - - /* - * shifts - */ - for (j=0; j<8; j++) - Z[j] = *userkey++; - - for (i=0; j> 7; - Z += i & 8; - i &= 7; - } -} /* en_key_idea */ - -/* Compute IDEA decryption subkeys DK from encryption subkeys Z */ -/* Note: these buffers *may* overlap! */ -static void de_key_idea(IDEAkey Z, IDEAkey DK) -{ - int j; - uint16 t1, t2, t3; - IDEAkey T; - word16 *p = T + KEYLEN; - - t1 = inv(*Z++); - t2 = -*Z++; - t3 = -*Z++; - *--p = inv(*Z++); - *--p = t3; - *--p = t2; + p = (word32) a *b; + if (p) { + b = low16(p); + a = p >> 16; + return (b - a) + (b < a); + } else if (a) { + return 1 - a; + } else { + return 1 - b; + } +} /* mul */ +#endif /* SMALL_CACHE */ + +/* + * 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 + mulInv(uint16 x) +{ + uint16 t0, t1; + uint16 q, y; + + if (x <= 1) + return x; /* 0 and 1 are self-inverse */ + 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; + x = x % y; + t0 += q * t1; + if (x == 1) + return t0; + q = y / x; + y = y % x; + t1 += q * t0; + } while (y != 1); + return low16(1 - t1); +} /* mukInv */ + +/* + * Expand a 128-bit user key to a working encryption key EK + */ +static void ideaExpandKey(byte const *userkey, word16 * EK) +{ + int i, j; + + 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; + } +} /* ideaExpandKey */ + +/* + * 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 i; + uint16 t1, t2, t3; + word16 temp[IDEAKEYLEN]; + word16 *p = temp + IDEAKEYLEN; + + t1 = mulInv(*EK++); + t2 = -*EK++; + t3 = -*EK++; + *--p = mulInv(*EK++); + *--p = t3; + *--p = t2; + *--p = t1; + + for (i = 0; i < IDEAROUNDS - 1; i++) { + t1 = *EK++; + *--p = *EK++; *--p = t1; - for (j = 1; j < ROUNDS; j++) - { - t1 = *Z++; - *--p = *Z++; - *--p = t1; - - t1 = inv(*Z++); - t2 = -*Z++; - t3 = -*Z++; - *--p = inv(*Z++); - *--p = t2; - *--p = t3; - *--p = t1; - } - t1 = *Z++; - *--p = *Z++; - *--p = t1; - - t1 = inv(*Z++); - t2 = -*Z++; - t3 = -*Z++; - *--p = inv(*Z++); - *--p = t3; + t1 = mulInv(*EK++); + t2 = -*EK++; + t3 = -*EK++; + *--p = mulInv(*EK++); *--p = t2; + *--p = t3; *--p = t1; + } + t1 = *EK++; + *--p = *EK++; + *--p = t1; + + 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 be a side-effect-free lvalue. + * y may be anything, but unlike x, must be strictly less than 65536 + * 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, *key++); + x3 += *key++; + x2 += *key++; + MUL(x4, *key); + + out = (word16 *) outbuf; +#ifdef HIGHFIRST + *out++ = x1; + *out++ = x3; + *out++ = x2; + *out = x4; +#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]; - clock_t start, end; - long l; - - /* Make a sample user key for testing... */ - for(i=0; i<8; i++) - userkey[i] = i+1; - - /* Compute encryption subkeys from user key... */ - en_key_idea(userkey,Z); - printf("\nEncryption key subblocks: "); - for(j=0; j 0 */ -{ - if (count) - do - *buf++ ^= *mask++; - while (--count); -} /* xorbuf */ - - -/* - * 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++; - } - /* now copy count bytes from buf to shifted tail of IV */ - do *iv++ = *buf++; - while (--count); - } -} /* cfbshift */ - - - -/* 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 */ - - -/* initkey_idea initializes IDEA for ECB mode operations */ -void initkey_idea(byte key[16], boolean decryp) +void ideaCfbReinit(struct IdeaCfbContext *context, byte const *iv) { - 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 */ + if (iv) + memcpy(context->iv, 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; + + if (bufleft) { + memmove(context->iv + bufleft, context->iv, 8 - bufleft); + memcpy(context->iv, context->oldcipher + 8 - bufleft, bufleft); + context->bufleft = 0; + } +} + +/* + * 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++; + } + 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++); + } + /* 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); +} +/********************************************************************/ /* - * 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 */ - + * 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. + */ /* - * 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. + * 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]) { - 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); + int i; - /* 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); - - count -= chunksize; - buf += chunksize; - } -} /* ideacfb */ + ideaExpandKey(key, context->key); + context->bufleft = 0; + memcpy(context->internalbuf, seed, 8); +} /* - 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 */ + * Read out the RNG's state. + */ +void ideaRandState(struct IdeaRandContext *context, byte key[16], byte seed[8]) { - short i; - for (i = 0; i < KEYLEN; i++) - Z[i] = 0; -} /* close_idea() */ + int i; -/********************************************************************/ + 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]; + } + +} /* - * These buffers are used by init_idearand, idearand, and close_idearand. + * Encrypt the RNG's state with the given CFB encryptor. */ -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 - */ -void init_idearand(byte key[16], byte seed[8], word32 tstamp) -{ - 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 */ +void ideaRandWash(struct IdeaRandContext *context, struct IdeaCfbContext *cfb) +{ + byte keyseed[16 + 8]; + int i; -} /* 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 */ + int i; - /* 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 */ + if (!c->bufleft) { + byte timestamp[8]; + /* Get some true-random noise to help */ + randPoolGetBytes(timestamp, sizeof(timestamp)); -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; - } - close_idea(); /* erase current key schedule tables */ -} /* close_idearand */ + /* 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; + } + return c->outbuf[--c->bufleft]; +} /* end of idea.c */ -