home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / vbasic / Data / Utils / XZipComp.exe / XceedEncryption.Cab / F112986_RSASign.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-07-04  |  14.4 KB  |  423 lines

  1. /* Xceed Encryption Library - RSASign Sample Application
  2.  * Copyright (c) 2001 Xceed Software Inc.
  3.  *
  4.  * [RSASign.cpp]
  5.  *
  6.  * This console application shows how to sign a file or a message. 
  7.  * It specifically demonstrates:
  8.  *  - The SetRandomKeyPair, ReadFile and Sign methods.
  9.  *  - The Signature, PrivateKey and SigningMethod properties.
  10.  *
  11.  * [Example]
  12.  *
  13.  * To generate a pair of private and public keys of strength 512:
  14.  *   RSASIGN /g=512 PRIVATE.TXT PUBLIC.TXT
  15.  *
  16.  * To sign file "HELLO.BMP" from private key stored in 
  17.  * hexadecimal in file "PRIVATE.TXT", and write resulting
  18.  * signature in "HELLO.SIG":
  19.  *   RSASIGN HELLO.BMP PRIVATE.TXT HELLO.SIG
  20.  *   
  21.  * This file is part of the Xceed Encryption Library sample 
  22.  * applications. The source code in this file is only intended as 
  23.  * a supplement to Xceed Encryption Library's documentation, 
  24.  * and is provided "as is", without warranty of any kind, either 
  25.  * expressed or implied. 
  26.  */
  27.  
  28. #include "stdafx.h"
  29. #include "RSASign.h"
  30.  
  31. #include "utility.h"
  32.  
  33. //
  34. // Entry point of the application
  35. //
  36.  
  37. int main(int argc, char* argv[])
  38. {
  39.   CoInitialize( NULL );
  40.  
  41.   try
  42.   {
  43.     // Create an instance of the XceedSigning coclass, and
  44.     // use the "I" interface which manipulates byte arrays instead of
  45.     // Variants as the "D" interface does.
  46.     IXceedSigningPtr piSign;
  47.     piSign.CreateInstance( CLSID_XceedSigning );
  48.  
  49.     // Parameter values we want to grab
  50.     short   nKeyPairSize  = 0;
  51.     _bstr_t bstrInputFileName;
  52.     _bstr_t bstrSignatureFileName;
  53.     bool    bGenerateKeyPair  = false;
  54.  
  55.     // Extract the command line parameters and initialize the Signing 
  56.     // instance according to the user specification. After this call
  57.     // the Signing instance piSign is ready to sign.
  58.     if( !ExtractParameters( argc, argv, 
  59.                             piSign,
  60.                             nKeyPairSize, 
  61.                             bstrInputFileName, 
  62.                             bstrSignatureFileName,
  63.                             bGenerateKeyPair ) )
  64.     {
  65.       // There's been an error extracting the command-line parameters or the
  66.       // user requested some help.
  67.       ShowHelp();
  68.       return 1;
  69.     }
  70.  
  71.     if( bGenerateKeyPair )
  72.     {
  73.       // The user wants to generate a key pair. The bstrInputFileName and
  74.       // bstrSignatureFileName variables respectively contain the private
  75.       // key filename and public key filename.
  76.  
  77.       GenerateKeyPair( piSign, nKeyPairSize, bstrInputFileName, bstrSignatureFileName );
  78.     }
  79.     else if( bstrInputFileName.length() == 0 )
  80.     {
  81.       // An input file name was not provided by the user.
  82.       // Get the source from the console
  83.  
  84.       SignConsoleInput( piSign, bstrSignatureFileName );
  85.     }
  86.     else
  87.     {
  88.       // An input file name was provided by the user.
  89.       // Read the input file and sign
  90.  
  91.       SignInputFile( piSign, bstrInputFileName, bstrSignatureFileName );
  92.     }
  93.   }
  94.   catch( const _com_error& err )
  95.   {
  96.     // When using the "#import" directive, the compiler generates wrapper classes
  97.     // around all interface types. These wrapper classes throw exceptions when
  98.     // a method call returns an HRESULT which is a failure code.
  99.     printf( "Error %08x: %s\n", err.Error(), ( const char* )err.Description() );
  100.   }
  101.   catch( const char* pszError )
  102.   {
  103.     // We also throw string exceptions ourselves!
  104.     printf( "Error: %s\n", pszError );
  105.   }
  106.   catch( ... )
  107.   {
  108.     // Catch any other exceptions
  109.     printf( "An unknown error occured.\n" );
  110.   }
  111.  
  112.   // Close the COM library for the current thread
  113.   CoUninitialize();
  114.  
  115.     return 0;
  116. }
  117.  
  118. //--------------------------------------------------------------------------
  119. // Sign a file and write signature to another key file.
  120. //--------------------------------------------------------------------------
  121. void SignInputFile( IXceedSigningPtr piSign, const char* pszInputFileName, 
  122.                     const char* pszSignatureFileName )
  123. {
  124.   DWORD dwBytesRead     = 0;
  125.   DWORD dwBytesWritten  = 0;
  126.  
  127.   // Sign by reading a file and sending the signature to another file.
  128.   // We specify :
  129.   //  - The source filename, without any offset or size, since we want
  130.   //    to sign all the source file.
  131.   //  - The processing we want to perform, in this case efpSign.
  132.   //  - The bEndOfData parameter set to TRUE, since we do all the
  133.   //    processing in a single block.
  134.   //  - The address of a DWORD that will receive the number of bytes
  135.   //    actually read from the source.
  136.   piSign->ReadFile( pszInputFileName, 0, 0, efpSign, TRUE, &dwBytesRead );
  137.  
  138.   if( !SaveSignatureToFile( pszSignatureFileName, piSign ) )
  139.     throw "Could not write signature to destination file.";
  140.  
  141.   // Write the signing statistics to the screen. 
  142.   printf( "Successfully signed file %s [%d] to file %s\n", 
  143.           pszInputFileName, dwBytesRead, pszSignatureFileName );
  144. }
  145.  
  146. //--------------------------------------------------------------------------
  147. // Sign the data typed to the console input.
  148. //--------------------------------------------------------------------------
  149. void SignConsoleInput( IXceedSigningPtr piSign, const char* pszSignatureFileName )
  150. {
  151.   printf( "Signing from the console input. Press Ctrl-Z and Enter when done.\n\n" );
  152.  
  153.   char pcBuffer[ BUFFER_SIZE ];
  154.  
  155.   while( !feof( stdin ) )
  156.   {
  157.     // Read from the console BUFFER_SIZE characters at a time.
  158.     int nRead = fread( pcBuffer, sizeof( char ), BUFFER_SIZE, stdin );
  159.  
  160.     if( nRead )
  161.     {
  162.       // Sign the buffer read so far.
  163.       // We specify :
  164.       //  - The source buffer, with the size, since we want
  165.       //    to sign all the source buffer.
  166.       //  - The bEndOfData parameter set to FALSE, since we do the
  167.       //    processing in multiple block.
  168.       piSign->Sign( ( BYTE* )pcBuffer, nRead, FALSE );
  169.     }
  170.   }
  171.  
  172.   // Since we always called with bEndOfData to FALSE, we must
  173.   // make sure to flush the remaining data.
  174.   piSign->Sign( NULL, 0, TRUE );
  175.  
  176.   if( !SaveSignatureToFile( pszSignatureFileName, piSign ) )
  177.     throw "Could not write signature to destination file.";
  178.  
  179.   printf( "Successfully signed the console input to file %s\n", 
  180.           pszSignatureFileName );
  181. }
  182.  
  183. //--------------------------------------------------------------------------
  184. // Generate a new key pair and write it to key files.
  185. //--------------------------------------------------------------------------
  186. void GenerateKeyPair( IXceedSigningPtr piSign, int nKeyPairSize,
  187.                       const char* pszPrivateKeyFileName, const char* pszPublicKeyFileName )
  188. {
  189.   // Let's get a hand back on the signing method. The line below implies
  190.   // a call to QueryInterface to the signing method returned by piSign.
  191.   IXceedRSASigningMethodPtr piRSA( piSign->SigningMethod );
  192.  
  193.   if( piRSA == NULL )
  194.   {
  195.     // That's strange! We assigned an RSA signing method to this
  196.     // property in ExtractParameters.
  197.     throw "Invalid type of signing method.";
  198.   }
  199.  
  200.   // Generate a new key pair
  201.   piRSA->SetRandomKeyPair( nKeyPairSize, NULL, 0 );
  202.  
  203.   // Get the data to the private key and write it to private filename
  204.   BYTE* pcKey = NULL;
  205.   short nKeySize = 0;
  206.   bool  bSuccess = true;
  207.  
  208.   piRSA->GetPrivateKey( &pcKey, &nKeySize );
  209.  
  210.   bSuccess = WriteHexValueToFile( pszPrivateKeyFileName, pcKey, nKeySize );
  211.  
  212.   CoTaskMemFree( pcKey );
  213.  
  214.   if( !bSuccess )
  215.     throw "Could not write private key to destination file.";
  216.  
  217.   // Get the data to the public key and write it to public filename
  218.   piRSA->GetPublicKey( &pcKey, &nKeySize );
  219.  
  220.   bSuccess = WriteHexValueToFile( pszPublicKeyFileName, pcKey, nKeySize );
  221.  
  222.   CoTaskMemFree( pcKey );
  223.  
  224.   if( !bSuccess )
  225.     throw "Could not write public key to destination file.";
  226.  
  227.   printf( "Successfully generated key pair\n" );
  228.   printf( "Private key file: %s\n", pszPrivateKeyFileName );
  229.   printf( "Public key file : %s\n", pszPublicKeyFileName );
  230. }
  231.  
  232. //--------------------------------------------------------------------------
  233. // Display usage information
  234. //--------------------------------------------------------------------------
  235. void ShowHelp()
  236. {
  237.   //      "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
  238.   printf( "To generate a pair of private and public keys...\n\n"
  239.           "  RSASIGN  /g=key_pair_size  private_key_file  public_key_file\n\n"
  240.           "    key_pair_size    : the strength of the key pair to generate (e.g. 512)\n"
  241.           "    private_key_file : the file where to write the private key in hexadecimal\n"
  242.           "    public_key_file  : the file where to write the public key in hexadecimal\n\n"
  243.           "To sign a source file (or the console input)...\n\n"
  244.           "  RSASIGN  [input_file]  private_key_file  signature_file\n\n"
  245.           "    input_file       : the source file to generate a signature for\n"
  246.           "                       the console input is used if absent\n"
  247.           "    private_key_file : the file containing the private key (in hexadecimal)\n"
  248.           "                       that will be used to sign\n"
  249.           "    signature_file   : the destination destination file where to write the\n"
  250.           "                       signature in hexadecimal\n\n" );
  251. }
  252.  
  253. //--------------------------------------------------------------------------
  254. // Extract commands from the parameters
  255. //
  256. // In this function, we call the piSign interface and let exceptions
  257. // be caught by the caller.
  258. // This function returns false if an error occured parsing the command
  259. // line parameters or if the user requested help.
  260. //--------------------------------------------------------------------------
  261. bool ExtractParameters( int argc, char* argv[],
  262.                         IXceedSigningPtr piSign, 
  263.                         short& nKeyPairSize, 
  264.                         _bstr_t& bstrInputFileName,
  265.                         _bstr_t& bstrSignatureFileName,
  266.                         bool& bGenerateKeyPair )
  267. {
  268.   // Initialize byref parameters
  269.   nKeyPairSize = 0;
  270.   bGenerateKeyPair = false;
  271.  
  272.   // We parse each command line parameter
  273.   int i = 0;
  274.  
  275.   while( ++i < argc )
  276.   {
  277.     if( argv[ i ][ 0 ] == '/' )
  278.     {
  279.       // The parameter starts with a /
  280.       // Meaning it's an option parameter
  281.       switch( argv[ i ][ 1 ] )
  282.       {
  283.         case 'g':
  284.         case 'G':
  285.           if( argv[i][2] != '=' )
  286.           {
  287.             printf("You did not specify the key pair size value\n");
  288.             return false;
  289.           }
  290.  
  291.           // The user wants to create a new key pair
  292.           if( argc < 4 || argv[ argc - 1 ][ 0 ] == '/' || argv[ argc - 2 ][ 0 ] == '/' )
  293.           {
  294.             printf("You did not specify both private key file AND public key file\n");
  295.             return false;
  296.           }
  297.  
  298.           // Extract the key pair strength specified by the /g command
  299.           nKeyPairSize = atoi( argv[i] + 3 );
  300.  
  301.           bGenerateKeyPair = true;
  302.           break;
  303.  
  304.         case 'h':
  305.         case 'H':
  306.         case '?':
  307.           return false;
  308.           break;
  309.  
  310.         default:
  311.           printf( "Unknown command '%s'\n\n", argv[ i ] );
  312.           return false;
  313.           break;
  314.       }
  315.     }
  316.   }
  317.  
  318.   _bstr_t bstrPrivateKeyFileName;
  319.  
  320.   if( bGenerateKeyPair )
  321.   {
  322.     // Check if the user provided both key filenames
  323.     if( argc < 4 || argv[ argc - 1 ][ 0 ] == '/' || argv[ argc - 2 ][ 0 ] == '/' )
  324.     {
  325.       printf( "You did not specify both private key filename and public key filename\n\n" );
  326.       return false;
  327.     }
  328.     else
  329.     {
  330.       // We cheat a little bit and assign key filenames in these byref parameters
  331.       bstrInputFileName     = argv[ argc - 2 ];
  332.       bstrSignatureFileName = argv[ argc - 1 ];
  333.     }
  334.   }
  335.   else
  336.   {
  337.     // Check if the user provided at least an output filename and private key filename
  338.     if( argc < 3 || argv[ argc - 1 ][ 0 ] == '/' || argv[ argc - 2 ][ 0 ] == '/' )
  339.     {
  340.       printf( "You did not specify both private key filename and signature filename\n\n" );
  341.       return false;
  342.     }
  343.     else if( argc < 4 || argv[ argc - 3 ][ 0 ] == '/' )
  344.     {
  345.       // Only a private key and signature file were specified
  346.       bstrPrivateKeyFileName  = argv[ argc - 2 ];
  347.       bstrSignatureFileName   = argv[ argc - 1 ];
  348.     }
  349.     else
  350.     {
  351.       // â• nput, private key and signature file were specified
  352.       bstrInputFileName       = argv[ argc - 3 ];
  353.       bstrPrivateKeyFileName  = argv[ argc - 2 ];
  354.       bstrSignatureFileName   = argv[ argc - 1 ];
  355.     }
  356.   }
  357.  
  358.   // In any case, we use the RSA signing method
  359.   IXceedRSASigningMethodPtr piRSA;
  360.   piRSA.CreateInstance( CLSID_XceedRSASigningMethod );
  361.  
  362.   bool bSuccess = true;
  363.  
  364.   if( !bGenerateKeyPair )
  365.   {
  366.     // Before signing, we initialise the private key from a key value
  367.     // in the source key filename.
  368.  
  369.     BYTE* pcKey = NULL;
  370.     short nKeySize = 0;
  371.  
  372.     bSuccess = ReadHexValueFromFile( bstrPrivateKeyFileName, &pcKey, &nKeySize );
  373.  
  374.     piRSA->SetPrivateKey( pcKey, nKeySize );
  375.  
  376.     delete [] pcKey;
  377.   }
  378.  
  379.   // The property is of type IXceedSignData*. Every signing method implements
  380.   // this private interface. We simply need to do a QueryInterface on piRSA.
  381.   piSign->SigningMethod = IXceedSignDataPtr( piRSA );
  382.  
  383.   return bSuccess;
  384. }
  385.  
  386. //--------------------------------------------------------------------------
  387. // Extract the calculated signature from the XceedSigning object and
  388. // save it to the specified file
  389. //--------------------------------------------------------------------------
  390. bool SaveSignatureToFile( const char* pszSignatureFileName, 
  391.                           IXceedSigningPtr piSign )
  392. {
  393.   // We need the XceedRSASigningMethod instance to get the Signature.
  394.   // The line below implies a call to QueryInterface, to get the correct
  395.   // interface.
  396.   IXceedRSASigningMethodPtr piRSA( piSign->SigningMethod );
  397.  
  398.   if( piRSA == NULL )
  399.   {
  400.     // Hmmm, that's strange since the only type of method we are assigning 
  401.     // to the SigningMethod property is an XceedRSASigning instance.
  402.     throw "Invalid type of signing method.";
  403.   }
  404.  
  405.   // Get the signature from this signing method.
  406.   BYTE* pcSignature = NULL;
  407.   short nSignatureSize = 0;
  408.  
  409.   piRSA->GetSignature( &pcSignature, &nSignatureSize );
  410.  
  411.   // Save the signature to the file in hexadecimal.
  412.   bool bSuccess = WriteHexValueToFile( pszSignatureFileName, pcSignature, nSignatureSize );
  413.   
  414.   // Free the memory used by the signature.
  415.   CoTaskMemFree( pcSignature );
  416.  
  417.   return bSuccess;
  418. }
  419.  
  420. //
  421. // END_OF_FILE
  422. //
  423.