Annotation of pgp/src/idea.c, revision 1.1.1.1

1.1       root        1: /*     idea.c - C source code for IDEA block cipher.
                      2:        IDEA (International Data Encryption Algorithm), formerly known as 
                      3:        IPES (Improved Proposed Encryption Standard).
                      4:        Algorithm developed by Xuejia Lai and James L. Massey, of ETH Zurich.
                      5:        This implementation modified and derived from original C code 
                      6:        developed by Xuejia Lai.  Last modified 8 July 92.
                      7: 
                      8:        Zero-based indexing added, names changed from IPES to IDEA.
                      9:        CFB functions added.  Random number routines added.
                     10: 
                     11:        The IDEA(tm) block cipher is covered by a patent held by ETH and a
                     12:        Swiss company called Ascom-Tech AG.  The Swiss patent number is
                     13:        PCT/CH91/00117.  International patents are pending. IDEA(tm) is a
                     14:        trademark of Ascom-Tech AG.  There is no license fee required for
                     15:        noncommercial use.  Commercial users may obtain licensing details
                     16:        from Dieter Profos, Ascom Tech AG, Solothurn Lab, Postfach 151, 4502
                     17:        Solothurn, Switzerland, Tel +41 65 242885, Fax +41 65 235761.
                     18: 
                     19:        The IDEA block cipher uses a 64-bit block size, and a 128-bit key 
                     20:        size.  It breaks the 64-bit cipher block into four 16-bit words
                     21:        because all of the primitive inner operations are done with 16-bit 
                     22:        arithmetic.  It likewise breaks the 128-bit cipher key into eight 
                     23:        16-bit words.
                     24: 
                     25:        For further information on the IDEA cipher, see these papers:
                     26:        1)      Xuejia Lai, "Detailed Description and a Software Implementation of 
                     27:        the IPES Cipher", Institute for Signal and Information
                     28:        Processing, ETH-Zentrum, Zurich, Switzerland, 1991
                     29:        2)      Xuejia Lai, James L. Massey, Sean Murphy, "Markov Ciphers and 
                     30:        Differential Cryptanalysis", Advances in Cryptology- EUROCRYPT'91
                     31: 
                     32:        This code assumes that each pair of 8-bit bytes comprising a 16-bit 
                     33:        word in the key and in the cipher block are externally represented 
                     34:        with the Most Significant Byte (MSB) first, regardless of the
                     35:        internal native byte order of the target CPU.
                     36: 
                     37: */
                     38: #include <stdio.h>
                     39: #include "idea.h"
                     40: 
                     41: /* #define lower16(x) ((word16)((x) & mask16)) */ /* unoptimized version */
                     42: #define lower16(x)   ((word16)(x))     /* optimized version */
                     43: 
                     44: #define maxim        0x10001
                     45: #define fuyi         0x10000   /* Why did Lai pick a name like this? */
                     46: #define mask16       ((word16) 0xffff)
                     47: #define ROUNDS       8         /* Don't change this value, should be 8 */
                     48: 
                     49: static void en_key_idea(word16 userkey[8], word16 Z[6][ROUNDS+1]);
                     50: static void de_key_idea(word16 Z[6][ROUNDS+1], word16 DK[6][ROUNDS+1]);
                     51: static void cipher_idea(word16 inblock[4], word16 outblock[4],
                     52:                 word16 Z[6][ROUNDS+1]);
                     53: 
                     54: 
                     55: /*     Multiplication, modulo (2**16)+1 */
                     56: static word16 mul(register word16 a, register word16 b)
                     57: {
                     58:        register word32 q;
                     59:        register long int p;
                     60:        if (a==0)
                     61:                p = maxim-b; 
                     62:        else 
                     63:                if (b==0)
                     64:                        p = maxim-a;  
                     65:                else
                     66:                {       q = (word32)a * (word32)b; 
                     67:                        p = (q & mask16) - (q>>16);
                     68:                        if (p<=0) 
                     69:                                p = p+maxim;
                     70:                }
                     71:        return (lower16(p));
                     72: }        /* mul */
                     73: 
                     74: 
                     75: /*     Compute multiplicative inverse of x, modulo (2**16)+1,
                     76:        using Euclid's GCD algorithm. */
                     77: static word16 inv(word16 x)     
                     78: {
                     79:        long n1,n2,q,r,b1,b2,t;
                     80:        if (x == 0)
                     81:                b2 = 0;
                     82:        else
                     83:        {       n1 = maxim;
                     84:                n2 = x;
                     85:                b2 = 1;
                     86:                b1 = 0;
                     87:                do   
                     88:                {       r = (n1 % n2);
                     89:                        q = (n1-r)/n2;
                     90:                        if (r == 0)  
                     91:                        {       if (b2 < 0)
                     92:                                        b2 = maxim+b2;
                     93:                        }
                     94:                        else
                     95:                        {       n1 = n2; 
                     96:                                n2 = r; 
                     97:                                t = b2;
                     98:                                b2 = b1 - q*b2; 
                     99:                                b1 = t;
                    100:                        }
                    101:                } while (r != 0);
                    102:        } 
                    103: #ifdef IDEA_DEBUG
                    104:        if ( mul(x, (word16) b2) != 1) /* check answer */
                    105:                printf("\n\07Error! inv(%u) = %u ?\n", x, (word16) b2 );
                    106: #endif
                    107:        return ((word16) b2);
                    108: }        /* inv */
                    109: 
                    110: 
                    111: /*     Compute IDEA encryption subkeys Z */
                    112: static void en_key_idea(word16 userkey[8], word16 Z[6][ROUNDS+1])
                    113: {
                    114:        word16 S[54];
                    115:        int i,j,r;
                    116:        /*   shifts   */
                    117:        for (i = 0; i<8; i++)
                    118:                S[i] = userkey[i];
                    119:        for (i = 8; i<54; i++)
                    120:        {       if ((i+2)%8 == 0)  /* for S[14],S[22],...  */  
                    121:                        S[i] = lower16((S[i-7] << 9) ^ (S[i-14] >> 7)); 
                    122:                else
                    123:                        if ((i+1)%8 == 0)  /* for S[15],S[23],...   */
                    124:                        S[i] = lower16((S[i-15] << 9) ^ (S[i-14] >> 7)); 
                    125:                else
                    126:                        S[i] = lower16((S[i-7] << 9) ^ (S[i-6] >> 7));
                    127:        }
                    128:        /* get subkeys */
                    129:        for (r=0; r<ROUNDS+1; r++)
                    130:                for (j=0; j<6; j++)
                    131:                        Z[j][r] = S[6*r + j];
                    132: 
                    133:        /* clear sensitive key data from memory... */
                    134:        for (i=0; i<54; i++) S[i] = 0;
                    135: 
                    136: }        /* en_key_idea */
                    137: 
                    138: 
                    139: /*     Compute IDEA decryption subkeys DK from encryption subkeys Z */
                    140: static void de_key_idea(word16 Z[6][ROUNDS+1], word16 DK[6][ROUNDS+1])
                    141: {  
                    142:        int j;
                    143:        for (j=0; j<ROUNDS+1; j++)
                    144:        {       DK[0][ROUNDS-j] = inv(Z[0][j]);
                    145:                DK[3][ROUNDS-j] = inv(Z[3][j]);
                    146:                if (j==0 || j==ROUNDS)
                    147:                {       DK[1][ROUNDS-j] = lower16(fuyi-Z[1][j]);
                    148:                        DK[2][ROUNDS-j] = lower16(fuyi-Z[2][j]);
                    149:                }
                    150:                else
                    151:                {       DK[1][ROUNDS-j] = lower16(fuyi-Z[2][j]);
                    152:                        DK[2][ROUNDS-j] = lower16(fuyi-Z[1][j]);
                    153:                }
                    154:        }  
                    155:        for (j=0; j<ROUNDS; j++)
                    156:        {       DK[4][ROUNDS-1-j] = Z[4][j];
                    157:                DK[5][ROUNDS-1-j] = Z[5][j];
                    158:        }
                    159: }        /* de_key_idea */
                    160: 
                    161: 
                    162: /*     IDEA encryption/decryption algorithm */
                    163: static void cipher_idea(word16 inblock[4], word16 outblock[4],
                    164:                 register word16 Z[6][ROUNDS+1])
                    165: {      /* Note that inblock and outblock can be the same buffer */ 
                    166:        int r;
                    167:        register word16 x1, x2, x3, x4, kk, t1, t2, a;
                    168:        x1=inblock[0];
                    169:        x2=inblock[1];
                    170:        x3=inblock[2];
                    171:        x4=inblock[3];
                    172:        for (r=0; r<ROUNDS; r++)
                    173:        {       x1 = mul(x1, Z[0][r]);
                    174:                x4 = mul(x4, Z[3][r]);
                    175:                x2 = lower16(x2 + Z[1][r]);
                    176:                x3 = lower16(x3 + Z[2][r]);
                    177:                kk = mul(Z[4][r], (x1^x3));      
                    178:                t1 = mul(Z[5][r], lower16(kk + (x2^x4)) );
                    179:                t2 = lower16(kk + t1);
                    180:                x1 = x1^t1;
                    181:                x4 = x4^t2; 
                    182:                a  = x2^t2;
                    183:                x2 = x3^t1;
                    184:                x3 = a;
                    185:        }
                    186:        outblock[0] = mul(x1, Z[0][ROUNDS]);
                    187:        outblock[3] = mul(x4, Z[3][ROUNDS]);
                    188:        outblock[1] = lower16(x3 + Z[1][ROUNDS]);
                    189:        outblock[2] = lower16(x2 + Z[2][ROUNDS]);
                    190: }        /* cipher_idea */
                    191: 
                    192: 
                    193: /*-------------------------------------------------------------*/
                    194: 
                    195: #ifdef TEST
                    196: 
                    197: void main(void)
                    198: {      /* Test driver for IDEA cipher */ 
                    199:        int i, j, k; 
                    200:        word16 Z[6][ROUNDS+1], DK[6][ROUNDS+1], XX[4], TT[4], YY[4];     
                    201:        word16 userkey[8];
                    202: 
                    203:        /* Make a sample user key for testing... */
                    204:        for(i=0; i<8; i++)
                    205:                userkey[i] = i+1;
                    206: 
                    207:        /* Compute encryption subkeys from user key... */
                    208:        en_key_idea(userkey,Z);
                    209:        printf("\nEncryption key subblocks: ");
                    210:        for(j=0; j<ROUNDS+1; j++) 
                    211:        {       printf("\nround %d:   ", j+1);
                    212:                if (j==ROUNDS)
                    213:                        for(i=0; i<4; i++)
                    214:                                printf(" %6u", Z[i][j]);
                    215:                else
                    216:                        for(i=0; i<6; i++)
                    217:                                printf(" %6u", Z[i][j]);
                    218:        }
                    219: 
                    220:        /* Compute decryption subkeys from encryption subkeys... */
                    221:        de_key_idea(Z,DK);
                    222:        printf("\nDecryption key subblocks: ");
                    223:        for(j=0; j<ROUNDS+1; j++) 
                    224:        {       printf("\nround %d:   ", j+1);
                    225:                if (j==ROUNDS)
                    226:                        for(i=0; i<4; i++)
                    227:                                printf(" %6u", DK[i][j]);
                    228:                else
                    229:                        for(i=0; i<6; i++)
                    230:                                printf(" %6u", DK[i][j]);
                    231:        }
                    232: 
                    233:        /* Make a sample plaintext pattern for testing... */
                    234:        for (k=0; k<4; k++)
                    235:                XX[k] = k;
                    236: 
                    237:        cipher_idea(XX,YY,Z);       /* encrypt plaintext XX, making YY */ 
                    238: 
                    239:        cipher_idea(YY,TT,DK);      /* decrypt ciphertext YY, making TT */ 
                    240: 
                    241:        printf("\nX %6u   %6u  %6u  %6u \n",    
                    242:          XX[0], XX[1],  XX[2], XX[3]);
                    243:        printf("Y %6u   %6u  %6u  %6u \n",
                    244:          YY[0], YY[1],  YY[2], YY[3]);
                    245:        printf("T %6u   %6u  %6u  %6u \n",
                    246:          TT[0], TT[1],  TT[2], TT[3]);
                    247: 
                    248:        /* Now decrypted TT should be same as original XX */
                    249:        for (k=0; k<4; k++)
                    250:                if (TT[k] != XX[k])
                    251:                {       printf("\n\07Error!  Noninvertable encryption.\n");
                    252:                        exit(-1);       /* error exit */ 
                    253:                }
                    254:        printf("\nNormal exit.\n");
                    255:        exit(0);        /* normal exit */ 
                    256: }        /* main */
                    257: 
                    258: 
                    259: #endif         /* TEST */
                    260: 
                    261: 
                    262: /*************************************************************************/
                    263: 
                    264: 
                    265: #define byteglue(lo,hi) ((((word16) hi) << 8) + (word16) lo)
                    266: 
                    267: /*
                    268: **     xorbuf - change buffer via xor with random mask block
                    269: **     Used for Cipher Feedback (CFB) or Cipher Block Chaining
                    270: **     (CBC) modes of encryption.
                    271: **     Can be applied for any block encryption algorithm,
                    272: **     with any block size, such as the DES or the IDEA cipher.
                    273: */
                    274: static void xorbuf(register byteptr buf, register byteptr mask, register int count)
                    275: /*     count must be > 0 */
                    276: {      if (count) 
                    277:                do
                    278:                        *buf++ ^= *mask++;
                    279:                while (--count);
                    280: }      /* xorbuf */
                    281: 
                    282: 
                    283: /*
                    284: **     cfbshift - shift bytes into IV for CFB input
                    285: **     Used only for Cipher Feedback (CFB) mode of encryption.
                    286: **     Can be applied for any block encryption algorithm with any 
                    287: **     block size, such as the DES or the IDEA cipher.
                    288: */
                    289: static void cfbshift(register byteptr iv, register byteptr buf, 
                    290:                register int count, int blocksize)
                    291: /*     iv is the initialization vector.
                    292:        buf is the buffer pointer.
                    293:        count is the number of bytes to shift in...must be > 0.
                    294:        blocksize is 8 bytes for DES or IDEA ciphers.
                    295: */
                    296: {      int retained;
                    297:        if (count)
                    298:        {       retained = blocksize-count;     /* number bytes in iv to retain */
                    299:                /* left-shift retained bytes of IV over by count bytes to make room */
                    300:                while (retained--)
                    301:                {       *iv = *(iv+count);
                    302:                        iv++;
                    303:                }
                    304:                /* now copy count bytes from buf to shifted tail of IV */
                    305:                do      *iv++ = *buf++;
                    306:                while (--count);
                    307:        }
                    308: }      /* cfbshift */
                    309: 
                    310: 
                    311: 
                    312: /* Key schedules for IDEA encryption and decryption */
                    313: static word16 Z[6][ROUNDS+1], DK[6][ROUNDS+1];
                    314: static word16 (*keyschedule)[ROUNDS+1];        /* pointer to key schedule Z or DK */
                    315: static word16 *iv_idea;                /* pointer to IV for CFB or CBC */
                    316: static boolean cfb_dc_idea; /* TRUE iff CFB decrypting */
                    317: 
                    318: 
                    319: /* initkey_idea initializes IDEA for ECB mode operations */
                    320: void initkey_idea(byte key[16], boolean decryp)
                    321: {
                    322:        word16 userkey[8];      /* IDEA key is 16 bytes long */
                    323:        int i;
                    324:        /* Assume each pair of bytes comprising a word is ordered MSB-first. */
                    325:        for (i=0; i<8; i++)
                    326:        {       userkey[i] = byteglue(*(key+1),*key);
                    327:                key++; key++;
                    328:        }
                    329:        en_key_idea(userkey,Z);
                    330:        keyschedule = Z;
                    331:        if (decryp)
                    332:        {       int r,j;
                    333:                de_key_idea(Z,DK);      /* compute inverse key schedule DK */
                    334:                keyschedule = DK;
                    335:                /* Don't need Z anymore.  Erase dangerous traces... */
                    336:                for (r=0; r<ROUNDS+1; r++)
                    337:                        for (j=0; j<6; j++)
                    338:                                Z[j][r] = 0;
                    339:        }
                    340:        for (i=0; i<8; i++)     /* Erase dangerous traces */
                    341:                userkey[i] = 0;
                    342: }      /* initkey_idea */
                    343: 
                    344: 
                    345: /*     Run a 64-bit block thru IDEA in ECB (Electronic Code Book) mode,
                    346:        using the currently selected key schedule.
                    347: */
                    348: void idea_ecb(word16 *inbuf, word16 *outbuf)
                    349: {
                    350:        /* Assume each pair of bytes comprising a word is ordered MSB-first. */
                    351: #ifndef HIGHFIRST      /* If this is a least-significant-byte-first CPU */
                    352:        /* Invert the byte order for each 16-bit word for internal use. */
                    353:        union {
                    354:                word16 w[4];
                    355:                byte b[8];
                    356:        } inbuf2, outbuf2;
                    357:        register byte *p;
                    358:        p = (byte *) inbuf;
                    359:        inbuf2.b[1] = *p++;
                    360:        inbuf2.b[0] = *p++;
                    361:        inbuf2.b[3] = *p++;
                    362:        inbuf2.b[2] = *p++;
                    363:        inbuf2.b[5] = *p++;
                    364:        inbuf2.b[4] = *p++;
                    365:        inbuf2.b[7] = *p++;
                    366:        inbuf2.b[6] = *p++;
                    367:        cipher_idea(inbuf2.w,outbuf2.w,keyschedule);
                    368:        /* Now invert the byte order for each 16-bit word for external use. */
                    369:        p = (byte *) outbuf;
                    370:        *p++ = outbuf2.b[1];
                    371:        *p++ = outbuf2.b[0];
                    372:        *p++ = outbuf2.b[3];
                    373:        *p++ = outbuf2.b[2];
                    374:        *p++ = outbuf2.b[5];
                    375:        *p++ = outbuf2.b[4];
                    376:        *p++ = outbuf2.b[7];
                    377:        *p++ = outbuf2.b[6];
                    378: #else  /* HIGHFIRST */
                    379:        /* Byte order for internal and external representations is the same. */
                    380:        cipher_idea(inbuf,outbuf,keyschedule);
                    381: #endif /* HIGHFIRST */
                    382: }      /* idea_ecb */
                    383: 
                    384: 
                    385: /*
                    386: **     initcfb - Initializes the IDEA key schedule tables via key,
                    387: **     and initializes the Cipher Feedback mode IV.
                    388: **     References context variables cfb_dc_idea and iv_idea.
                    389: */
                    390: void initcfb_idea(word16 iv0[4], byte key[16], boolean decryp)
                    391: /*     iv0 is copied to global iv_idea, buffer will be destroyed by ideacfb.
                    392:        key is pointer to key buffer.
                    393:        decryp is TRUE if decrypting, FALSE if encrypting.
                    394: */
                    395: {      iv_idea = iv0;
                    396:        cfb_dc_idea = decryp;
                    397:        initkey_idea(key,FALSE);
                    398: } /* initcfb_idea */
                    399: 
                    400: 
                    401: /*
                    402: **     ideacfb - encipher a buffer with IDEA enciphering algorithm,
                    403: **             using Cipher Feedback (CFB) mode.
                    404: **
                    405: **     Assumes initcfb_idea has already been called.
                    406: **     References context variables cfb_dc_idea and iv_idea.
                    407: */
                    408: void ideacfb(byteptr buf, int count)
                    409: /*     buf is input, output buffer, may be more than 1 block.
                    410:        count is byte count of buffer.  May be > IDEABLOCKSIZE.
                    411: */
                    412: {      int chunksize;  /* smaller of count, IDEABLOCKSIZE */
                    413:        word16 temp[IDEABLOCKSIZE/2];
                    414: 
                    415:        while ((chunksize = min(count,IDEABLOCKSIZE)) > 0)
                    416:        {
                    417:                idea_ecb(iv_idea,temp);  /* encrypt iv_idea, making temp. */ 
                    418: 
                    419:                if (cfb_dc_idea)        /* buf is ciphertext */
                    420:                        /* shift in ciphertext to IV... */
                    421:                        cfbshift((byte *)iv_idea,buf,chunksize,IDEABLOCKSIZE);
                    422: 
                    423:                /* convert buf via xor */
                    424:                xorbuf(buf,(byte *)temp,chunksize); /* buf now has enciphered output */
                    425: 
                    426:                if (!cfb_dc_idea)       /* buf was plaintext, is now ciphertext */
                    427:                        /* shift in ciphertext to IV... */
                    428:                        cfbshift((byte *)iv_idea,buf,chunksize,IDEABLOCKSIZE);
                    429: 
                    430:                count -= chunksize;
                    431:                buf += chunksize;
                    432:        }
                    433: } /* ideacfb */
                    434: 
                    435: 
                    436: /*
                    437:        close_idea function erases all the key schedule information when 
                    438:        we are all done with a set of operations for a particular IDEA key 
                    439:        context.  This is to prevent any sensitive data from being left 
                    440:        around in memory.
                    441: */
                    442: void close_idea(void)  /* erase current key schedule tables */
                    443: {      short r,j;
                    444:        for (r=0; r<ROUNDS+1; r++)
                    445:                for (j=0; j<6; j++)
                    446:                        keyschedule[j][r] = 0;
                    447: }      /* close_idea() */
                    448: 
                    449: /********************************************************************/
                    450: 
                    451: /*
                    452: **     These buffers are used by init_idearand, idearand, and close_idearand.
                    453: */
                    454: static word16 dtbuf_idea[4] = {0}; /* buffer for enciphered timestamp */
                    455: static word16 randseed_idea[4] = {0}; /* seed for IDEA random # generator */
                    456: static word16 randbuf_idea[4] = {0}; /* buffer for IDEA random # generator */
                    457: static byte randbuf_idea_counter = 0;  /* # of random bytes left in randbuf_idea */
                    458: 
                    459: /*
                    460: **     init_idearand - initialize idearand, IDEA random number generator.
                    461: **             Used for generating cryptographically strong random numbers.
                    462: **             Much of the design comes from Appendix C of ANSI X9.17.
                    463: **             key is pointer to IDEA key buffer.
                    464: **             seed is pointer to random number seed buffer.
                    465: **             tstamp is a 32-bit timestamp
                    466: */
                    467: void init_idearand(byte key[16], byte seed[8], word32 tstamp)
                    468: {      int i;
                    469:        initkey_idea(key, FALSE);       /* initialize IDEA */
                    470: 
                    471:        for (i=0; i<4; i++)     /* capture timestamp material */
                    472:        {       dtbuf_idea[i] = tstamp; /* get bottom byte */
                    473:                tstamp = tstamp >> 16;  /* drop bottom byte */
                    474:                /* tstamp has only 4 bytes-- last 4 bytes will always be 0 */
                    475:        }
                    476:        /* Start with enciphered timestamp: */
                    477:        idea_ecb(dtbuf_idea,dtbuf_idea);
                    478: 
                    479:        /* initialize seed material */
                    480:        for (i=0; i<8; i++)
                    481:                ((byte *)randseed_idea)[i] = seed[i];
                    482: 
                    483:        randbuf_idea_counter = 0;       /* # of random bytes left in randbuf_idea */
                    484: 
                    485: } /* init_idearand */
                    486: 
                    487: 
                    488: /*
                    489: **     idearand - IDEA pseudo-random number generator
                    490: **             Used for generating cryptographically strong random numbers.
                    491: **             Much of the design comes from Appendix C of ANSI X9.17.
                    492: */
                    493: byte idearand(void)
                    494: {      int i;
                    495:        if (randbuf_idea_counter==0)    /* if random buffer is spent...*/
                    496:        {
                    497:                /* Combine enciphered timestamp with seed material: */
                    498:                for (i=0; i<4; i++)
                    499:                        randseed_idea[i] ^= dtbuf_idea[i];
                    500:                idea_ecb(randseed_idea,randbuf_idea); /* fill new block */
                    501: 
                    502:                /* Compute new seed vector: */
                    503:                for (i=0; i<4; i++)
                    504:                        randseed_idea[i] = randbuf_idea[i] ^ dtbuf_idea[i];
                    505:                idea_ecb(randseed_idea,randseed_idea); /* fill new seed */
                    506: 
                    507:                randbuf_idea_counter = 8;       /* reset counter for full buffer */
                    508:        }
                    509:        /* Take a byte from randbuf_idea: */
                    510:        return(((byte *)randbuf_idea)[--randbuf_idea_counter]);
                    511: } /* idearand */
                    512: 
                    513: 
                    514: void close_idearand(void)
                    515: {      /* Erase random IDEA buffers and wipe out IDEA key info */
                    516:        int i;
                    517:        for (i=0; i<4; i++)
                    518:        {       randbuf_idea[i] = 0;
                    519:                randseed_idea[i] = 0;
                    520:                dtbuf_idea[i] = 0;
                    521:        }
                    522:        close_idea();   /* erase current key schedule tables */
                    523: }      /* close_idearand */
                    524: 
                    525: /* end of idea.c */

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.