/******************************************************************************\
*       Adapted by Bruce Fortune (Citrix Systems, Inc.) from MS Online Source 
*       This is a part of the Microsoft Source Code Samples. 
*       Copyright (C) 1996 Microsoft Corporation.
*       All rights reserved. 
*       This source code is only intended as a supplement to 
*       Microsoft Development Tools and/or WinHelp documentation.
*       See these sources for detailed information regarding the 
*       Microsoft samples programs.
\******************************************************************************/

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <wincrypt.h>

#define SIGKEYSIZE 1024

#define PUBBLOBFILE "pubblob.h"
#define PRIVBLOBFILE "privblob.h"

//
// LINE_VALS - maximum number of byte values printed on each line of
//             the "blob" files
//
#define LINE_VALS 8

char *pszProgname; // program name - from argv[0]


BOOL
OpenBlobFile(
    FILE **file,
    CHAR *fname
    )
{
    *file = fopen( fname, "wt" );
    if ( !*file ) {
        return(FALSE);
    }
    return(TRUE);
}

void
DumpKeyBlob(
    FILE *file,
    DWORD dwBlobType,
    HCRYPTKEY hKey,
    HCRYPTKEY hExportKey )
{
    int dwBlobCount;
    if (!CryptExportKey(
            hKey,
            hExportKey,
            dwBlobType,
            0,
            NULL,
            &dwBlobCount)) {
        printf( "Error %x during CryptExportKey 1!\n", GetLastError());
        exit(1);
    } else {
        PBYTE pBlob;
        pBlob = (PBYTE) malloc( dwBlobCount );
        if ( !pBlob || !CryptExportKey(
                hKey,
                hExportKey,
                dwBlobType,
                0,
                pBlob,
                &dwBlobCount)) {
            printf("Error %x during malloc/CryptExportKey 2!\n",
                GetLastError());
            exit(1);
        } else {
            int cnt=0;
            fprintf( file, "// This data is generated by %s.\n", pszProgname );
            fprintf( file, "// Key Blob - %d bytes\n",
                dwBlobCount );
            while ( cnt < dwBlobCount ) {
                int i;
                for ( i=0; (i < LINE_VALS) && (cnt < dwBlobCount); cnt++,i++) {
                    fprintf( file, "0x%02x, ", *(pBlob+cnt) );
                }
                fprintf( file, "\n" );
            }
            free( pBlob );
        }
    }
}

/*****************************************************************************/
void _cdecl main(int argc, char *argv[])
{
    HCRYPTPROV hProv;
    HCRYPTKEY hSigKey;
    CHAR szUserName[100];
    DWORD dwUserNameLen = 100;
    FILE *blobfile;

    pszProgname = argv[0];

    // Attempt to acquire a handle to the default key container.
    if(!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV, PROV_RSA_FULL, 0)) {
	// Some sort of error occured.

	// Create default key container.
	if(!CryptAcquireContext(&hProv, NULL, MS_DEF_PROV,
                PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
	    printf("Error creating key container!\n");
	    exit(1);
	}

	// Get name of default key container.
	if(!CryptGetProvParam(hProv, PP_CONTAINER, szUserName,
                &dwUserNameLen, 0)) {
	    // Error getting key container name.
	    szUserName[0] = 0;
	}

	printf("Create key container '%s'\n",szUserName);
    }

    // Attempt to get handle to signature key.
    // Commented out the following 2 lines. We always gerenate a new signature key. TSE4.0
    // uses the existing key which seems to generate the same key all the time.
    //    if( !CryptGetUserKey(hProv, AT_SIGNATURE, &hSigKey)) {
    //	if( GetLastError() == NTE_NO_KEY) {
    //
    // Create signature key pair.
    //
    printf("Creating signature key pair...");

    if (!CryptGenKey( hProv,
                      AT_SIGNATURE,
                      (SIGKEYSIZE << 16 ) | CRYPT_EXPORTABLE,
                      &hSigKey)) {
        printf("Error %x during CryptGenKey!\n", GetLastError());
        exit(1);
    } else {
        // Get Public Key BLOB
        if ( !OpenBlobFile( &blobfile, PUBBLOBFILE ) ) {
            printf( "Error %x during OpenBlobFile!\n", GetLastError() );
            exit(1);
        }
        fprintf( blobfile, "unsigned char PublicKeySigBlob[] = {\n" );
        DumpKeyBlob( blobfile, PUBLICKEYBLOB, hSigKey, 0 );
        fprintf( blobfile, "};\n" );

    }

    
#if 0 // Commented out the following code. We always gerenate a new signature key. TSE4.0
      // uses the existing key which seems to generate the same key all the time.

	} else {
	    printf("Error %x during CryptGetUserKey!\n", GetLastError());
	    exit(1);
	}
    } else {
        // Get Public Key BLOB
        printf( "Using existing keys..." );
        if ( !OpenBlobFile( &blobfile, PUBBLOBFILE ) ) {
            printf( "Error %x during OpenBlobFile!\n", GetLastError() );
            exit(1);
        }
        fprintf( blobfile, "unsigned char PublicKeySigBlob[] = {\n" );
        DumpKeyBlob( blobfile, PUBLICKEYBLOB, hSigKey, 0 );
        fprintf( blobfile, "};\n" );
    }
#endif

    // Get Private Key BLOB
    if ( !OpenBlobFile( &blobfile, PRIVBLOBFILE ) ) {
        printf( "Error %x during OpenBlobFile - %s!\n",
            GetLastError(),
            PRIVBLOBFILE );
        exit(1);
    }
    fprintf( blobfile, "unsigned char PrivateKeySigBlob[] = {\n" );
    DumpKeyBlob( blobfile, PRIVATEKEYBLOB, hSigKey, 0 );
    fprintf( blobfile, "};\n" );
    CryptDestroyKey(hSigKey);

    CryptReleaseContext(hProv,0);

    printf( " successful.\n" );
    exit(0);
}
