home *** CD-ROM | disk | FTP | other *** search
- /* Xceed Encryption Library - RSASign Sample Application
- * Copyright (c) 2001 Xceed Software Inc.
- *
- * [RSASign.cpp]
- *
- * This console application shows how to sign a file or a message.
- * It specifically demonstrates:
- * - The SetRandomKeyPair, ReadFile and Sign methods.
- * - The Signature, PrivateKey and SigningMethod properties.
- *
- * [Example]
- *
- * To generate a pair of private and public keys of strength 512:
- * RSASIGN /g=512 PRIVATE.TXT PUBLIC.TXT
- *
- * To sign file "HELLO.BMP" from private key stored in
- * hexadecimal in file "PRIVATE.TXT", and write resulting
- * signature in "HELLO.SIG":
- * RSASIGN HELLO.BMP PRIVATE.TXT HELLO.SIG
- *
- * This file is part of the Xceed Encryption Library sample
- * applications. The source code in this file is only intended as
- * a supplement to Xceed Encryption Library's documentation,
- * and is provided "as is", without warranty of any kind, either
- * expressed or implied.
- */
-
- #include "stdafx.h"
- #include "RSASign.h"
-
- #include "utility.h"
-
- //
- // Entry point of the application
- //
-
- int main(int argc, char* argv[])
- {
- CoInitialize( NULL );
-
- try
- {
- // Create an instance of the XceedSigning coclass, and
- // use the "I" interface which manipulates byte arrays instead of
- // Variants as the "D" interface does.
- IXceedSigningPtr piSign;
- piSign.CreateInstance( CLSID_XceedSigning );
-
- // Parameter values we want to grab
- short nKeyPairSize = 0;
- _bstr_t bstrInputFileName;
- _bstr_t bstrSignatureFileName;
- bool bGenerateKeyPair = false;
-
- // Extract the command line parameters and initialize the Signing
- // instance according to the user specification. After this call
- // the Signing instance piSign is ready to sign.
- if( !ExtractParameters( argc, argv,
- piSign,
- nKeyPairSize,
- bstrInputFileName,
- bstrSignatureFileName,
- bGenerateKeyPair ) )
- {
- // There's been an error extracting the command-line parameters or the
- // user requested some help.
- ShowHelp();
- return 1;
- }
-
- if( bGenerateKeyPair )
- {
- // The user wants to generate a key pair. The bstrInputFileName and
- // bstrSignatureFileName variables respectively contain the private
- // key filename and public key filename.
-
- GenerateKeyPair( piSign, nKeyPairSize, bstrInputFileName, bstrSignatureFileName );
- }
- else if( bstrInputFileName.length() == 0 )
- {
- // An input file name was not provided by the user.
- // Get the source from the console
-
- SignConsoleInput( piSign, bstrSignatureFileName );
- }
- else
- {
- // An input file name was provided by the user.
- // Read the input file and sign
-
- SignInputFile( piSign, bstrInputFileName, bstrSignatureFileName );
- }
- }
- catch( const _com_error& err )
- {
- // When using the "#import" directive, the compiler generates wrapper classes
- // around all interface types. These wrapper classes throw exceptions when
- // a method call returns an HRESULT which is a failure code.
- printf( "Error %08x: %s\n", err.Error(), ( const char* )err.Description() );
- }
- catch( const char* pszError )
- {
- // We also throw string exceptions ourselves!
- printf( "Error: %s\n", pszError );
- }
- catch( ... )
- {
- // Catch any other exceptions
- printf( "An unknown error occured.\n" );
- }
-
- // Close the COM library for the current thread
- CoUninitialize();
-
- return 0;
- }
-
- //--------------------------------------------------------------------------
- // Sign a file and write signature to another key file.
- //--------------------------------------------------------------------------
- void SignInputFile( IXceedSigningPtr piSign, const char* pszInputFileName,
- const char* pszSignatureFileName )
- {
- DWORD dwBytesRead = 0;
- DWORD dwBytesWritten = 0;
-
- // Sign by reading a file and sending the signature to another file.
- // We specify :
- // - The source filename, without any offset or size, since we want
- // to sign all the source file.
- // - The processing we want to perform, in this case efpSign.
- // - The bEndOfData parameter set to TRUE, since we do all the
- // processing in a single block.
- // - The address of a DWORD that will receive the number of bytes
- // actually read from the source.
- piSign->ReadFile( pszInputFileName, 0, 0, efpSign, TRUE, &dwBytesRead );
-
- if( !SaveSignatureToFile( pszSignatureFileName, piSign ) )
- throw "Could not write signature to destination file.";
-
- // Write the signing statistics to the screen.
- printf( "Successfully signed file %s [%d] to file %s\n",
- pszInputFileName, dwBytesRead, pszSignatureFileName );
- }
-
- //--------------------------------------------------------------------------
- // Sign the data typed to the console input.
- //--------------------------------------------------------------------------
- void SignConsoleInput( IXceedSigningPtr piSign, const char* pszSignatureFileName )
- {
- printf( "Signing from the console input. Press Ctrl-Z and Enter when done.\n\n" );
-
- char pcBuffer[ BUFFER_SIZE ];
-
- while( !feof( stdin ) )
- {
- // Read from the console BUFFER_SIZE characters at a time.
- int nRead = fread( pcBuffer, sizeof( char ), BUFFER_SIZE, stdin );
-
- if( nRead )
- {
- // Sign the buffer read so far.
- // We specify :
- // - The source buffer, with the size, since we want
- // to sign all the source buffer.
- // - The bEndOfData parameter set to FALSE, since we do the
- // processing in multiple block.
- piSign->Sign( ( BYTE* )pcBuffer, nRead, FALSE );
- }
- }
-
- // Since we always called with bEndOfData to FALSE, we must
- // make sure to flush the remaining data.
- piSign->Sign( NULL, 0, TRUE );
-
- if( !SaveSignatureToFile( pszSignatureFileName, piSign ) )
- throw "Could not write signature to destination file.";
-
- printf( "Successfully signed the console input to file %s\n",
- pszSignatureFileName );
- }
-
- //--------------------------------------------------------------------------
- // Generate a new key pair and write it to key files.
- //--------------------------------------------------------------------------
- void GenerateKeyPair( IXceedSigningPtr piSign, int nKeyPairSize,
- const char* pszPrivateKeyFileName, const char* pszPublicKeyFileName )
- {
- // Let's get a hand back on the signing method. The line below implies
- // a call to QueryInterface to the signing method returned by piSign.
- IXceedRSASigningMethodPtr piRSA( piSign->SigningMethod );
-
- if( piRSA == NULL )
- {
- // That's strange! We assigned an RSA signing method to this
- // property in ExtractParameters.
- throw "Invalid type of signing method.";
- }
-
- // Generate a new key pair
- piRSA->SetRandomKeyPair( nKeyPairSize, NULL, 0 );
-
- // Get the data to the private key and write it to private filename
- BYTE* pcKey = NULL;
- short nKeySize = 0;
- bool bSuccess = true;
-
- piRSA->GetPrivateKey( &pcKey, &nKeySize );
-
- bSuccess = WriteHexValueToFile( pszPrivateKeyFileName, pcKey, nKeySize );
-
- CoTaskMemFree( pcKey );
-
- if( !bSuccess )
- throw "Could not write private key to destination file.";
-
- // Get the data to the public key and write it to public filename
- piRSA->GetPublicKey( &pcKey, &nKeySize );
-
- bSuccess = WriteHexValueToFile( pszPublicKeyFileName, pcKey, nKeySize );
-
- CoTaskMemFree( pcKey );
-
- if( !bSuccess )
- throw "Could not write public key to destination file.";
-
- printf( "Successfully generated key pair\n" );
- printf( "Private key file: %s\n", pszPrivateKeyFileName );
- printf( "Public key file : %s\n", pszPublicKeyFileName );
- }
-
- //--------------------------------------------------------------------------
- // Display usage information
- //--------------------------------------------------------------------------
- void ShowHelp()
- {
- // "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
- printf( "To generate a pair of private and public keys...\n\n"
- " RSASIGN /g=key_pair_size private_key_file public_key_file\n\n"
- " key_pair_size : the strength of the key pair to generate (e.g. 512)\n"
- " private_key_file : the file where to write the private key in hexadecimal\n"
- " public_key_file : the file where to write the public key in hexadecimal\n\n"
- "To sign a source file (or the console input)...\n\n"
- " RSASIGN [input_file] private_key_file signature_file\n\n"
- " input_file : the source file to generate a signature for\n"
- " the console input is used if absent\n"
- " private_key_file : the file containing the private key (in hexadecimal)\n"
- " that will be used to sign\n"
- " signature_file : the destination destination file where to write the\n"
- " signature in hexadecimal\n\n" );
- }
-
- //--------------------------------------------------------------------------
- // Extract commands from the parameters
- //
- // In this function, we call the piSign interface and let exceptions
- // be caught by the caller.
- // This function returns false if an error occured parsing the command
- // line parameters or if the user requested help.
- //--------------------------------------------------------------------------
- bool ExtractParameters( int argc, char* argv[],
- IXceedSigningPtr piSign,
- short& nKeyPairSize,
- _bstr_t& bstrInputFileName,
- _bstr_t& bstrSignatureFileName,
- bool& bGenerateKeyPair )
- {
- // Initialize byref parameters
- nKeyPairSize = 0;
- bGenerateKeyPair = false;
-
- // We parse each command line parameter
- int i = 0;
-
- while( ++i < argc )
- {
- if( argv[ i ][ 0 ] == '/' )
- {
- // The parameter starts with a /
- // Meaning it's an option parameter
- switch( argv[ i ][ 1 ] )
- {
- case 'g':
- case 'G':
- if( argv[i][2] != '=' )
- {
- printf("You did not specify the key pair size value\n");
- return false;
- }
-
- // The user wants to create a new key pair
- if( argc < 4 || argv[ argc - 1 ][ 0 ] == '/' || argv[ argc - 2 ][ 0 ] == '/' )
- {
- printf("You did not specify both private key file AND public key file\n");
- return false;
- }
-
- // Extract the key pair strength specified by the /g command
- nKeyPairSize = atoi( argv[i] + 3 );
-
- bGenerateKeyPair = true;
- break;
-
- case 'h':
- case 'H':
- case '?':
- return false;
- break;
-
- default:
- printf( "Unknown command '%s'\n\n", argv[ i ] );
- return false;
- break;
- }
- }
- }
-
- _bstr_t bstrPrivateKeyFileName;
-
- if( bGenerateKeyPair )
- {
- // Check if the user provided both key filenames
- if( argc < 4 || argv[ argc - 1 ][ 0 ] == '/' || argv[ argc - 2 ][ 0 ] == '/' )
- {
- printf( "You did not specify both private key filename and public key filename\n\n" );
- return false;
- }
- else
- {
- // We cheat a little bit and assign key filenames in these byref parameters
- bstrInputFileName = argv[ argc - 2 ];
- bstrSignatureFileName = argv[ argc - 1 ];
- }
- }
- else
- {
- // Check if the user provided at least an output filename and private key filename
- if( argc < 3 || argv[ argc - 1 ][ 0 ] == '/' || argv[ argc - 2 ][ 0 ] == '/' )
- {
- printf( "You did not specify both private key filename and signature filename\n\n" );
- return false;
- }
- else if( argc < 4 || argv[ argc - 3 ][ 0 ] == '/' )
- {
- // Only a private key and signature file were specified
- bstrPrivateKeyFileName = argv[ argc - 2 ];
- bstrSignatureFileName = argv[ argc - 1 ];
- }
- else
- {
- // â• nput, private key and signature file were specified
- bstrInputFileName = argv[ argc - 3 ];
- bstrPrivateKeyFileName = argv[ argc - 2 ];
- bstrSignatureFileName = argv[ argc - 1 ];
- }
- }
-
- // In any case, we use the RSA signing method
- IXceedRSASigningMethodPtr piRSA;
- piRSA.CreateInstance( CLSID_XceedRSASigningMethod );
-
- bool bSuccess = true;
-
- if( !bGenerateKeyPair )
- {
- // Before signing, we initialise the private key from a key value
- // in the source key filename.
-
- BYTE* pcKey = NULL;
- short nKeySize = 0;
-
- bSuccess = ReadHexValueFromFile( bstrPrivateKeyFileName, &pcKey, &nKeySize );
-
- piRSA->SetPrivateKey( pcKey, nKeySize );
-
- delete [] pcKey;
- }
-
- // The property is of type IXceedSignData*. Every signing method implements
- // this private interface. We simply need to do a QueryInterface on piRSA.
- piSign->SigningMethod = IXceedSignDataPtr( piRSA );
-
- return bSuccess;
- }
-
- //--------------------------------------------------------------------------
- // Extract the calculated signature from the XceedSigning object and
- // save it to the specified file
- //--------------------------------------------------------------------------
- bool SaveSignatureToFile( const char* pszSignatureFileName,
- IXceedSigningPtr piSign )
- {
- // We need the XceedRSASigningMethod instance to get the Signature.
- // The line below implies a call to QueryInterface, to get the correct
- // interface.
- IXceedRSASigningMethodPtr piRSA( piSign->SigningMethod );
-
- if( piRSA == NULL )
- {
- // Hmmm, that's strange since the only type of method we are assigning
- // to the SigningMethod property is an XceedRSASigning instance.
- throw "Invalid type of signing method.";
- }
-
- // Get the signature from this signing method.
- BYTE* pcSignature = NULL;
- short nSignatureSize = 0;
-
- piRSA->GetSignature( &pcSignature, &nSignatureSize );
-
- // Save the signature to the file in hexadecimal.
- bool bSuccess = WriteHexValueToFile( pszSignatureFileName, pcSignature, nSignatureSize );
-
- // Free the memory used by the signature.
- CoTaskMemFree( pcSignature );
-
- return bSuccess;
- }
-
- //
- // END_OF_FILE
- //
-