home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / h / hpack78s.zip / keycvt / keycvt.c < prev    next >
C/C++ Source or Header  |  1992-11-30  |  15KB  |  573 lines

  1. /* PGP 2.0 secret key conversion utility.
  2.  
  3.    Written in one long hacking session on 7 November 1992 by
  4.      Peter Gutmann (pgut1@cs.aukuni.ac.nz).
  5.    Placed in the public domain like the PGP code itself.
  6.  
  7.    Known bugs: Doesn't handle schizophrenic keys too well.  These are caused
  8.                     by a bug in PGP 2.0.
  9.                There are several bugs in the PGP format and format docs.
  10.                     The code contains some workarounds */
  11.  
  12. #include <ctype.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <time.h>
  17. #include "mdc.h"
  18.  
  19. /* Buffering with getchar() is extremely braindamaged.  Under DOS and OS/2
  20.    we can use getch(), otherwise use the ostrich algorithm */
  21.  
  22. #ifdef __MSDOS__
  23.   int getch( void );
  24.  
  25.   #undef getchar
  26.   #define getchar    getch
  27. #endif /* __MSDOS__ */
  28.  
  29. /* Magic numbers for PGP 2.0 keyrings */
  30.  
  31. #define PGP_CTB_SECKEY        0x95    /* Secret key packet CTB */
  32. #define PGP_CTB_TRUST        0xB0    /* Trust packet */
  33. #define PGP_CTB_USERID        0xB4    /* Userid packet CTB */
  34.  
  35. #define PGP_VERSION_BYTE    2        /* Version number byte for PGP 2.0 */
  36.  
  37. #define PKE_ALGORITHM_RSA    1        /* RSA public-key encryption algorithm */
  38.  
  39. #define CKE_ALGORITHM_NONE    0        /* No CKE algorithm */
  40. #define CKE_ALGORITHM_IDEA    1        /* IDEA cipher */
  41. #define CKE_ALGORITHM_MDC    64        /* MDC cipher */
  42.  
  43. /* The size of the IDEA IV */
  44.  
  45. #define IDEA_IV_SIZE        8
  46.  
  47. /* Conversion from bitcount to bytecount */
  48.  
  49. #define bits2bytes(x)    ( ( ( x ) + 7 ) >> 3 )
  50.  
  51. /* Storage for MPI's */
  52.  
  53. #define MAX_MPI_SIZE        256
  54.  
  55. BYTE n[ MAX_MPI_SIZE ], e[ MAX_MPI_SIZE ], d[ MAX_MPI_SIZE ];
  56. BYTE p[ MAX_MPI_SIZE ], q[ MAX_MPI_SIZE ], u[ MAX_MPI_SIZE ];
  57. int nLen, eLen, dLen, pLen, qLen, uLen;
  58.  
  59. /* Information needed by the IDEA cipher */
  60.  
  61. char password[ 80 ];            /* The user's password */
  62. BYTE ideaKey[ 16 ];                /* IDEA cipher key */
  63. BYTE ideaIV[ IDEA_IV_SIZE ];    /* IDEA cipher IV */
  64.  
  65. /* Prototypes for functions in IDEA.C */
  66.  
  67. void initcfb_idea( BYTE iv[ IDEA_IV_SIZE ], BYTE ideakey[ 16 ], BOOLEAN decrypt );
  68. void ideacfb( BYTE *buffer, int count );
  69. void close_idea( void );
  70.  
  71. /* The buffers needed for the MDC encryption */
  72.  
  73. BYTE cryptBuffer[ 2048 ], outBuffer[ 1024 ];
  74.  
  75. /* Whether we've converted any keys or not */
  76.  
  77. BOOLEAN keysConverted;
  78.  
  79. /* The crc16 table and crc16 variable itself */
  80.  
  81. WORD crc16tbl[ 256 ];
  82. WORD crc16;
  83.  
  84. /* The block crc16 calculation routine.  Ideally this should be done in
  85.    assembly language for speed */
  86.  
  87. void crc16buffer( BYTE *bufPtr, int length )
  88.     {
  89.     while( length-- )
  90.         crc16 = crc16tbl[ ( BYTE ) crc16 ^ *bufPtr++ ] ^ ( crc16 >> 8 );
  91.     }
  92.  
  93. /* The initialisation routine for the crc16 table */
  94.  
  95. void initCRC16( void )
  96.     {
  97.     int bitCount, tblIndex;
  98.     WORD crcVal;
  99.  
  100.     for( tblIndex = 0; tblIndex < 256; tblIndex++ )
  101.         {
  102.         crcVal = tblIndex;
  103.         for( bitCount = 0; bitCount < 8; bitCount++ )
  104.             if( crcVal & 0x01 )
  105.                 crcVal = ( crcVal >> 1 ) ^ 0xA001;
  106.             else
  107.                 crcVal >>=  1;
  108.         crc16tbl[ tblIndex ] = crcVal;
  109.         }
  110.     }
  111. /* Routines to read BYTE, WORD, LONG */
  112.  
  113. BYTE fgetByte( FILE *inFilePtr )
  114.     {
  115.     return( getc( inFilePtr ) );
  116.     }
  117.  
  118. WORD fgetWord( FILE *inFilePtr )
  119.     {
  120.     WORD value;
  121.  
  122.     value = ( ( WORD ) getc( inFilePtr ) ) << 8;
  123.     value |= ( WORD ) getc( inFilePtr );
  124.     return( value );
  125.     }
  126.  
  127. LONG fgetLong( FILE *inFilePtr )
  128.     {
  129.     LONG value;
  130.  
  131.     value = ( ( LONG ) getc( inFilePtr ) ) << 24;
  132.     value |= ( ( LONG ) getc( inFilePtr ) ) << 16;
  133.     value |= ( ( LONG ) getc( inFilePtr ) ) << 8;
  134.     value |= ( LONG ) getc( inFilePtr );
  135.     return( value );
  136.     }
  137.  
  138. /* Routines to write BYTE, WORD, LONG */
  139.  
  140. void fputByte( FILE *outFilePtr, BYTE data )
  141.     {
  142.     putc( data, outFilePtr );
  143.     }
  144.  
  145. void fputWord( FILE *outFilePtr, WORD data )
  146.     {
  147.     putc( ( BYTE ) ( data >> 8 ), outFilePtr );
  148.     putc( ( BYTE ) data, outFilePtr );
  149.     }
  150.  
  151. void fputLong( FILE *outFilePtr, LONG data )
  152.     {
  153.     putc( ( BYTE ) ( data >> 24 ), outFilePtr );
  154.     putc( ( BYTE ) ( data >> 16 ), outFilePtr );
  155.     putc( ( BYTE ) ( data >> 8 ), outFilePtr );
  156.     putc( ( BYTE ) data, outFilePtr );
  157.     }
  158.  
  159. /* Read an MPI */
  160.  
  161. void readMPI( FILE *inFilePtr, int *mpiLen, BYTE *mpReg )
  162.     {
  163.     BYTE *regPtr;
  164.     int length;
  165.  
  166.     *mpiLen = fgetWord( inFilePtr );
  167.     length = bits2bytes( *mpiLen );
  168.     regPtr = mpReg;
  169.     while( length-- )
  170.         *regPtr++ = fgetByte( inFilePtr );
  171.     }
  172.  
  173. /* Write an MPI */
  174.  
  175. void writeMPI( FILE *outFilePtr, int mpiLen, BYTE *mpReg )
  176.     {
  177.     int length = bits2bytes( mpiLen );
  178.  
  179.     fputWord( outFilePtr, mpiLen );
  180.     while( length-- )
  181.         fputByte( outFilePtr, *mpReg++ );
  182.     }
  183.  
  184. /* Store an MPI in an in-memory buffer */
  185.  
  186. int storeMPI( BYTE *buffer, int mpiLen, BYTE *mpReg )
  187.     {
  188.     int length = bits2bytes( mpiLen );
  189.  
  190.     *buffer++ = ( BYTE ) ( mpiLen >> 8 );
  191.     *buffer++ = ( BYTE ) mpiLen;
  192.     memcpy( buffer, mpReg, length );
  193.     return( sizeof( WORD ) + length );
  194.     }
  195.  
  196. /* IDEA support code needed by convertPrivateKey().  Note that the IV must
  197.    be declared static since the IDEA code sets up a pointer to it and uses
  198.    it for storage (ick!) */
  199.  
  200. void getPassword( void )
  201.     {
  202.     puts( "Please enter password for this private key" );
  203.     printf( "Password: " );
  204.     fflush( stdout );
  205.     gets( password );
  206.     }
  207.  
  208. void initCrypt( void )
  209.     {
  210.     MD5_CTX    mdContext;
  211.     static BYTE iv[ IDEA_IV_SIZE ];
  212.  
  213.     /* Get the password from the (l)user */
  214.     getPassword();
  215.  
  216.     /* Reduce it to 128 bits using MD5 */
  217.     MD5Init( &mdContext );
  218.     MD5Update( &mdContext, ( BYTE * ) password, strlen( password ) );
  219.     MD5Final( &mdContext );
  220.  
  221.     /* Set up IDEA key */
  222.     memset( iv, 0, IDEA_IV_SIZE );
  223.     initcfb_idea( iv, mdContext.digest, TRUE );
  224.     ideacfb( ideaIV, 8 );
  225.     }
  226.  
  227. /* Skip to the start of the next key packet block */
  228.  
  229. void skipToKeyPacket( FILE *inFilePtr, const int length )
  230.     {
  231.     BYTE ctb;
  232.  
  233.     /* First skip the rest of the current packet if necessary */
  234.     if( length )
  235.         fseek( inFilePtr, length, SEEK_CUR );
  236.  
  237.     /* Now skip any following userID packets */
  238.     while( ( ctb = fgetByte( inFilePtr ) ) == PGP_CTB_USERID )
  239.         fseek( inFilePtr, fgetByte( inFilePtr ), SEEK_CUR );
  240.  
  241.     /* Finally, put back the last CTB we read */
  242.     ungetc( ctb, inFilePtr );
  243.     }
  244.  
  245. /* Convert a private key packet from PGP 1.0 to PGP 2.0 format */
  246.  
  247. WORD checksum( BYTE *data, int length )
  248.     {
  249.     WORD checkSum = ( ( BYTE ) ( length >> 8 ) ) + ( ( BYTE ) length );
  250.  
  251.     length = bits2bytes( length );
  252.     while( length-- )
  253.         checkSum += *data++;
  254.     return( checkSum );
  255.     }
  256.  
  257. void convertPrivateKey( FILE *inFilePtr, FILE *outFilePtr )
  258.     {
  259.     char userID[ 256 ];
  260.     BOOLEAN isEncrypted;
  261.     LONG timeStamp;
  262.     WORD checkSum, packetChecksum, validityPeriod;
  263.     int length, i, packetLength;
  264.     struct tm *localTime;
  265.     BYTE *outBufPtr = outBuffer, *mdcIV, *ivPtr, ctb;
  266.  
  267.     /* Skip CTB, packet length, and version byte */
  268.     if( fgetc( inFilePtr ) == EOF )
  269.         return;
  270.     packetLength = fgetWord( inFilePtr );
  271.     if( fgetByte( inFilePtr ) != PGP_VERSION_BYTE )
  272.         {
  273.         /* Unknown version number, skip this packet */
  274.         puts( "Skipping unknown packet type..." );
  275.         skipToKeyPacket( inFilePtr, packetLength - sizeof( BYTE ) );
  276.         return;
  277.         }
  278.     packetLength -= sizeof( BYTE );
  279.  
  280.     /* Read timestamp, validity period */
  281.     timeStamp = fgetLong( inFilePtr );
  282.     validityPeriod = fgetWord( inFilePtr );
  283.     packetLength -= sizeof( LONG ) + sizeof( WORD );
  284.  
  285.     /* Read public key components */
  286.     if( fgetByte( inFilePtr ) != PKE_ALGORITHM_RSA )
  287.         {
  288.         /* Unknown PKE algorithm type, skip this packet */
  289.         puts( "Skipping unknown PKE algorithm packet..." );
  290.         skipToKeyPacket( inFilePtr, packetLength - sizeof( BYTE ) );
  291.         return;
  292.         }
  293.     readMPI( inFilePtr, &nLen, n );
  294.     readMPI( inFilePtr, &eLen, e );
  295.     packetLength -= sizeof( BYTE ) + sizeof( WORD ) + bits2bytes( nLen ) + \
  296.                                      sizeof( WORD ) + bits2bytes( eLen );
  297.  
  298.     /* Handle decryption info for secret components if necessary */
  299.     if( ( ctb = fgetByte( inFilePtr ) ) == CKE_ALGORITHM_MDC )
  300.         {
  301.         puts( "Key has already been converted, skipping packet..." );
  302.         skipToKeyPacket( inFilePtr, packetLength - sizeof( BYTE ) );
  303.         return;
  304.         }
  305.     isEncrypted = ( ctb == CKE_ALGORITHM_IDEA );
  306.     if( isEncrypted )
  307.         for( i = 0; i < IDEA_IV_SIZE; i++ )
  308.             ideaIV[ i ] = fgetc( inFilePtr );
  309.     packetLength -= sizeof( BYTE ) + ( isEncrypted ) ? IDEA_IV_SIZE : 0;
  310.  
  311.     /* Read in private key components and checksum */
  312.     readMPI( inFilePtr, &dLen, d );
  313.     readMPI( inFilePtr, &pLen, p );
  314.     readMPI( inFilePtr, &qLen, q );
  315.     readMPI( inFilePtr, &uLen, u );
  316.     packetLength -= sizeof( WORD ) + bits2bytes( dLen ) + \
  317.                     sizeof( WORD ) + bits2bytes( pLen ) + \
  318.                     sizeof( WORD ) + bits2bytes( qLen ) + \
  319.                     sizeof( WORD ) + bits2bytes( uLen );
  320.     packetChecksum = fgetWord( inFilePtr );
  321.     packetLength -= sizeof( WORD );
  322.  
  323.     /* Read the userID packet */
  324.     if( ( ctb = fgetByte( inFilePtr ) ) != PGP_CTB_USERID )
  325.         {
  326.         /* Check whether we may have found a keyring trust packet (PGP bug) */
  327.         if( ctb == PGP_CTB_TRUST )
  328.             {
  329.             /* Remember it for later */
  330.             fgetByte( inFilePtr );    /* Skip length */
  331.             fgetByte( inFilePtr );    /* Skip null trust info */
  332.             ctb = fgetByte( inFilePtr );
  333.             }
  334.  
  335.         /* If we still don't have a userID CTB, complain */
  336.         if( ctb != PGP_CTB_USERID )
  337.             {
  338.             puts( "Can't find userID packet after key packet, skipping..." );
  339.             skipToKeyPacket( inFilePtr,  ( int ) fgetByte( inFilePtr ) );
  340.             return;
  341.             }
  342.         }
  343.     length = fgetByte( inFilePtr );
  344.     for( i = 0; i < length; i++ )
  345.         userID[ i ] = fgetByte( inFilePtr );
  346.     userID[ i ] = '\0';
  347.  
  348.     /* Check whether we may have found a keyring trust packet (another bug) */
  349.     if( ( ctb = fgetByte( inFilePtr ) ) == PGP_CTB_TRUST )
  350.         {
  351.         /* Remember it for later */
  352.         fgetByte( inFilePtr );    /* Skip length */
  353.         fgetByte( inFilePtr );    /* Skip null trust info */
  354.         }
  355.     else
  356.         ungetc( ctb, inFilePtr );
  357.  
  358.     /* Display the key and ask the user if they want to convert it */
  359.     localTime = localtime( ( time_t * ) &timeStamp );
  360.     printf( "%d bits, date %02d/%02d/%02d, userID %s\n", nLen, \
  361.             localTime->tm_mday, localTime->tm_mon, localTime->tm_year, \
  362.             userID );
  363.     printf( "Add information for this key so HPACK can use it (y/n) " );
  364.     if( toupper( getchar() ) == 'N' )
  365.         {
  366. #ifdef __MSDOS__
  367.         putchar( '\n' );
  368. #else
  369.         getchar();    /* Fix getchar() problem */
  370. #endif /* __MSDOS__ */
  371.         puts( "Skipping key..." );
  372.         return;
  373.         }
  374.  
  375. #ifdef __MSDOS__
  376.     putchar( '\n' );
  377. #else
  378.     getchar();    /* Try and fix some of getchar()'s problems */
  379. #endif /* __MSDOS__ */
  380.  
  381.     /* Decrypt the secret-key fields if necessary */
  382.     if( isEncrypted )
  383.         for( i = 0; ; i++ )
  384.             {
  385.             /* Attempt to decrypt the secret-key fields */
  386.             initCrypt();
  387.             ideacfb( d, bits2bytes( dLen ) );
  388.             ideacfb( p, bits2bytes( pLen ) );
  389.             ideacfb( q, bits2bytes( qLen ) );
  390.             ideacfb( u, bits2bytes( uLen ) );
  391.  
  392.             /* Make sure all was OK */
  393.             checkSum = checksum( d, dLen );
  394.             checkSum += checksum( p, pLen );
  395.             checkSum += checksum( q, qLen );
  396.             checkSum += checksum( u, uLen );
  397.             if( checkSum != packetChecksum )
  398.                 {
  399.                 /* If they still haven't got it right after 3 attempts,
  400.                    give up */
  401.                 if( i == 3 )
  402.                     {
  403.                     puts( "Can't decrypt key packet, skipping..." );
  404.                     return;
  405.                     }
  406.  
  407.                 puts( "Incorrect checksum, possibly due to incorrect password" );
  408.                 }
  409.             else
  410.                 break;
  411.             }
  412.     else
  413.         /* Get the password for encryption, since we didn't need to get one
  414.            for decryption */
  415.         getPassword();
  416.  
  417.     /* Write the PGP 2.0 header information */
  418.     fputByte( outFilePtr, PGP_CTB_SECKEY );
  419.     fputWord( outFilePtr, sizeof( BYTE ) + \
  420.                           sizeof( LONG ) + sizeof( WORD ) + sizeof( BYTE ) + \
  421.                           sizeof( WORD ) + bits2bytes( nLen ) + \
  422.                           sizeof( WORD ) + bits2bytes( eLen ) + \
  423.                           sizeof( BYTE ) + IV_SIZE + \
  424.                           sizeof( WORD ) + bits2bytes( dLen ) + \
  425.                           sizeof( WORD ) + bits2bytes( pLen ) + \
  426.                           sizeof( WORD ) + bits2bytes( qLen ) + \
  427.                           sizeof( WORD ) + bits2bytes( uLen ) + \
  428.                           sizeof( WORD ) );
  429.     fputByte( outFilePtr, PGP_VERSION_BYTE );
  430.  
  431.     /* Write timestamps, algorithm byte */
  432.     fputLong( outFilePtr, timeStamp );
  433.     fputWord( outFilePtr, validityPeriod );
  434.     fputByte( outFilePtr, PKE_ALGORITHM_RSA );
  435.  
  436.     /* Write public key components */
  437.     writeMPI( outFilePtr, nLen, n );
  438.     writeMPI( outFilePtr, eLen, e );
  439.  
  440.     /* Write secret key components */
  441.     fputByte( outFilePtr, CKE_ALGORITHM_MDC );
  442.     mdcIV = ivPtr = getIV();
  443.     for( i = 0; i < IV_SIZE; i++ )
  444.         fputByte( outFilePtr, *ivPtr++ );
  445.     outBufPtr += storeMPI( outBufPtr, dLen, d );
  446.     outBufPtr += storeMPI( outBufPtr, pLen, p );
  447.     outBufPtr += storeMPI( outBufPtr, qLen, q );
  448.     outBufPtr += storeMPI( outBufPtr, uLen, u );
  449.     length = ( int ) ( outBufPtr - outBuffer );
  450.  
  451.     /* Write secret key checksum */
  452.     crc16 = 0;
  453.     crc16buffer( outBuffer, length );
  454.     outBuffer[ length++ ] = ( BYTE ) ( crc16 >> 8 );
  455.     outBuffer[ length++ ] = ( BYTE ) crc16;
  456.  
  457.     /* Encrypt the secret key components and write them */
  458.     initKey( ( BYTE * ) password, strlen( password ), mdcIV );
  459.     encryptCFB( outBuffer, length );
  460.     fwrite( outBuffer, length, 1, outFilePtr );
  461.  
  462.     /* Write the userID packet for the preceding key */
  463.     fputByte( outFilePtr, PGP_CTB_USERID );
  464.     length = strlen( userID );
  465.     fputByte( outFilePtr, length );
  466.     for( i = 0; i < length; i++ )
  467.         fputByte( outFilePtr, userID[ i ] );
  468.  
  469.     /* Zap encryption information */
  470.     memset( password, 0, 80 );
  471.     close_idea();
  472.  
  473.     keysConverted = TRUE;
  474.     }
  475.  
  476. void main( const int argc, const char *argv[] )
  477.     {
  478.     FILE *inFilePtr, *outFilePtr;
  479.     char tempFileName[ 256 ];
  480.     long fileSize;
  481.     int ch;
  482.  
  483.     puts( "HPACK keyring format converter\n" );
  484.     if( argc == 3 )
  485.         {
  486.         if( ( inFilePtr = fopen( argv[ 1 ], "rb" ) ) == NULL )
  487.             {
  488.             perror( argv[ 1 ] );
  489.             exit( ERROR );
  490.             }
  491.         strcpy( tempFileName, argv[ 2 ] );
  492.         strcpy( tempFileName + strlen( tempFileName ) - 1, "_" );
  493.         if( ( outFilePtr = fopen( tempFileName, "wb" ) ) == NULL )
  494.             {
  495.             perror( tempFileName );
  496.             exit( ERROR );
  497.             }
  498.         }
  499.     else
  500.         {
  501.         puts( "Usage: keycvt <input keyfile> <output keyfile>" );
  502.         puts( "\nThe keyfiles are the PGP secret keyrings.  The source keyring may contain" );
  503.         puts( " one or more secret keys.  For each key you will be asked whether you" );
  504.         puts( " wish to add an HPACK-readable version to the destination keyring." );
  505.         puts( " Adding the HPACK-readable version will add an extra key packet which" );
  506.         puts( " is used by HPACK.  In normal usage the input and output keyfiles are" );
  507.         puts( " the same file." );
  508.         exit( ERROR );
  509.         }
  510.  
  511.     /* Set up CRC table */
  512.     initCRC16();
  513.  
  514.     /* Find out whether we're handling a public or private keyring */
  515.     ch = fgetc( inFilePtr );
  516.     ungetc( ch, inFilePtr );
  517.     if( ch != PGP_CTB_SECKEY )
  518.         {
  519.         printf( "%s doesn't appear to be a PGP secret key file.\n", argv[ 1 ] );
  520.         exit( ERROR );
  521.         }
  522.     else
  523.         {
  524.         /* Convert all the keys in the keyring */
  525.         keysConverted = FALSE;
  526.         while( !feof( inFilePtr ) )
  527.             {
  528.             convertPrivateKey( inFilePtr, outFilePtr );
  529.             putchar( '\n' );
  530.             }
  531.         }
  532.  
  533.     /* Check before we add the new packets to the output keyring */
  534.     fclose( inFilePtr );
  535.     fclose( outFilePtr );
  536.     if( keysConverted )
  537.         {
  538.         printf( "Finished processing keys. Add new key information to output keyring (y/n) " );
  539.         fflush( stdout );
  540.         if( toupper( getchar() ) == 'N' )
  541.             {
  542.             /* Clean up and exit */
  543.             unlink( tempFileName );
  544.             exit( ERROR );
  545.             }
  546.  
  547.         /* Append the new packets to the end of the output keyring */
  548.         if( ( inFilePtr = fopen( tempFileName, "rb" ) ) == NULL )
  549.             {
  550.             puts( "Cannot open temporary work file" );
  551.             exit( ERROR );
  552.             }
  553.         if( ( outFilePtr = fopen( argv[ 2 ], "ab" ) ) == NULL )
  554.             {
  555.             perror( argv[ 2 ] );
  556.             exit( ERROR );
  557.             }
  558.         fseek( inFilePtr, 0L, SEEK_END );
  559.         fileSize = ftell( inFilePtr );
  560.         fseek( inFilePtr, 0L, SEEK_SET );
  561.         while( fileSize-- )
  562.             fputc( fgetc( inFilePtr ), outFilePtr );
  563.         fclose( inFilePtr );
  564.         fclose( outFilePtr );
  565.         }
  566.     else
  567.         puts( "No keys converted, output file left unchanged." );
  568.  
  569.     /* Finish up */
  570.     unlink( tempFileName );
  571.     puts( "\nDone" );
  572.     }
  573.