home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / h / hpack78s.zip / crypt / crypt.c next >
C/C++ Source or Header  |  1992-11-26  |  49KB  |  1,584 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                           Encryption Interface Routines                    *
  7. *                             CRYPT.C  Updated 11/08/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *        Copyright 1990 - 1992  Peter C.Gutmann.  All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. /* "Modern cryptography is nothing more than a mathematical framework for
  19.     debating the implications of various paranoid delusions".
  20.                                                 - Don Alvarez */
  21. #include <ctype.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #ifdef __MAC__
  27.   #include "defs.h"
  28.   #include "choice.h"
  29.   #include "error.h"
  30.   #include "filesys.h"
  31.   #include "flags.h"
  32.   #include "frontend.h"
  33.   #include "hpacklib.h"
  34.   #include "hpaktext.h"
  35.   #include "system.h"
  36.   #include "crc16.h"
  37.   #include "crypt.h"
  38.   #include "md5.h"
  39.   #include "mdc.h"
  40.   #include "packet.h"
  41.   #include "rsa.h"
  42.   #include "fastio.h"
  43.   #include "hpackio.h"
  44. #else
  45.   #include "defs.h"
  46.   #include "choice.h"
  47.   #include "error.h"
  48.   #include "filesys.h"
  49.   #include "flags.h"
  50.   #include "frontend.h"
  51.   #include "hpacklib.h"
  52.   #include "system.h"
  53.   #include "crc/crc16.h"
  54.   #include "crypt/crypt.h"
  55.   #include "crypt/md5.h"
  56.   #include "crypt/mdc.h"
  57.   #include "crypt/packet.h"
  58.   #include "crypt/rsa.h"
  59.   #include "io/fastio.h"
  60.   #include "io/hpackio.h"
  61.   #include "language/hpaktext.h"
  62. #endif /* __MAC__ */
  63.  
  64. /* The environment variable where various key files hide */
  65.  
  66. #if defined( __MSDOS__ ) && ( ARCHIVE_TYPE != 1 )
  67.   #define PGPPATH                NULL
  68.   #define PEMPATH                ( NULL + 1 )
  69. #else
  70.   #define PGPPATH                "PGPPATH"    /* Env.var for PGP path */
  71.   #define PEMPATH                "PEMPATH"    /* Env.var for PEM path */
  72. #endif /* __MSDOS__ && ARCHIVE_TYPE != 1 */
  73.  
  74. /* These files use the environmental variable PGPPATH as a default path */
  75.  
  76. #ifdef __ARC__
  77. char PGP_PUBKEY_FILENAME[] = "pubring";
  78. char PGP_SECKEY_FILENAME[] = "secring";
  79. #else
  80. char PGP_PUBKEY_FILENAME[] = "pubring.pgp";
  81. char PGP_SECKEY_FILENAME[] = "secring.pgp";
  82. #endif /* __ARC__ */
  83. #define PGP_PUBKEY_FILELENGTH    ( sizeof( PGP_PUBKEY_FILENAME ) - 1 )
  84. #define PGP_SECKEY_FILELENGTH    ( sizeof( PGP_SECKEY_FILENAME ) - 1 )
  85.  
  86. /* These files use the environmental variable PEMPATH as a default path */
  87.  
  88. #ifdef __ARC__
  89. char PEM_PUBKEY_FILENAME[] = "???";
  90. char PEM_SECKEY_FILENAME[] = "???";
  91. #else
  92. char PEM_PUBKEY_FILENAME[] = "???.???";
  93. char PEM_SECKEY_FILENAME[] = "???.???";
  94. #endif /* __ARC__ */
  95. #define PEM_PUBKEY_FILELENGTH    ( sizeof( PEM_PUBKEY_FILENAME ) - 1 )
  96. #define PEM_SECKEY_FILELENGTH    ( sizeof( PEM_SECKEY_FILENAME ) - 1 )
  97.  
  98. /* These files can use either the PGP or PEM path as the default path */
  99.  
  100. #ifdef __ARC__
  101. char RANDSEED_FILENAME[] = "hpakseed";
  102. #else
  103. char RANDSEED_FILENAME[] = "hpakseed.bin";
  104. #endif /* __ARC__ */
  105. #define RANDSEED_FILELENGTH        ( sizeof( RANDSEED_FILENAME ) - 1 )
  106.  
  107. /* Symbolic defines to indicate whether we should set globalPrecision when
  108.    calling readMPI() or not */
  109.  
  110. #define SET_PRECISION        TRUE
  111. #define NO_SET_PRECISION    FALSE
  112.  
  113. /* The encryption password lengths.  A minimum length of 8 bytes provides a
  114.    reasonable level of security */
  115.  
  116. #define MIN_KEYLENGTH    8
  117. #define MAX_KEYLENGTH    80        /* Any reasonable value will do */
  118.  
  119. /* The encryption passwords */
  120.  
  121. char key[ MAX_KEYLENGTH + 1 ], secKey[ MAX_KEYLENGTH + 1 ];
  122. int keyLength = 0, secKeyLength = 0;
  123.  
  124. /* The number of password attempts the user is allowed to decrypt their
  125.    secret key */
  126.  
  127. #define PASSWORD_RETRIES    3
  128.  
  129. /* The information structure for public and private keys.  Both PEM/PKCS and
  130.    PGP key packets contain more information than this but HPACK doesn't use
  131.    any of it */
  132.  
  133. typedef struct {
  134.                /* Key status */
  135.                BOOLEAN isPemKey;            /* Whether it's a PGP or PEM key */
  136.                BOOLEAN isEncrypted;            /* Whether secret fields are encrypted */
  137.  
  138.                /* General key ID information */
  139.                char userID[ 256 ];            /* userID associated with the key */
  140.                BYTE keyID[ KEYFRAG_SIZE ];     /* keyID for the key */
  141.                char ascKeyID[ ( KEYDISPLAY_SIZE * 2 ) + 1 ];
  142.                                             /* ASCII hex keyID */
  143.                LONG timeStamp;                /* Timestamp for this key */
  144.  
  145.                /* The key itself */
  146.                MP_REG n[ MAX_UNIT_PRECISION ], e[ MAX_UNIT_PRECISION ];
  147.                                             /* Public key components */
  148.                MP_REG d[ MAX_UNIT_PRECISION ], p[ MAX_UNIT_PRECISION ], \
  149.                       q[ MAX_UNIT_PRECISION ], u[ MAX_UNIT_PRECISION ];
  150.                                             /* Secret key components */
  151.                } KEYINFO;
  152.  
  153. /* The following is defined in FRONTEND.C */
  154.  
  155. extern char choice;
  156.  
  157. /* The following are defined in MDC.C */
  158.  
  159. extern BYTE auxKey[];
  160.  
  161. /* Prototypes for functions in VIEWFILE.C */
  162.  
  163. void extractDate( const LONG time, int *date1, int *date2, int *date3, \
  164.                                    int *hours, int *minutes, int *seconds );
  165.  
  166. /* Prototypes for functions in ARCHIVE.C */
  167.  
  168. void blankLine( int length );
  169. void blankChars( int length );
  170.  
  171. /* Prototypes for functions in GUI.C */
  172.  
  173. char *getPassword( char *passWord, const char *prompt );
  174. void showSig( const BOOLEAN isGoodSig, const char *userID, const LONG timeStamp );
  175.  
  176. #ifdef __MAC__
  177. /* Prototypes for functions in MAC.C */
  178.  
  179. FD openResourceFork( const char *filePath, const int mode );
  180. void closeResourceFork( const FD theFD );
  181. #endif /* __MAC__ */
  182.  
  183. /* The random key and IV, seedFile FD, MD5 context, and position in seed
  184.    buffer used for public-key encryption */
  185.  
  186. BYTE mdcKey[ BLOCKSIZE ];
  187. BYTE seedIV[ BLOCKSIZE ];    /* Needed for non-interference with main IV */
  188. FD seedFileFD = ERROR;        /* No seedfile to begin with */
  189. MD5_CTX mdSeedContext;
  190. int seedPos = BLOCKSIZE;    /* Always reseed generator */
  191.  
  192. /* The general-purpose crypto buffer */
  193.  
  194. BYTE *cryptBuffer = NULL;
  195.  
  196. #if CRYPT_BUFSIZE < ( MAX_BYTE_PRECISION * 33 )
  197.   #error Need to increase CRYPT_BUFSIZE
  198. #endif /* Safety check for size of crypto buffer */
  199.  
  200. /* The keyInfo structures for the encryption and digital signature keys (made
  201.    global to save on stack space, especially with very long keys) */
  202.  
  203. KEYINFO cryptKeyInfo, signKeyInfo;
  204.  
  205. /****************************************************************************
  206. *                                                                            *
  207. *                         Initialise the Encryption System                     *
  208. *                                                                            *
  209. ****************************************************************************/
  210.  
  211. #ifndef GUI
  212.  
  213. char *getPassword( char *passWord, const char *prompt )
  214.     {
  215.     int i;
  216.     char ch;
  217.  
  218.     while( TRUE )
  219.         {
  220.         hprintf( prompt );
  221.  
  222.         /* Get a password string */
  223.         i = 0;
  224.         while( ( ch = hgetch() ) != '\r' && ch != '\n' )
  225.             {
  226.             /* Handle backspace key.  The way this is handled is somewhat
  227.                messy, since hitting BS at the last char position deletes
  228.                the previous char */
  229.             if( ch == '\b' )
  230.                 {
  231.                 if( i )
  232.                     i--;
  233.                 else
  234.                     hputchar( '\007' );
  235.                 continue;
  236.                 }
  237.  
  238.             if( i == MAX_KEYLENGTH )
  239.                 hputchar( '\007' );
  240.             else
  241.                 passWord[ i++ ] = ch;
  242.             }
  243.  
  244.         /* Exit if format is valid */
  245.         if( i >= MIN_KEYLENGTH )
  246.             break;
  247.  
  248.         hputs( MESG_KEY_INCORRECT_LENGTH );
  249.         }
  250.  
  251.     passWord[ i ] = '\0';
  252.     blankLine( screenWidth - 1 );
  253.  
  254.     return( passWord );
  255.     }
  256. #endif /* !GUI */
  257.  
  258. /* Set up the encryption password */
  259.  
  260. void initPassword( const BOOLEAN isMainKey )
  261.     {
  262.     char key1[ MAX_KEYLENGTH + 1 ], key2[ MAX_KEYLENGTH + 1 ];
  263.     BOOLEAN exitNow = FALSE;
  264.  
  265.     /* Set up the password */
  266.     getPassword( key1, ( isMainKey ) ? MESG_ENTER_PASSWORD : MESG_ENTER_SEC_PASSWORD );
  267.     if( choice == ADD || choice == FRESHEN || choice == REPLACE || choice == UPDATE )
  268.         exitNow = strcmp( key1, getPassword( key2, MESG_REENTER_TO_CONFIRM ) );
  269.  
  270.     /* Set up the appropriate encryption key */
  271.     if( isMainKey )
  272.         {
  273.         strcpy( key, key1 );
  274.         keyLength = strlen( key );
  275.         }
  276.     else
  277.         {
  278.         strcpy( secKey, key1 );
  279.         secKeyLength = strlen( key );
  280.         }
  281.  
  282.     /* Scrub temporary passwords */
  283.     memset( key1, 0, MAX_KEYLENGTH + 1 );
  284.     memset( key2, 0, MAX_KEYLENGTH + 1 );
  285.  
  286.     if( exitNow )
  287.         error( PASSWORDS_NOT_SAME );
  288.     }
  289.  
  290. /* Clear out the ID fields of a public key */
  291.  
  292. static void clearIDfields( KEYINFO *keyInfo )
  293.     {
  294.     memset( keyInfo->userID, 0, sizeof( keyInfo->userID ) );
  295.     memset( keyInfo->keyID, 0, sizeof( keyInfo->keyID ) );
  296.     memset( keyInfo->ascKeyID, 0, sizeof( keyInfo->ascKeyID ) );
  297.     }
  298.  
  299. /* Initialise the encryption system */
  300.  
  301. void initCrypt( void )
  302.     {
  303.     /* Allocate general-purpose crypt buffer */
  304.     if( ( cryptBuffer = hmalloc( CRYPT_BUFSIZE ) ) == NULL )
  305.         error( OUT_OF_MEMORY );
  306.  
  307.     /* Clear out ID fields in PKC keys */
  308.     clearIDfields( &cryptKeyInfo );
  309.     clearIDfields( &signKeyInfo );
  310.     }
  311.  
  312. /* Shut down the encryption system */
  313.  
  314. void endCrypt( void )
  315.     {
  316.     /* Clear the MDC Mysterious Constants if necessary by resetting them to
  317.        the normal MD5 values */
  318.     MD5SetConst( NULL );
  319.  
  320.     /* Write the random MDC seed to the seedFile if necessary */
  321.     if( seedFileFD != ERROR )
  322.         {
  323.         /* Step the MD5 RNG to hide the previous key, then write it to the
  324.            seed file */
  325.         MD5Update( &mdSeedContext, mdcKey, BLOCKSIZE );
  326.         MD5Final( &mdSeedContext );
  327.         hlseek( seedFileFD, 0L, SEEK_SET );
  328.         hwrite( seedFileFD, mdSeedContext.digest, BLOCKSIZE );
  329.         hclose( seedFileFD );
  330.         }
  331.  
  332.     /* Scrub the encryption keys so other users can't find them by examining
  333.        core after HPACK has run */
  334.     memset( key, 0, MAX_KEYLENGTH + 1 );
  335.     memset( secKey, 0, MAX_KEYLENGTH + 1 );
  336.     memset( mdcKey, 0, BLOCKSIZE );
  337.     memset( auxKey, 0, MD5_BLOCKSIZE );
  338.     memset( &cryptKeyInfo, 0, sizeof( KEYINFO ) );
  339.     memset( &signKeyInfo, 0, sizeof( KEYINFO ) );
  340.  
  341.     /* Scrub the cryptBuffer if we've allocated it */
  342.     if( cryptBuffer != NULL )
  343.         {
  344.         memset( cryptBuffer, 0, CRYPT_BUFSIZE );
  345.         hfree( cryptBuffer );
  346.         }
  347.     }
  348.  
  349. /* Delete a file (if we're using encryption, "annihilate" would be a better
  350.    term) */
  351.  
  352. void wipeFile( const char *filePath )
  353.     {
  354.     FILEINFO fileInfo;
  355.     long fileSize, count;
  356.     char renameFilePath[ MAX_PATH ];
  357.     FD wipeFileFD;
  358. #ifdef __MAC__
  359.     FD resourceForkFD;
  360. #endif /* __MAC__ */
  361.  
  362.     /* Perform a simple delete if we're not encrypting the data */
  363.     if( !( flags & CRYPT ) )
  364.         {
  365.         hunlink( filePath );
  366.         return;
  367.         }
  368.  
  369.     /* If we're encrypting the data, we need to comprehensively destroy the
  370.        file.  We do this by getting its size, overwriting it with a pattern
  371.        of ones and zeroes, breaking it up into sector-size chunks (presumably
  372.        scattered all over the disk), resetting its attributes and timestamp
  373.        to zero, renaming it to 'X', and finally deleting it.  The most anyone
  374.        can ever recover from this is that there was once some file on the disk
  375.        which HPACK has now deleted */
  376.     findFirst( filePath, ALLFILES_DIRS, &fileInfo );
  377.     findEnd( &fileInfo );
  378.     fileSize = fileInfo.fSize;
  379.     hchmod( filePath, CREAT_ATTR );        /* Make sure we can get at the file */
  380.     if( ( wipeFileFD = hopen( filePath, O_WRONLY ) ) != IO_ERROR )
  381.         {
  382.         /* Overwrite the data with a pattern of ones and zeroes */
  383.         memset( _outBuffer, 0xAA, _BUFSIZE );
  384.         for( count = 0; count < fileSize; count++ )
  385.             {
  386.             hwrite( wipeFileFD, _outBuffer, ( count + _BUFSIZE < fileSize ) ? \
  387.                     _BUFSIZE : ( int ) ( fileSize - count ) );
  388.             count += _BUFSIZE;
  389.             }
  390.  
  391.         /* Truncate the file every 512 bytes to break up the linked chain of
  392.            sectors */
  393.         for( count = fileSize & ~0x1FFL; count >= 0; count -= 512 )
  394.             {
  395.             hlseek( wipeFileFD, count, SEEK_SET );
  396.             htruncate( wipeFileFD );
  397.             }
  398. #ifdef __MAC__
  399.         /* Wipe the resource fork as well */
  400.         if( ( resourceForkFD = openResourceFork( filePath, O_WRONLY ) ) != IO_ERROR )
  401.             {
  402.             for( count = 0; count < fileSize; count++ )
  403.                 {
  404.                 hwrite( resourceForkFD, _outBuffer, ( count + _BUFSIZE < fileSize ) ? \
  405.                         _BUFSIZE : fileSize - count );
  406.                 count += _BUFSIZE;
  407.                 }
  408.             for( count = fileSize; count >= 0; count -= 512 )
  409.                 {
  410.                 hlseek( resourceForkFD, count, SEEK_SET );
  411.                 htruncate( resourceForkFD );
  412.                 }
  413.             closeResourceFork( resourceForkFD );
  414.             }
  415. #endif /* __MAC__ */
  416.         hclose( wipeFileFD );
  417.         }
  418.  
  419.     /* Rename the file, reset it's timestamp to zero, and delete it.  If a
  420.        file called 'X' already exists we just do it to the original file.
  421.        Note that the setting of the date can have interesting effects if the
  422.        epoch predates the epoch of the host filesystem */
  423.     strcpy( renameFilePath, filePath );
  424.     strcpy( findFilenameStart( renameFilePath ), "X" );
  425.     if( hrename( filePath, renameFilePath ) != IO_ERROR )
  426.         {
  427.         setFileTime( renameFilePath, 0L );
  428.         hunlink( renameFilePath );
  429.         }
  430.     else
  431.         {
  432.         setFileTime( filePath, 0L );
  433.         hunlink( filePath );
  434.         }
  435.     }
  436.  
  437. /****************************************************************************
  438. *                                                                            *
  439. *                        General Encryption I/O Routines                        *
  440. *                                                                            *
  441. ****************************************************************************/
  442.  
  443. /* Endianness-reverse an MPI */
  444.  
  445. static void byteReverse( BYTE *regPtr, int count )
  446.     {
  447.     int sourceCount = 0;
  448.     BYTE temp;
  449.  
  450.     /* Swap endianness of MPI */
  451.     for( count--; count > sourceCount; count--, sourceCount++ )
  452.         {
  453.         temp = regPtr[ sourceCount ];
  454.         regPtr[ sourceCount ] = regPtr[ count ];
  455.         regPtr[ count ] = temp;
  456.         }
  457.     }
  458.  
  459. #ifdef BIG_ENDIAN
  460.  
  461. /* Endianness-reverse the words in an MPI */
  462.  
  463. static void wordReverse( BYTE *regPtr, int count )
  464.     {
  465.     BYTE temp;
  466.     int i;
  467.  
  468.     for( i = 0; i < count; i += sizeof( WORD ) )
  469.         {
  470.         temp = regPtr[ i ];
  471.         regPtr[ i ] = regPtr[ i + 1 ];
  472.         regPtr[ i + 1 ] = temp;
  473.         }
  474.     }
  475. #endif /* BIG_ENDIAN */
  476.  
  477. /* Get the length of a packet.  If it's an HPACK packet we have to make sure
  478.    we calculate the checksum on the header bytes, if it's a PGP packet we
  479.    need to look out for longer packet types */
  480.  
  481. static int getPacketLength( const BYTE ctb )
  482.     {
  483.     /* If reading a PGP packet we don't calculate a checksum, and need to
  484.        take longer packet types into account */
  485.     if( ctbLength( ctb ) == CTB_LEN_BYTE )
  486.         return( ( int ) fgetByte() );
  487.     else
  488.         if( ctbLength( ctb ) == CTB_LEN_WORD )
  489.             return( ( int ) fgetWord() );
  490.         else
  491.             return( ( int ) fgetLong() );
  492.     }
  493.  
  494. static int getCheckPacketLength( const BYTE ctb )
  495.     {
  496.     BYTE buffer[ sizeof( BYTE ) + sizeof( BYTE ) ];
  497.  
  498.     /* If reading an HPACK packet we need to calculate a checksum on the
  499.        packet header as we read it */
  500.     crc16 = 0;
  501.     buffer[ 0 ] = ctb;
  502.     buffer[ 1 ] = fgetByte();
  503.     crc16buffer( buffer, sizeof( BYTE ) + sizeof( BYTE ) );
  504.     return( ( int ) buffer[ 1 ] );
  505.     }
  506.  
  507. /* Read a MPI in the form of a byte array preceded by a 16-bit bitcount from
  508.    a file or memory into a multiprecision register */
  509.  
  510. static int readMPI( MP_REG *mpReg, BOOLEAN doSetPrecision )
  511.     {
  512.     int count, byteCount;
  513.     BYTE *regPtr = ( BYTE * ) mpReg;
  514.     WORD bitCount;
  515.  
  516.     /* Read in the MPI itself from the file.  First, read in the bit count
  517.        and set the global precision accordingly */
  518.     mp_init( mpReg, 0 );
  519.     bitCount = fgetWord();
  520.     if( ( count = byteCount = bits2bytes( bitCount ) ) > MAX_BYTE_PRECISION )
  521.         /* Impossibly long MPI value */
  522.         return( ERROR );
  523.     if( doSetPrecision )
  524.         /* Set the precision to that specified by the number read */
  525.         setPrecision( bits2units( bitCount + SLOP_BITS ) );
  526.  
  527. #ifdef _BIG_ENDIAN
  528.     /* Read in the value */
  529.     while( count-- )
  530.         *regPtr++ = fgetByte();
  531. #else
  532.     /* Read in the value with endianness reversal */
  533.     regPtr += count - 1;
  534.     while( count-- )
  535.         *regPtr-- = fgetByte();
  536. #endif /* BIG_ENDIAN */
  537.  
  538.     /* Return number of bytes processed */
  539.     return( byteCount + sizeof( WORD ) );
  540.     }
  541.  
  542. static int getMPI( BYTE *buffer, MP_REG *mpReg )
  543.     {
  544.     int count, byteCount;
  545.     BYTE *regPtr = ( BYTE * ) mpReg;
  546.  
  547.     /* Get the MPI from an in-memory buffer.  We don't need to bother with
  548.        setting the precision since this has already been done */
  549.     mp_init( mpReg, 0 );
  550.     if( ( count = byteCount = bits2bytes( mgetWord( buffer ) ) ) > MAX_BYTE_PRECISION )
  551.         /* Impossibly long MPI value */
  552.         return( ERROR );
  553.     buffer += sizeof( WORD );
  554.  
  555.     /* Read in the value with endianness reversal */
  556.     regPtr += count - 1;
  557.     while( count-- )
  558.         *regPtr-- = *buffer++;
  559.  
  560.     /* Return number of bytes processed */
  561.     return( byteCount + sizeof( WORD ) );
  562.     }
  563.  
  564. /* Decrypt the encrypted fields of a previously-read key packet */
  565.  
  566. BYTE keyBuffer[ ( 4 * MAX_BYTE_PRECISION ) + sizeof( WORD ) ];
  567. BYTE keyIV[ IV_SIZE ];
  568. int keyBufSize;
  569.  
  570. static BOOLEAN decryptKeyPacket( KEYINFO *keyInfo )
  571.     {
  572.     BYTE decryptBuffer[ ( 4 * MAX_BYTE_PRECISION ) + sizeof( WORD ) ];
  573.     char keyPassword[ MAX_KEYLENGTH + 1 ];
  574.     WORD savedCRC16 = crc16;
  575.     int i, j, k, l;
  576.  
  577.     /* Try and decrypt the key information */
  578.     for( i = 0; i < PASSWORD_RETRIES; i++ )
  579.         {
  580.         getPassword( keyPassword, MESG_ENTER_SECKEY_PASSWORD );
  581.         initKey( ( BYTE * ) keyPassword, strlen( keyPassword ), keyIV );
  582.  
  583.         /* Read in key and try to decrypt it */
  584.         memcpy( decryptBuffer, keyBuffer, keyBufSize );
  585.         decryptCFB( decryptBuffer, keyBufSize );
  586.         crc16 = 0;
  587.         crc16buffer( decryptBuffer, keyBufSize - sizeof( WORD ) );
  588.         if( crc16 != mgetWord( decryptBuffer + keyBufSize - sizeof( WORD ) ) )
  589. #ifdef GUI
  590.             alert( ALERT_PASSWORD_INCORRECT, NULL );
  591. #else
  592.             hputs( MESG_PASSWORD_INCORRECT );
  593. #endif /* GUI */
  594.         else
  595.             /* Key was successfully decrypted, exit */
  596.             break;
  597.         }
  598.  
  599.     /* Restore callers checksum information */
  600.     crc16 = savedCRC16;
  601.  
  602.     /* If we couldn't get the password, invaldiate key and give up */
  603.     if( i == PASSWORD_RETRIES )
  604.         return( FALSE );
  605.  
  606.     /* Get information from buffer */
  607.     i = getMPI( decryptBuffer, keyInfo->d );
  608.     j = getMPI( decryptBuffer + i, keyInfo->p );
  609.     k = getMPI( decryptBuffer + i + j, keyInfo->q );
  610.     l = getMPI( decryptBuffer + i + j + k, keyInfo->u );
  611.  
  612.     /* Check for possible problems in reading MPI's */
  613.     if( ( i | j | k | l ) == ERROR )
  614.         error( BAD_KEYFILE );
  615.  
  616. #ifdef BIG_ENDIAN
  617.     /* Perform an endianness-reversal if necessary */
  618.     wordReverse( ( BYTE * ) keyInfo->d, globalPrecision * sizeof( MP_REG ) );
  619.     wordReverse( ( BYTE * ) keyInfo->p, globalPrecision * sizeof( MP_REG ) );
  620.     wordReverse( ( BYTE * ) keyInfo->q, globalPrecision * sizeof( MP_REG ) );
  621.     wordReverse( ( BYTE * ) keyInfo->u, globalPrecision * sizeof( MP_REG ) );
  622. #endif /* BIG_ENDIAN */
  623.  
  624.     keyInfo->isEncrypted = FALSE;    /* Key is now decrypted */
  625.     return( TRUE );
  626.     }
  627.  
  628. /* Read in a key packet from a file.  It will return the ctb, timestamp,
  629.    userid, keyID, public key components n and e, and private key components
  630.    d, p, q and u if necessary.  The strategy we use is to keep parsing data
  631.    until we find a userID, then return.   Since userID's always follow keys,
  632.    and since there can be multiple keys attached to each userID, each call
  633.    yields a new userID (but not necessarily a new key) */
  634.  
  635. #define IS_PUBLICKEY    FALSE    /* Whether we should try to read secret fields */
  636. #define IS_SECRETKEY    TRUE
  637.  
  638. static BOOLEAN readKeyPacket( BOOLEAN isSecretKey, KEYINFO *keyInfo )
  639.     {
  640.     int ctb;
  641.     WORD certLength;
  642.     int i, j, k, l;
  643.     BOOLEAN needMoreInfo = TRUE, gotKeyPacket = TRUE;
  644.     BYTE ch;
  645.  
  646.     /* Keep reading packets until we have a key packet and userID packet we
  647.        can use */
  648.     while( needMoreInfo )
  649.         {
  650.         /*  Get key certificate CTB and length info */
  651.         if( ( ctb = fgetByte() ) == FEOF )
  652.             break;
  653.         certLength = getPacketLength( ctb );
  654.  
  655.         /* If it's a userID packet, read the ID */
  656.         switch( ctb )
  657.             {
  658.             case CTB_USERID:
  659.                 /* Get userID as Pascal string (I am NAN!) */
  660.                 for( i = 0; i < certLength; i++ )
  661.                     keyInfo->userID[ i ] = fgetByte();
  662.                 keyInfo->userID[ i ] = '\0';
  663.                 certLength = 0;
  664.  
  665.                 /* Work out whether we can exit now or not */
  666.                 if( gotKeyPacket )
  667.                     needMoreInfo = FALSE;
  668.                 break;
  669.  
  670.             case CTB_CERT_PUBKEY:
  671.             case CTB_CERT_SECKEY:
  672.                 /* Get version byte, return if it was created by a version
  673.                    we don't know how to handle */
  674.                 gotKeyPacket = FALSE;        /* We haven't decoded the packet yet */
  675.                 certLength -= sizeof( BYTE );
  676.                 if( fgetByte() != PGP_VERSION )
  677.                     break;
  678.  
  679.                 /* Get timestamp, validity period, and PKE algorithm ID */
  680.                 certLength -= sizeof( LONG ) + sizeof( WORD ) + sizeof( BYTE );
  681.                 keyInfo->timeStamp = fgetLong();
  682.                 fgetWord();
  683.                 if( fgetByte() != PKE_ALGORITHM_RSA )
  684.                     break;
  685.  
  686.                 /* We're past certificate headers, get initial key material */
  687.                 i = readMPI( keyInfo->n, SET_PRECISION );
  688.                 j = readMPI( keyInfo->e, NO_SET_PRECISION );
  689.                 certLength -= i + j;
  690.  
  691.                 /* Copy the keyID from the low bits of n, convert it to
  692.                    ASCII hex, and perform an endianness reversal if necessary */
  693.                 memcpy( keyInfo->keyID, keyInfo->n, KEYFRAG_SIZE );
  694.                 for( k = KEYDISPLAY_SIZE - 1, l = 0; k >= 0; k-- )
  695.                     {
  696.                     ch = ( keyInfo->keyID[ k ] >> 4 ) + '0';
  697.                     keyInfo->ascKeyID[ l++ ] = ( ch <= '9' ) ? ch : ch + 'A' - '9' - 1;
  698.                     ch = ( keyInfo->keyID[ k ] & 0x0F ) + '0';
  699.                     keyInfo->ascKeyID[ l++ ] = ( ch <= '9' ) ? ch : ch + 'A' - '9' - 1;
  700.                     }
  701.                 keyInfo->ascKeyID[ l ] = '\0';
  702. #ifdef BIG_ENDIAN
  703.                 wordReverse( ( BYTE * ) keyInfo->n, globalPrecision * sizeof( MP_REG ) );
  704.                 wordReverse( ( BYTE * ) keyInfo->e, globalPrecision * sizeof( MP_REG ) );
  705. #endif /* BIG_ENDIAN */
  706.  
  707.                 /* Check for possible problems in reading MPI's */
  708.                 if( ( i | j ) == ERROR )
  709.                     error( BAD_KEYFILE );
  710.  
  711.                 /* Read the secret key fields if necessary */
  712.                 keyInfo->isEncrypted = FALSE;
  713.                 if( isSecretKey )
  714.                     {
  715.                     /* Check if we can process the following MPI fields */
  716.                     certLength -= sizeof( BYTE );
  717.                     if( ( ctb = fgetByte() ) != CKE_ALGORITHM_NONE )
  718.                         {
  719.                         /* If we can't decrypt the remainder of the
  720.                            information, skip it */
  721.                         if( ctb != CKE_ALGORITHM_MDC )
  722.                             break;
  723.  
  724.                         /* Get decryption information for the key, and the
  725.                            encrypted key itself */
  726.                         for( i = 0; i < IV_SIZE; i++ )
  727.                             keyIV[ i ] = fgetByte();
  728.                         certLength -= IV_SIZE;
  729.                         for( i = 0; i < certLength; i++ )
  730.                             keyBuffer[ i ] = fgetByte();
  731.                         keyBufSize = certLength;
  732.  
  733.                         certLength = 0;
  734.                         keyInfo->isEncrypted = TRUE;
  735.                         }
  736.  
  737.                     /* Read key fields if they're non-encrypted */
  738.                     if( !keyInfo->isEncrypted )
  739.                         {
  740.                         /* Get information from file */
  741.                         i = readMPI( keyInfo->d, NO_SET_PRECISION );
  742.                         j = readMPI( keyInfo->p, NO_SET_PRECISION );
  743.                         k = readMPI( keyInfo->q, NO_SET_PRECISION );
  744.                         l = readMPI( keyInfo->u, NO_SET_PRECISION );
  745.  
  746.                         /* Check for possible problems in reading MPI's */
  747.                         if( ( i | j | k | l ) == ERROR )
  748.                             error( BAD_KEYFILE );
  749.  
  750.                         fgetWord();        /* Skip checksum */
  751.                         certLength -= i + j + k + l + sizeof( WORD );
  752. #ifdef BIG_ENDIAN
  753.                         /* Perform an endianness-reversal if necessary */
  754.                         wordReverse( ( BYTE * ) keyInfo->d, globalPrecision * sizeof( MP_REG ) );
  755.                         wordReverse( ( BYTE * ) keyInfo->p, globalPrecision * sizeof( MP_REG ) );
  756.                         wordReverse( ( BYTE * ) keyInfo->q, globalPrecision * sizeof( MP_REG ) );
  757.                         wordReverse( ( BYTE * ) keyInfo->u, globalPrecision * sizeof( MP_REG ) );
  758. #endif /* BIG_ENDIAN */
  759.                         }
  760.                     }
  761.  
  762.                 /* Now we've got a valid key packet */
  763.                 gotKeyPacket = TRUE;
  764.             }
  765.  
  766.         /* Skip rest of this key certificate */
  767.         if( certLength )
  768.             skipSeek( ( LONG ) certLength );
  769.         }
  770.  
  771.     /* Return TRUE if we've got a packet, FALSE otherwise */
  772.     return( ctb != FEOF );
  773.     }
  774.  
  775. /* Get the public or private key corresponding to a given keyID/userID from
  776.    the public/private key file */
  777.  
  778. #define IS_KEYID    TRUE
  779. #define IS_USERID    FALSE
  780.  
  781. #define IS_PEM_KEY    TRUE
  782. #define IS_PGP_KEY    FALSE
  783.  
  784. static BOOLEAN getKey( const BOOLEAN isPemKey, const BOOLEAN isSecretKey, \
  785.                        const BOOLEAN isKeyID, char *keyFileName, \
  786.                        BYTE *wantedID, KEYINFO *keyInfo )
  787.     {
  788.     FD keyFileFD, savedInFD = getInputFD();
  789.     BOOLEAN matched, firstTime = TRUE;
  790.     char *matchID, firstChar;
  791.     int userIDlength, i;
  792.  
  793.     /* Open key file */
  794.     if( ( keyFileFD = hopen( keyFileName, O_RDONLY | S_DENYWR ) ) == IO_ERROR )
  795.         return( FALSE );
  796.     setInputFD( keyFileFD );
  797.     resetFastIn();
  798.  
  799.     /* Set up key type information */
  800.     keyInfo->isPemKey = isPemKey;
  801.  
  802.     /* Set up userID info if necessary */
  803.     if( !isKeyID )
  804.         {
  805.         /* Check for a hexadecimal userID, signifying the user wants to
  806.            match by hex ASCII keyID and not by userID */
  807.         if( !strnicmp( ( char * ) wantedID, "0x", 2 ) )
  808.             {
  809.             wantedID += 2;
  810.             matchID = keyInfo->ascKeyID;
  811.             }
  812.         else
  813.             matchID = keyInfo->userID;
  814.  
  815.         userIDlength = strlen( ( char * ) wantedID );
  816.         firstChar = toupper( *wantedID );
  817.         }
  818.  
  819.     /* Grovel through the file looking for the key */
  820.     while( TRUE )
  821.         {
  822.         /* Try and read a key packet, unless its the first time through
  823.            the loop in which case the information may already be in memory */
  824.         if( !firstTime && !readKeyPacket( isSecretKey, keyInfo ) )
  825.             break;
  826.         firstTime = FALSE;
  827.  
  828.         matched = FALSE;
  829.         if( isKeyID )
  830.             {
  831.             /* wantedID contains key fragment, check it against n from keyfile */
  832.             if( !memcmp( wantedID, keyInfo->keyID, KEYFRAG_SIZE ) )
  833.                 matched = TRUE;
  834.             }
  835.         else
  836.             /* wantedID contains partial userID, check it against userID from keyfile */
  837.             for( i = 0; matchID[ i ]; i++ )
  838.                 if( ( toupper( matchID[ i ] ) == firstChar ) && \
  839.                     !strnicmp( ( char * ) wantedID, matchID + i, userIDlength ) )
  840.                     matched = TRUE;
  841.  
  842.         /* Found key matching ID */
  843.         if( matched )
  844.             {
  845.             /* If it's a secret key, try and decrypt it */
  846.             if( keyInfo->isEncrypted && !decryptKeyPacket( keyInfo ) )
  847.                 {
  848.                 /* Couldn't decrypt, invalidate key ID fields so we don't
  849.                    match the key the next time around, and continue */
  850.                 clearIDfields( keyInfo );
  851.                 continue;
  852.                 }
  853.  
  854.             /* Got valid key, clean up and exit */
  855.             hclose( keyFileFD );
  856.             setInputFD( savedInFD );
  857.             return( TRUE );
  858.             }
  859.         }
  860.  
  861.     /* Couldn't find key */
  862.     hclose( keyFileFD );
  863.     setInputFD( savedInFD );
  864.     return( FALSE );
  865.     }
  866.  
  867. /* Build the path to a keyring file */
  868.  
  869. static BOOLEAN buildKeyringPath( char *keyFileName, const char *keyringName, \
  870.                                  const int keyringNameLength )
  871.     {
  872.     char *pgpPath;
  873.     BOOLEAN hasPath = FALSE;
  874.     int i;
  875.  
  876.     *keyFileName = '\0';
  877.     if( ( pgpPath = getenv( PGPPATH ) ) != NULL )
  878.         {
  879.         if( strlen( pgpPath ) + keyringNameLength > MAX_PATH )
  880.             error( PATH_ss_TOO_LONG, pgpPath, keyringName );
  881.         strcpy( keyFileName, pgpPath );
  882.         if( ( i = keyFileName[ strlen( keyFileName ) - 1 ] ) != '/' && i != '\\' )
  883.             /* Add trailing slash if necessary */
  884.             strcat( keyFileName, "/" );
  885.         hasPath = TRUE;
  886.         }
  887.     strcat( keyFileName, keyringName );
  888.  
  889.     return( hasPath );
  890.     }
  891.  
  892. /* Generate a cryptographically strong random MDC key */
  893.  
  894. static BYTE *getStrongRandomKey( void )
  895.     {
  896.     char keyFileName[ MAX_PATH ];
  897.     BOOLEAN hasPath;
  898.  
  899.     /* Open the MDC seed file if we need to */
  900.     if( seedFileFD == ERROR )
  901.         {
  902.         /* Build path to seed file and read in the key */
  903.         hasPath = buildKeyringPath( keyFileName, RANDSEED_FILENAME, RANDSEED_FILELENGTH );
  904.         if( ( ( seedFileFD = hopen( keyFileName, O_RDWR | S_DENYRDWR ) ) == ERROR && \
  905.               !( hasPath && ( seedFileFD = hopen( RANDSEED_FILENAME, O_RDWR | S_DENYRDWR ) ) != ERROR ) ) || \
  906.             ( hread( seedFileFD, mdcKey, BLOCKSIZE ) < BLOCKSIZE ) )
  907.             {
  908.             seedFileFD = ERROR;
  909.             error( CANNOT_READ_RANDOM_SEEDFILE );
  910.             }
  911.         }
  912.  
  913.     /* Step the MD5 RNG and init the MDC system with the random key */
  914.     MD5Init( &mdSeedContext );
  915.     MD5Update( &mdSeedContext, mdcKey, BLOCKSIZE );
  916.     MD5Final( &mdSeedContext );
  917.     memcpy( mdcKey, mdSeedContext.digest, BLOCKSIZE );
  918.     initKey( mdcKey, BLOCKSIZE, DEFAULT_IV );
  919.  
  920.     return( mdcKey );
  921.     }
  922.  
  923. /* Return cryptographically strong random BYTE, WORD, LONG.  This code
  924.    assumes initKey() has already been called, which is always the case
  925.    in HPACK */
  926.  
  927. BYTE getStrongRandomByte( void )
  928.     {
  929.     BYTE *auxKey = cryptBuffer;        /* Used in mdcTransform */
  930.  
  931.     /* Step the MDC RNG if necessary */
  932.     if( seedPos == BLOCKSIZE )
  933.         {
  934.         /* Transform the seedIV, with the cryptBuffer as the auxKey.  It
  935.            doesn't really matter what's in it */
  936.         mdcTransform( seedIV );
  937.         seedPos = 0;
  938.         }
  939.  
  940.     return( mdcKey[ seedPos++ ] );
  941.     }
  942.  
  943. WORD getStrongRandomWord( void )
  944.     {
  945.     /* Note that although both sides of the '|' have side-effects, we're not
  946.        particularly worried about the order of evaluation */
  947.     return( ( ( WORD ) getStrongRandomByte() << 8 ) | getStrongRandomByte() );
  948.     }
  949.  
  950. LONG getStrongRandomLong( void )
  951.     {
  952.     return( ( ( LONG ) getStrongRandomWord() << 16 ) | getStrongRandomWord() );
  953.     }
  954.  
  955. /* Get the first/next userID in a list of userID's.  Since PGP doesn't
  956.    currently implement mailing lists, this is a fairly simple-minded process
  957.    of pulling subsequent userID's from a comma-seperated list.  In future
  958.    this will be expanded to handle full mailing lists as soon as some
  959.    mechanism is defined in PGP */
  960.  
  961. char *userIDlistPos, userIDvalue[ 255 ];
  962.  
  963. BOOLEAN getNextUserID( char **userID )
  964.     {
  965.     char *userIDlistPtr = userIDlistPos;
  966.     int length;
  967.  
  968.     /* Extract the next userID from the list.  When there is a proper
  969.        mailing list mechanism defined this will simply involve returning
  970.        a pointer to the next name in a linked list */
  971.     while( *userIDlistPtr && *userIDlistPtr != ',' )
  972.         userIDlistPtr++;
  973.     length = ( int ) ( userIDlistPtr - userIDlistPos );
  974.     strncpy( userIDvalue, userIDlistPos, length );
  975.     userIDvalue[ length ] = '\0';
  976.     *userID = userIDvalue;
  977.     if( *userIDlistPtr == ',' )
  978.         userIDlistPtr++;    /* Skip comma separator */
  979.     userIDlistPos = userIDlistPtr;
  980.  
  981.     return( ( *userIDlistPos ) ? TRUE : FALSE );
  982.     }
  983.  
  984. BOOLEAN getFirstUserID( char **userID, const BOOLEAN isMainKey )
  985.     {
  986.     userIDlistPos = ( isMainKey ) ? mainUserID : secUserID;
  987.     return( getNextUserID( userID ) );
  988.     }
  989.  
  990. /****************************************************************************
  991. *                                                                            *
  992. *                        Data Authentication Routines                        *
  993. *                                                                            *
  994. ****************************************************************************/
  995.  
  996. /* Calculate the MD5 message digest for a section of a file */
  997.  
  998. static void md5file( const long startPos, long noBytes, MD5_CTX *mdContext )
  999.     {
  1000.     int bytesToProcess;
  1001.  
  1002.     /* Calculate the message digest for the data */
  1003.     vlseek( startPos, SEEK_SET );
  1004.     MD5Init( mdContext );
  1005.     while( noBytes )
  1006.         {
  1007.         bytesToProcess = ( noBytes < _BUFSIZE ) ? \
  1008.                          ( int ) noBytes : _BUFSIZE;
  1009.         vread( _inBuffer, bytesToProcess );
  1010.         noBytes -= bytesToProcess;
  1011.  
  1012.         /* Calculate the MD5 checksum for the buffer contents */
  1013.         MD5Update( mdContext, _inBuffer, bytesToProcess );
  1014.         }
  1015.     MD5Final( mdContext );
  1016.     }
  1017.  
  1018. /* Convert plaintext message into an integer less than the modulus n by
  1019.    making it 1 byte shorter than the normalized modulus, as per PKCS #1,
  1020.    Section 8.  Since padding is easier for little-endian MPI's, we initially
  1021.    reverse the MPI to make it little-endian and then perform the padding */
  1022.  
  1023. #define BLOCKTYPE_PUBLIC    TRUE
  1024. #define BLOCKTYPE_PRIVATE    FALSE
  1025.  
  1026. static void preblock( BYTE *regPtr, int byteCount, MP_REG *modulus, BOOLEAN padOpPublic )
  1027.     {
  1028.     int bytePrecision, leadingZeroes, blockSize, padSize;
  1029.  
  1030.     /* Reverse the initial MPI */
  1031.     byteReverse( regPtr, byteCount );
  1032.  
  1033.     /* Calculate no.leading zeroes and blocksize (incl.data plus pad bytes) */
  1034.     bytePrecision = units2bytes( globalPrecision );
  1035.     leadingZeroes = bytePrecision - countbytes( modulus ) + 1;
  1036.     blockSize = bytePrecision - leadingZeroes;
  1037.  
  1038.     /* Calculate number of padding bytes (-2 is for leading 0, trailing 1) */
  1039.     padSize = blockSize - byteCount - 2;
  1040.  
  1041.     /* Perform padding as per PKCS #1 and RFC 1115 to generate the octet
  1042.        string EB = 00 BT PS 00 D */
  1043.     regPtr[ byteCount++ ] = 0;
  1044.     while( padSize-- )
  1045.         regPtr[ byteCount++ ] = ( padOpPublic ) ? getStrongRandomByte() : 0xFF;
  1046.     regPtr[ byteCount++ ] = padOpPublic ? BT_PUBLIC : BT_PRIVATE;
  1047.  
  1048.     /* Add leading zeroes */
  1049.     while( leadingZeroes-- )
  1050.         regPtr[ byteCount++ ] = 0;
  1051.  
  1052. #ifdef BIG_ENDIAN
  1053.     /* Swap endianness of padded MPI */
  1054.     wordReverse( regPtr, byteCount );
  1055. #endif /* BIG_ENDIAN */
  1056.     }
  1057.  
  1058. /* Reverse the above blocking operation */
  1059.  
  1060. static void postunblock( BYTE *regPtr, int count )
  1061.     {
  1062. #ifdef BIG_ENDIAN
  1063.     /* First reverse the individual words */
  1064.     wordReverse( regPtr, count );
  1065. #endif /* BIG_ENDIAN */
  1066.  
  1067.     /* Bytereverse the data */
  1068.     byteReverse( regPtr, count );
  1069.     }
  1070.  
  1071. /* Check a block of data's signature */
  1072.  
  1073. BOOLEAN checkSignature( LONG startPos, LONG noBytes )
  1074.     {
  1075.     char keyFileName[ MAX_PATH ];
  1076.     BYTE decryptedSignature[ MAX_BYTE_PRECISION ];
  1077.     BYTE *mdInfo = decryptedSignature + sizeof( BYTE ) + sizeof( BYTE );
  1078.     LONG timeStamp;
  1079.     MP_REG signature[ MAX_UNIT_PRECISION ];    /* MP_REG's are now long-aligned */
  1080.     BYTE wantedID[ KEYFRAG_SIZE ];
  1081.     MD5_CTX mdContext;
  1082.     int i;
  1083.     BOOLEAN hasPath, badSig = FALSE;
  1084. #ifndef GUI
  1085.     int time1, time2, time3, hours, minutes, seconds;
  1086. #endif /* !GUI */
  1087.  
  1088.     /* Build path to keyring file */
  1089.     hasPath = buildKeyringPath( keyFileName, PGP_PUBKEY_FILENAME, PGP_PUBKEY_FILELENGTH );
  1090.  
  1091.     /* Set up checksumming for rest of packet */
  1092.     checksumSetInput( ( long ) getCheckPacketLength( fgetByte() ), NO_RESET_CHECKSUM );
  1093.  
  1094.     /* Make sure we know how to check this signature */
  1095.     if( fgetByte() != SIG_ALGORITHM_RSA )
  1096.         {
  1097.         /* Don't know how to handle this signature scheme, complain and
  1098.            process file anyway */
  1099. #ifdef GUI
  1100.         alert( ALERT_CANT_FIND_PUBLIC_KEY, NULL );
  1101. #else
  1102.         hputs( WARN_CANT_FIND_PUBLIC_KEY );
  1103. #endif /* GUI */
  1104.         return( TRUE );
  1105.         }
  1106.  
  1107.     /* Copy rest of key fragment */
  1108.     for( i = 0; i < KEYFRAG_SIZE; i++ )
  1109.         wantedID[ i ] = fgetByte();
  1110.  
  1111.     /* Get signed message digest, first, setting precision to max.value to be
  1112.        on the safe side */
  1113.     setPrecision( MAX_UNIT_PRECISION );
  1114.     i = readMPI( signature, NO_SET_PRECISION );
  1115.     if( i == ERROR || fgetWord() != crc16 )
  1116.         {
  1117.         /* Authentication information bad or corrupted, complain and process
  1118.            file anyway */
  1119. #ifdef GUI
  1120.         alert( ALERT_SEC_INFO_CORRUPTED, NULL );
  1121. #else
  1122.         hputs( WARN_SEC_INFO_CORRUPTED );
  1123. #endif /* GUI */
  1124.         return( FALSE );
  1125.         }
  1126.  
  1127.     /* Perform a context switch from the general input buffer */
  1128.     saveInputState();
  1129.  
  1130.     /* Use wantedID prefix to get and validate public key from a key file.
  1131.        Check for the keyFile both on the key paths (if they exist) and in the
  1132.        current directory */
  1133.     if( !( getKey( IS_PGP_KEY, IS_PUBLICKEY, IS_KEYID, keyFileName, wantedID, &signKeyInfo ) || \
  1134.          ( hasPath && getKey( IS_PGP_KEY, IS_PUBLICKEY, IS_KEYID, PGP_PUBKEY_FILENAME, wantedID, &signKeyInfo ) ) ) )
  1135.         {
  1136.         /* Can't get public key, complain and process file anyway */
  1137. #ifdef GUI
  1138.         alert( ALERT_CANT_FIND_PUBLIC_KEY, NULL );
  1139. #else
  1140.         hputs( WARN_CANT_FIND_PUBLIC_KEY );
  1141. #endif /* GUI */
  1142.         restoreInputState();    /* Switch back to the general input buffer */
  1143.         return( TRUE );
  1144.         }
  1145.  
  1146.     /* Recover message digest via public key */
  1147. #ifdef BIG_ENDIAN
  1148.     wordReverse( ( BYTE * ) signature, globalPrecision * sizeof( MP_REG ) );
  1149. #endif /* BIG_ENDIAN */
  1150.     mp_modexp( ( MP_REG * ) decryptedSignature, signature, signKeyInfo.e, signKeyInfo.n );
  1151.     postunblock( decryptedSignature, MD_PACKET_LENGTH );
  1152.  
  1153.     /* Look at nested stuff within RSA block and make sure it's the correct
  1154.        message digest algorithm */
  1155.     if( ctbType( decryptedSignature[ 0 ] ) != CTBTYPE_MD || \
  1156.                  decryptedSignature[ 1 ] != MD_INFO_LENGTH || \
  1157.                  decryptedSignature[ 2 ] != MD_ALGORITHM_MD5 )
  1158.         {
  1159.         badSig = TRUE;        /* Bad RSA decrypt */
  1160.         timeStamp = 0L;        /* Can't establish timestamp for data */
  1161.         }
  1162.     else
  1163.         {
  1164.         /* Extract date and compute message digest for rest of file */
  1165.         timeStamp = mgetLong( mdInfo + MD_TIME_OFS );
  1166.         setInputFD( archiveFD );
  1167.         md5file( startPos, noBytes, &mdContext );
  1168.         }
  1169.  
  1170.     /* Switch back to the general input buffer */
  1171.     restoreInputState();
  1172.  
  1173.     /* Check that everything matches */
  1174.     if( badSig || memcmp( mdContext.digest, mdInfo + MD_DIGEST_OFS, 16 ) )
  1175.         {
  1176.         badSig = TRUE;
  1177. #ifdef GUI
  1178.         showSig( FALSE, signKeyInfo.userID, timeStamp );
  1179. #else
  1180.         hprintf( MESG_BAD_SIGNATURE );
  1181. #endif /* GUI */
  1182.         }
  1183.     else
  1184. #ifdef GUI
  1185.         showSig( TRUE, signKeyInfo.userID, timeStamp );
  1186. #else
  1187.         hprintf( MESG_GOOD_SIGNATURE );
  1188.     extractDate( timeStamp, &time1, &time2, &time3, &hours, &minutes, &seconds );
  1189.     if( timeStamp )
  1190.         hprintf( MESG_SIGNATURE_FROM_s_DATE_dddddd, \
  1191.                  signKeyInfo.userID, time1, time2, time3, hours, minutes, seconds );
  1192.     else
  1193.         hprintf( MESG_SIGNATURE_FROM_s_DATE_dddddd, signKeyInfo.userID, 0, 0, 0, 0, 0, 0 );
  1194. #endif /* GUI */
  1195.  
  1196.     return( !badSig );        /* Return status of signature */
  1197.     }
  1198.  
  1199. /* Create a signature for a block of data */
  1200.  
  1201. int createSignature( LONG startPos, LONG noBytes, char *wantedID )
  1202.     {
  1203.     char keyFileName[ MAX_PATH ];
  1204.     LONG timeStamp;
  1205.     MD5_CTX MD;
  1206.     MP_REG buffer2[ MAX_UNIT_PRECISION ];
  1207.     BYTE buffer1[ MAX_BYTE_PRECISION ], *bufPtr = buffer1 + sizeof( BYTE ) + sizeof( BYTE );
  1208.     int bitCount, byteCount, i;
  1209.     BOOLEAN hasPath;
  1210.  
  1211.     /* Build path to keyring file */
  1212.     hasPath = buildKeyringPath( keyFileName, PGP_SECKEY_FILENAME, PGP_SECKEY_FILELENGTH );
  1213.  
  1214.     /* Get the secret key, setting precision to max value to be on the safe
  1215.        side.  Check for the keyFile both on the key paths (if they exist) and
  1216.        in the current directory */
  1217.     setPrecision( MAX_UNIT_PRECISION );
  1218.     if( !( getKey( IS_PGP_KEY, IS_SECRETKEY, IS_USERID, keyFileName, ( BYTE * ) wantedID, &signKeyInfo ) || \
  1219.          ( hasPath && getKey( IS_PGP_KEY, IS_SECRETKEY, IS_USERID, PGP_SECKEY_FILENAME, ( BYTE * ) wantedID, &signKeyInfo ) ) ) )
  1220.         error( CANNOT_FIND_SECRET_KEY_FOR_s, wantedID );
  1221.  
  1222.     /* Build the packet header */
  1223.     buffer1[ 0 ] = CTB_MD;
  1224.     buffer1[ 1 ] = MD_INFO_LENGTH;
  1225.     buffer1[ 2 ] = MD_ALGORITHM_MD5;
  1226.  
  1227.     /* Generate the message digest for the data and add it to the packet */
  1228.     setInputFD( archiveFD );
  1229.     md5file( startPos, noBytes, &MD );
  1230.     memcpy( bufPtr + MD_DIGEST_OFS, MD.digest, 16 );
  1231.  
  1232.     /* Add the timestamp */
  1233.     time( ( time_t * ) &timeStamp );
  1234.     mputLong( bufPtr + MD_TIME_OFS, timeStamp );
  1235.  
  1236.     /* Pre-block mdPacket */
  1237.     preblock( buffer1, MD_INFO_LENGTH + 2, signKeyInfo.n, BLOCKTYPE_PRIVATE );
  1238.  
  1239.     /* Perform the RSA signature calculation */
  1240. #ifndef GUI
  1241.     hprintf( MESG_WAIT );
  1242.     hflush( stdout );
  1243. #endif /* !GUI */
  1244.     rsaDecrypt( buffer2, ( MP_REG * ) buffer1, \
  1245.                 signKeyInfo.d, signKeyInfo.p, signKeyInfo.q, signKeyInfo.u );
  1246. #ifndef GUI
  1247.     blankChars( strlen( MESG_WAIT ) );
  1248. #endif /* !GUI */
  1249. #ifdef BIG_ENDIAN
  1250.     wordReverse( ( BYTE * ) buffer2, globalPrecision * sizeof( MP_REG ) );
  1251. #endif /* BIG_ENDIAN */
  1252.  
  1253.     /* Calculate the size of the MPI needed to store the signature */
  1254.     bitCount = countbits( buffer2 );
  1255.     byteCount = bits2bytes( bitCount );
  1256.  
  1257.     /* Create the full signature packet */
  1258.     checksumBegin( RESET_CHECKSUM );
  1259.     fputByte( CTB_SKE );            /* Write header */
  1260.     fputByte( sizeof( BYTE ) + KEYFRAG_SIZE + ( 2 + ( BYTE ) byteCount ) );
  1261.     fputByte( SIG_ALGORITHM_RSA );
  1262.     for( i = 0; i < KEYFRAG_SIZE; i++ )    /* Write key ID */
  1263.         fputByte( signKeyInfo.keyID[ i ] );
  1264.     fputWord( bitCount );            /* Write signature as MPI */
  1265.     bufPtr = ( BYTE * ) buffer2 + byteCount - 1;
  1266.     for( i = 0; i < byteCount; i++ )
  1267.         fputByte( *bufPtr-- );
  1268.     checksumEnd();
  1269.     fputWord( crc16 );                /* Write packet checksum */
  1270.  
  1271.     return( sizeof( BYTE ) + sizeof( BYTE ) + sizeof( BYTE ) + \
  1272.             KEYFRAG_SIZE + ( 2 + byteCount ) + sizeof( WORD ) );
  1273.     }
  1274.  
  1275. /****************************************************************************
  1276. *                                                                            *
  1277. *                        Public-Key Encryption Routines                        *
  1278. *                                                                            *
  1279. ****************************************************************************/
  1280.  
  1281. static int pkeEncrypt( BYTE *pkePacket, const char *wantedID, BYTE *keyInfo )
  1282.     {
  1283.     char keyFileName[ MAX_PATH ];
  1284.     MP_REG buffer2[ MAX_UNIT_PRECISION ];
  1285.     BOOLEAN hasPath;
  1286.     BYTE buffer1[ MAX_BYTE_PRECISION ], *buf2ptr;
  1287.     int count, byteCount;
  1288.  
  1289.     /* Build path to keyring file */
  1290.     hasPath = buildKeyringPath( keyFileName, PGP_PUBKEY_FILENAME, PGP_PUBKEY_FILELENGTH );
  1291.  
  1292.     /* Use userID to get and validate public key from a key file.  Check for
  1293.        the keyFile both on the key paths (if they exist) and in the current
  1294.        directory */
  1295.     setPrecision( MAX_UNIT_PRECISION );
  1296.     if( !( getKey( IS_PGP_KEY, IS_PUBLICKEY, IS_USERID, keyFileName, ( BYTE * ) wantedID, &cryptKeyInfo ) || \
  1297.          ( hasPath && getKey( IS_PGP_KEY, IS_PUBLICKEY, IS_USERID, PGP_PUBKEY_FILENAME, ( BYTE * ) wantedID, &cryptKeyInfo ) ) ) )
  1298.         error( CANNOT_FIND_PUBLIC_KEY_FOR_s, wantedID );
  1299.  
  1300.     /* Copy the algorithm ID and keyID to the PKE packet */
  1301.     *pkePacket++ = PKE_ALGORITHM_RSA;
  1302.     memcpy( pkePacket, cryptKeyInfo.keyID, KEYFRAG_SIZE );
  1303.     pkePacket += KEYFRAG_SIZE;
  1304.  
  1305.     /* Assemble a CKE info packet and pre-block it */
  1306.     buffer1[ 0 ] = CTB_CKEINFO;
  1307.     buffer1[ 1 ] = sizeof( BYTE ) + BLOCKSIZE;
  1308.     buffer1[ 2 ] = CKE_ALGORITHM_MDC;
  1309.     memcpy( buffer1 + 3, keyInfo, BLOCKSIZE );
  1310.     preblock( buffer1, sizeof( BYTE ) + sizeof( BYTE ) + sizeof( BYTE ) + BLOCKSIZE, \
  1311.               cryptKeyInfo.n, BLOCKTYPE_PUBLIC );
  1312.  
  1313.     /* Now encrypt the crap out of it */
  1314.     mp_modexp( buffer2, ( MP_REG * ) buffer1, cryptKeyInfo.e, cryptKeyInfo.n );
  1315. #ifdef BIG_ENDIAN
  1316.     wordReverse( ( BYTE * ) buffer2, globalPrecision * sizeof( MP_REG ) );
  1317. #endif /* BIG_ENDIAN */
  1318.  
  1319.     /* Calculate the size of the MPI needed to store the data */
  1320.     count = countbits( buffer2 );
  1321.     byteCount = bits2bytes( count );
  1322.  
  1323.     /* Write MPI to PKE packet with endianness reversal */
  1324.     mputWord( pkePacket, count );
  1325.     pkePacket += sizeof( WORD );
  1326.     buf2ptr = ( BYTE * ) buffer2 + ( byteCount - 1 );
  1327.     count = byteCount;
  1328.     while( count-- )
  1329.         *pkePacket++ = *buf2ptr--;
  1330.  
  1331.     return( sizeof( BYTE ) + KEYFRAG_SIZE + sizeof( WORD ) + byteCount );
  1332.     }
  1333.  
  1334. static BOOLEAN pkeDecrypt( MP_REG *pkePacket, BYTE *wantedID, BYTE *decryptedMPI )
  1335.     {
  1336.     char keyFileName[ MAX_PATH ];
  1337.     BOOLEAN hasPath, foundKey = TRUE;
  1338.  
  1339.     /* Build path to keyring file */
  1340.     hasPath = buildKeyringPath( keyFileName, PGP_SECKEY_FILENAME, PGP_SECKEY_FILELENGTH );
  1341.  
  1342.     /* Perform a context switch from the general input buffer */
  1343.     saveInputState();
  1344.  
  1345.     /* Get the secret key (the precision has already been set when the
  1346.        pkePacket was read).  Check for the keyFile both on the key paths (if
  1347.        they exist) and in the current directory */
  1348.     if( !( getKey( IS_PGP_KEY, IS_SECRETKEY, IS_KEYID, keyFileName, wantedID, &cryptKeyInfo ) || \
  1349.          ( hasPath && getKey( IS_PGP_KEY, IS_SECRETKEY, IS_KEYID, PGP_SECKEY_FILENAME, wantedID, &cryptKeyInfo ) ) ) )
  1350.         foundKey = FALSE;
  1351.  
  1352.     /* Switch back to the general input buffer */
  1353.     restoreInputState();
  1354.  
  1355.     /* Leave now if we couldn't find a matching key (there may be one in a
  1356.        following PKE packet) */
  1357.     if( !foundKey )
  1358.         return( FALSE );
  1359.  
  1360.     /* Recover CKE packet */
  1361. #ifndef GUI
  1362.     hprintf( MESG_WAIT );
  1363.     hflush( stdout );
  1364. #endif /* !GUI */
  1365. #ifdef BIG_ENDIAN
  1366.     wordReverse( ( BYTE * ) pkePacket, globalPrecision * sizeof( MP_REG ) );
  1367. #endif /* BIG_ENDIAN */
  1368.     rsaDecrypt( ( MP_REG * ) decryptedMPI, pkePacket, \
  1369.                 cryptKeyInfo.d, cryptKeyInfo.p, cryptKeyInfo.q, cryptKeyInfo.u );
  1370.     postunblock( decryptedMPI, PKE_PACKET_LENGTH );
  1371. #ifndef GUI
  1372.     blankChars( strlen( MESG_WAIT ) );
  1373. #endif /* !GUI */
  1374.     return( TRUE );
  1375.     }
  1376.  
  1377. /****************************************************************************
  1378. *                                                                            *
  1379. *                Encryption/Security Packet Management Routines                *
  1380. *                                                                            *
  1381. ****************************************************************************/
  1382.  
  1383. /* Parse an encryption information packet */
  1384.  
  1385. BOOLEAN getEncryptionInfo( int *length )
  1386.     {
  1387.     BYTE decryptedMPI[ MAX_BYTE_PRECISION ], keyID[ KEYFRAG_SIZE ], ctb;
  1388.     MP_REG pkePacket[ MAX_UNIT_PRECISION ];
  1389.     BOOLEAN packetOK = TRUE, morePackets = TRUE, foundKey = FALSE;
  1390.     int dataLength, totalLength = 0, i;
  1391.     BYTE iv[ IV_SIZE ];
  1392.  
  1393.     while( packetOK && morePackets )
  1394.         {
  1395.         /* Pull apart the security info to see what we've got */
  1396.         if( !isCTB( ctb = fgetByte() ) )
  1397.             {
  1398.             packetOK = FALSE;
  1399.             break;
  1400.             }
  1401.         if( !hasMore( ctb ) )
  1402.             morePackets = FALSE;
  1403.         dataLength = getCheckPacketLength( ctb );
  1404.         checksumSetInput( ( long ) dataLength, NO_RESET_CHECKSUM );
  1405.         totalLength += sizeof( BYTE ) + sizeof( BYTE );
  1406.  
  1407.         /* Process the encryption information packet unless we've already
  1408.            found the key we were looking for */
  1409.         if( !foundKey )
  1410.             switch( ctbType( ctb ) )
  1411.                 {
  1412.                 case CTBTYPE_PKE:
  1413.                     /* Public-key encryption packet.  First, skip the length
  1414.                        field and make sure it's a known PKE algorithm */
  1415.                     totalLength += sizeof( BYTE );
  1416.                     dataLength -= sizeof( BYTE );
  1417.                     if( fgetByte() != PKE_ALGORITHM_RSA )
  1418.                         {
  1419.                         packetOK = FALSE;
  1420.                         break;
  1421.                         }
  1422.  
  1423.                     /* If we've guessed at the archive being block encrypted with
  1424.                        a CKE, change this to a PKE */
  1425.                     if( cryptFlags & CRYPT_CKE_ALL )
  1426.                         cryptFlags ^= CRYPT_CKE_ALL | CRYPT_PKE_ALL;
  1427.  
  1428.                     /* Read in key ID fragment and ckePacket, setting the
  1429.                        precision to the max.precision to be on the safe side */
  1430.                     for( i = 0; i < KEYFRAG_SIZE; i++ )
  1431.                         keyID[ i ] = fgetByte();
  1432.                     setPrecision( MAX_UNIT_PRECISION );
  1433.                     i += readMPI( pkePacket, SET_PRECISION );
  1434.                     totalLength += i;    /* Adjust for KEYFRAG and MPI size */
  1435.                     dataLength -= i;
  1436.  
  1437.                     /* Try and decrypt the MPI containing the CKE info packet */
  1438.                     if( !pkeDecrypt( pkePacket, keyID, decryptedMPI ) )
  1439.                         break;
  1440.                     foundKey = TRUE;    /* We've found a usable key */
  1441.  
  1442.                     /* Now process the conventional-key information packet.
  1443.                        First make sure it's the right packet, skip its length
  1444.                        info, and make sure it's a known CKE algorithm */
  1445.                     if( decryptedMPI[ 0 ] != CTB_CKEINFO || \
  1446.                         decryptedMPI[ 2 ] != CKE_ALGORITHM_MDC )
  1447.                         {
  1448.                         packetOK = FALSE;
  1449.                         break;
  1450.                         }
  1451.  
  1452.                     /* Finally, we have the CKE keying information and can
  1453.                        perform the necessary setup operations with it */
  1454.                     initKey( decryptedMPI + 3, BLOCKSIZE, DEFAULT_IV );
  1455.                     break;
  1456.  
  1457.                 case CTBTYPE_CKE:
  1458.                     /* Conventional-key encryption packet.  Make sure it's a
  1459.                        known algorithm, and rekey the encryption system if
  1460.                        necessary */
  1461.                     foundKey = TRUE;    /* We've found a usable key */
  1462.                     totalLength += sizeof( BYTE ) + IV_SIZE;
  1463.                     dataLength -= sizeof( BYTE ) + IV_SIZE;
  1464.                     if( ( ctb = fgetByte() ) == CKE_ALGORITHM_MDC_R )
  1465.                         {
  1466.                         /* If we don't have a secondary password yet, get it now */
  1467.                         if( !secKeyLength )
  1468.                             initPassword( SECONDARY_KEY );
  1469.  
  1470.                         for( i = 0; i < IV_SIZE; i++ )
  1471.                             iv[ i ] = fgetByte();
  1472.                         initKey( ( BYTE * ) secKey, secKeyLength, iv );
  1473.                         }
  1474.                     else
  1475.                         if( ctb == CKE_ALGORITHM_MDC )
  1476.                             {
  1477.                             /* If we don't have a password yet, get it now */
  1478.                             if( !keyLength )
  1479.                                 initPassword( MAIN_KEY );
  1480.  
  1481.                             for( i = 0; i < IV_SIZE; i++ )
  1482.                                 iv[ i ] = fgetByte();
  1483.                             initKey( ( BYTE * ) key, keyLength, iv );
  1484.                             }
  1485.                         else
  1486.                             packetOK = FALSE;
  1487.                     break;
  1488.  
  1489.                 default:
  1490.                     /* Unknown encryption packet */
  1491.                     packetOK = FALSE;
  1492.                 }
  1493.  
  1494.         /* Read any unread bytes still in the packet, or skip the packet
  1495.            entirely if we've already found the key we were looking for */
  1496.         if( dataLength )
  1497.             {
  1498.             totalLength += dataLength;
  1499.             while( dataLength-- )
  1500.                 fgetByte();
  1501.             }
  1502.  
  1503.         /* Make sure the packet wasn't corrupted */
  1504.         totalLength += sizeof( WORD );
  1505.         if( fgetWord() != crc16 )
  1506.             {
  1507.             packetOK = FALSE;
  1508.             totalLength = 0;    /* Length may be corrupted - need to perform error recovery */
  1509.             }
  1510.         }
  1511.  
  1512.     /* If we haven't been able to find a matching key for a PKE packet, complain */
  1513.     if( !foundKey && packetOK )
  1514.         error( CANNOT_FIND_SECRET_KEY );
  1515.  
  1516.     *length = totalLength;
  1517.     return( packetOK );
  1518.     }
  1519.  
  1520. /* Write an encryption information packet to a file */
  1521.  
  1522. int putEncryptionInfo( const BOOLEAN isMainKey )
  1523.     {
  1524.     int cryptInfoLength, packetLength, i;
  1525.     BYTE pkePacket[ sizeof( BYTE ) + KEYFRAG_SIZE + sizeof( WORD ) + MAX_BYTE_PRECISION ];
  1526.     BYTE iv[ IV_SIZE ], *randomKey;
  1527.     BOOLEAN moreKeys, keyPresent;
  1528.     char *userID;
  1529.  
  1530.     if( cryptFlags & ( CRYPT_CKE | CRYPT_CKE_ALL ) )
  1531.         {
  1532.         checksumBegin( RESET_CHECKSUM );
  1533.  
  1534.         /* Write a conventional-key encryption information packet:
  1535.            CTB, length, algorithm ID, IV */
  1536.         memcpy( iv, getIV(), IV_SIZE );
  1537.         fputByte( CTB_CKE );
  1538.         fputByte( sizeof( BYTE ) + IV_SIZE );
  1539.         fputByte( ( isMainKey ) ? CKE_ALGORITHM_MDC : CKE_ALGORITHM_MDC_R );
  1540.         for( i = 0; i < IV_SIZE; i++ )
  1541.             fputByte( iv[ i ] );
  1542.         checksumEnd();
  1543.         fputWord( crc16 );
  1544.         cryptInfoLength = sizeof( BYTE ) + sizeof( BYTE ) + \
  1545.                           sizeof( BYTE ) + IV_SIZE + sizeof( WORD );
  1546.         initKey( ( isMainKey ) ? ( BYTE * ) key : ( BYTE * ) secKey, keyLength, iv );
  1547.         }
  1548.     else
  1549.         {
  1550.         cryptInfoLength = 0;
  1551.         moreKeys = getFirstUserID( &userID, isMainKey );
  1552.         keyPresent = TRUE;
  1553.         randomKey = getStrongRandomKey();
  1554.         do
  1555.             {
  1556.             checksumBegin( RESET_CHECKSUM );
  1557.  
  1558.             /* Write a public-key encryption information packet: CTB, length,
  1559.                algorithm ID, keyID, encrypted CKE info packet */
  1560.             if( moreKeys )
  1561.                 fputByte( CTB_PKE | CTB_MORE );
  1562.             else
  1563.                 {
  1564.                 fputByte( CTB_PKE );
  1565.                 keyPresent = FALSE;
  1566.                 }
  1567.             packetLength = pkeEncrypt( pkePacket, userID, randomKey );
  1568.             fputByte( ( BYTE ) packetLength );
  1569.             for( i = 0; i < packetLength; i++ )
  1570.                 fputByte( pkePacket[ i ] );
  1571.             checksumEnd();
  1572.             fputWord( crc16 );
  1573.             cryptInfoLength += sizeof( BYTE ) + sizeof( BYTE ) + \
  1574.                                packetLength + sizeof( WORD );
  1575.  
  1576.             /* Look for another keyID */
  1577.             moreKeys = getNextUserID( &userID );
  1578.             }
  1579.         while( keyPresent );
  1580.         }
  1581.  
  1582.     return( cryptInfoLength );
  1583.     }
  1584.