/////////////////////////////////////////////////////////////////////////////
//  FILE          : client.cxx                                             //
//  DESCRIPTION   : Crypto API interface                                   //
//  AUTHOR        :                                                        //
//  HISTORY       :                                                        //
//      Mar  8 1996 larrys  New                                            //
//                  dbarlow                                                //
//                                                                         //
//  Copyright (C) 1996 Microsoft Corporation   All Rights Reserved         //
/////////////////////////////////////////////////////////////////////////////

#include <windows.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <imagehlp.h>
#include "des.h"
#include "modes.h"

// SIG in file
#define SIG_RESOURCE_NAME   "#666"
// MAC in file
#define MAC_RESOURCE_NAME   "#667"

static DWORD dwMACInFileVersion = 0x100;

BYTE rgbDESKey[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};

// The function MACs the given bytes.
void MACBytes(
              IN DESTable *pDESKeyTable,
              IN BYTE *pbData,
              IN DWORD cbData,
              IN OUT BYTE *pbTmp,
              IN OUT DWORD *pcbTmp,
              IN OUT BYTE *pbMAC,
              IN BOOL fFinal
              )
{
    DWORD   cb = cbData;
    DWORD   cbMACed = 0;

    while (cb)
    {
        if ((cb + *pcbTmp) < DES_BLOCKLEN)
        {
            memcpy(pbTmp + *pcbTmp, pbData + cbMACed, cb);
            *pcbTmp += cb;
            break;
        }
        else
        {
            memcpy(pbTmp + *pcbTmp, pbData + cbMACed, DES_BLOCKLEN - *pcbTmp);
            CBC(des, DES_BLOCKLEN, pbMAC, pbTmp, pDESKeyTable,
                ENCRYPT, pbMAC);
            cbMACed = cbMACed + (DES_BLOCKLEN - *pcbTmp);
            cb = cb - (DES_BLOCKLEN - *pcbTmp);
            *pcbTmp = 0;
        }
    }
}

/*
void QuickTest()
{
    BYTE        rgbTmp[DES_BLOCKLEN];
    DWORD       cbTmp = 0;
    BYTE        rgbMAC[DES_BLOCKLEN] =
    {
        0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef
    };
    DESTable    DESKeyTable;
    DWORD       i;
    BYTE        rgbData[] =
    {
        0x37, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x20,
        0x4e, 0x6f, 0x77, 0x20, 0x69, 0x73, 0x20, 0x74,
        0x68, 0x65, 0x20, 0x74, 0x69, 0x6d, 0x65, 0x20,
        0x66, 0x6f, 0x72, 0x20, 0x00, 0x00, 0x00, 0x00
    };

    memset(&DESKeyTable, 0, sizeof(DESKeyTable));
    memset(rgbTmp, 0, sizeof(rgbTmp));

    // init the key table
    deskey(&DESKeyTable, rgbDESKey);

    MACBytes(&DESKeyTable, rgbData, sizeof(rgbData), rgbTmp,
             &cbTmp, rgbMAC, TRUE);

    printf("MAC - ");
    for (i = 0; i < DES_BLOCKLEN; i++)
    {
        printf("%02X", rgbMAC[i]);
    }
    printf("\n");
}
*/

// Given hInst, allocs and returns pointers to MAC pulled from
// resource
BOOL GetResourcePtr(
                    IN HMODULE hInst,
                    IN LPSTR pszRsrcName,
                    OUT BYTE **ppbRsrcMAC,
                    OUT DWORD *pcbRsrcMAC
                    )
{
    HRSRC   hRsrc;
    BOOL    fRet = FALSE;

    // Nab resource handle for our signature
    if (NULL == (hRsrc = FindResourceA(hInst, pszRsrcName,
                                       RT_RCDATA)))
        goto Ret;

    // get a pointer to the actual signature data
    if (NULL == (*ppbRsrcMAC = (PBYTE)LoadResource(hInst, hRsrc)))
        goto Ret;

    // determine the size of the resource
    if (0 == (*pcbRsrcMAC = SizeofResource(hInst, hRsrc)))
        goto Ret;

    fRet = TRUE;
Ret:
    return fRet;
}

#define CSP_TO_BE_MACED_CHUNK  4096

// Given hFile, reads the specified number of bytes (cbToBeMACed) from the file
// and MACs these bytes.  The function does this in chunks.
BOOL MACBytesOfFile(
                     IN HANDLE hFile,
                     IN DWORD cbToBeMACed,
                     IN DESTable *pDESKeyTable,
                     IN BYTE *pbTmp,
                     IN DWORD *pcbTmp,
                     IN BYTE *pbMAC,
                     IN BYTE fFinal
                     )
{
    BYTE    rgbChunk[CSP_TO_BE_MACED_CHUNK];
    DWORD   cbRemaining = cbToBeMACed;
    DWORD   cbToRead;
    DWORD   dwBytesRead;
    BOOL    fRet = FALSE;

    //
    // loop over the file for the specified number of bytes
    // updating the hash as we go.
    //

    while (cbRemaining > 0)
    {
        if (cbRemaining < CSP_TO_BE_MACED_CHUNK)
            cbToRead = cbRemaining;
        else
            cbToRead = CSP_TO_BE_MACED_CHUNK;

        if(!ReadFile(hFile, rgbChunk, cbToRead, &dwBytesRead, NULL))
            goto Ret;
        if (dwBytesRead != cbToRead)
            goto Ret;

        MACBytes(pDESKeyTable, rgbChunk, dwBytesRead, pbTmp, pcbTmp,
                 pbMAC, fFinal);
        cbRemaining -= cbToRead;
    }

    fRet = TRUE;
Ret:
    return fRet;
}


BOOL MACTheFileNoSig(
                     IN LPCSTR pszImage,
                     IN DWORD cbImage,
                     IN DWORD dwMACVersion,
                     IN DWORD dwCRCOffset,
                     OUT BYTE *pbMAC
                     )
{
    HMODULE                     hInst = 0;
    MEMORY_BASIC_INFORMATION    MemInfo;
    BYTE                        *pbStart;
    BYTE                        rgbMAC[DES_BLOCKLEN];
    BYTE                        rgbZeroMAC[DES_BLOCKLEN + sizeof(DWORD) * 2];
    BYTE                        *pbPostCRC;   // pointer to just after CRC
    DWORD                       cbCRCToMAC;   // number of bytes from CRC to sig
    DWORD                       cbPostMAC;    // size - (already hashed + signature size)
    BYTE                        *pbPostMAC;
    DWORD                       dwZeroCRC = 0;
    DWORD                       dwBytesRead = 0;
    OFSTRUCT                    ImageInfoBuf;
    HFILE                       hFile = HFILE_ERROR;
    HANDLE                      hMapping = NULL;
    DESTable                    DESKeyTable;
    BYTE                        rgbTmp[DES_BLOCKLEN];
    DWORD                       cbTmp = 0;
    BYTE                        *pbRsrcMAC = NULL;
    DWORD                       cbRsrcMAC;
    BOOL                        fRet = FALSE;

    memset(&MemInfo, 0, sizeof(MemInfo));
    memset(rgbMAC, 0, sizeof(rgbMAC));
    memset(rgbTmp, 0, sizeof(rgbTmp));

    // Load the file
    if (HFILE_ERROR == (hFile = OpenFile(pszImage, &ImageInfoBuf,
                                         OF_READ)))
    {
        goto Ret;
    }

    hMapping = CreateFileMapping((HANDLE)IntToPtr(hFile),
                                  NULL,
                                  PAGE_READONLY,
                                  0,
                                  0,
                                  NULL);
    if(hMapping == NULL)
    {
        goto Ret;
    }

    hInst = MapViewOfFile(hMapping,
                          FILE_MAP_READ,
                          0,
                          0,
                          0);
    if(hInst == NULL)
    {
        goto Ret;
    }
    pbStart = (BYTE*)hInst;

    // Convert pointer to HMODULE, using the same scheme as
    // LoadLibrary (windows\base\client\module.c).
    *((ULONG_PTR*)&hInst) |= 0x00000001;

    // create a zero byte MAC
    memset(rgbZeroMAC, 0, sizeof(rgbZeroMAC));

    if (!GetResourcePtr(hInst, MAC_RESOURCE_NAME, &pbRsrcMAC, &cbRsrcMAC))
    {
        printf("Couldn't find MAC placeholder\n");
        goto Ret;
    }

    pbPostCRC = pbStart + dwCRCOffset + sizeof(DWORD);
    cbCRCToMAC = (DWORD)(pbRsrcMAC - pbPostCRC);
    pbPostMAC = pbRsrcMAC + (DES_BLOCKLEN + sizeof(DWORD) * 2);
    cbPostMAC = (cbImage - (DWORD)(pbPostMAC - pbStart));

    // copy the resource MAC
    if (DES_BLOCKLEN != (cbRsrcMAC - (sizeof(DWORD) * 2)))
    {
        goto Ret;
    }

    // init the key table
    deskey(&DESKeyTable, rgbDESKey);

    // MAC up to the CRC
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), dwCRCOffset, &DESKeyTable, rgbTmp,
                        &cbTmp, rgbMAC, FALSE))
    {
        goto Ret;
    }

    // pretend CRC is zeroed
    MACBytes(&DESKeyTable, (BYTE*)&dwZeroCRC, sizeof(DWORD), rgbTmp, &cbTmp,
             rgbMAC, FALSE);
    if (!SetFilePointer((HANDLE)IntToPtr(hFile), sizeof(DWORD), NULL, FILE_CURRENT))
    {
        goto Ret;
    }

    // MAC from CRC to MAC resource
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbCRCToMAC, &DESKeyTable, rgbTmp,
                        &cbTmp, rgbMAC, FALSE))
    {
        goto Ret;
    }

    // pretend image has zeroed MAC
    MACBytes(&DESKeyTable, (BYTE*)rgbZeroMAC, cbRsrcMAC, rgbTmp, &cbTmp,
             rgbMAC, FALSE);
    if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbRsrcMAC, NULL, FILE_CURRENT))
    {
        goto Ret;
    }

    // MAC after the resource
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbPostMAC, &DESKeyTable, rgbTmp, &cbTmp,
                        rgbMAC, TRUE))
    {
        goto Ret;
    }

    memcpy(pbMAC, rgbMAC, DES_BLOCKLEN);

    fRet = TRUE;
Ret:
    if (pbRsrcMAC)
        FreeResource(pbRsrcMAC);
    if(hInst)
        UnmapViewOfFile(hInst);
    if(hMapping)
        CloseHandle(hMapping);
    if (HFILE_ERROR != hFile)
        _lclose(hFile);

    return fRet;
}

BOOL MACTheFileWithSig(
                       LPCSTR pszImage,
                       DWORD cbImage,
                       IN DWORD dwMACVersion,
                       IN DWORD dwCRCOffset,
                       OUT BYTE *pbMAC
                       )
{
    HMODULE                     hInst = 0;
    MEMORY_BASIC_INFORMATION    MemInfo;
    BYTE                        *pbRsrcMAC = NULL;
    DWORD                       cbRsrcMAC;
    BYTE                        *pbRsrcSig = NULL;
    DWORD                       cbRsrcSig;
    BYTE                        *pbStart;
    BYTE                        rgbMAC[DES_BLOCKLEN];
    BYTE                        rgbZeroMAC[DES_BLOCKLEN + sizeof(DWORD) * 2];
    BYTE                        rgbZeroSig[144];
    BYTE                        *pbPostCRC;   // pointer to just after CRC
    DWORD                       cbCRCToRsrc1; // number of bytes from CRC to first rsrc
    DWORD                       cbRsrc1ToRsrc2; // number of bytes from first rsrc to second
    DWORD                       cbPostRsrc;    // size - (already hashed + signature size)
    BYTE                        *pbRsrc1ToRsrc2;
    BYTE                        *pbPostRsrc;
    BYTE                        *pbZeroRsrc1;
    BYTE                        *pbZeroRsrc2;
    DWORD                       cbZeroRsrc1;
    DWORD                       cbZeroRsrc2;
    DWORD                       dwZeroCRC = 0;
    DWORD                       dwBytesRead = 0;
    OFSTRUCT                    ImageInfoBuf;
    HFILE                       hFile = HFILE_ERROR;
    HANDLE                      hMapping = NULL;
    DESTable                    DESKeyTable;
    BYTE                        rgbTmp[DES_BLOCKLEN];
    DWORD                       cbTmp = 0;
    BOOL                        fRet = FALSE;

    memset(&MemInfo, 0, sizeof(MemInfo));
    memset(rgbMAC, 0, sizeof(rgbMAC));
    memset(rgbTmp, 0, sizeof(rgbTmp));

    // Load the file
    if (HFILE_ERROR == (hFile = OpenFile(pszImage, &ImageInfoBuf,
                                         OF_READ)))
    {
        goto Ret;
    }

    hMapping = CreateFileMapping((HANDLE)IntToPtr(hFile),
                                  NULL,
                                  PAGE_READONLY,
                                  0,
                                  0,
                                  NULL);
    if(hMapping == NULL)
    {
        goto Ret;
    }

    hInst = MapViewOfFile(hMapping,
                          FILE_MAP_READ,
                          0,
                          0,
                          0);
    if(hInst == NULL)
    {
        goto Ret;
    }
    pbStart = (BYTE*)hInst;

    // Convert pointer to HMODULE, using the same scheme as
    // LoadLibrary (windows\base\client\module.c).
    *((ULONG_PTR*)&hInst) |= 0x00000001;

    // the MAC resource
    if (!GetResourcePtr(hInst, MAC_RESOURCE_NAME, &pbRsrcMAC, &cbRsrcMAC))
        goto Ret;

    // the MAC resource
    if (!GetResourcePtr(hInst, SIG_RESOURCE_NAME, &pbRsrcSig, &cbRsrcSig))
        goto Ret;

    if (cbRsrcMAC < (sizeof(DWORD) * 2))
        goto Ret;

    // create a zero byte MAC
    memset(rgbZeroMAC, 0, sizeof(rgbZeroMAC));

    // create a zero byte Sig
    memset(rgbZeroSig, 0, sizeof(rgbZeroSig));

    // set up the pointers
    pbPostCRC = pbStart + dwCRCOffset + sizeof(DWORD);
    if (pbRsrcSig > pbRsrcMAC)    // MAC is first Rsrc
    {
        cbCRCToRsrc1 = (DWORD)(pbRsrcMAC - pbPostCRC);
        pbRsrc1ToRsrc2 = pbRsrcMAC + cbRsrcMAC;
        cbRsrc1ToRsrc2 = (DWORD)(pbRsrcSig - pbRsrc1ToRsrc2);
        pbPostRsrc = pbRsrcSig + cbRsrcSig;
        cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart));

        // zero pointers
        pbZeroRsrc1 = rgbZeroMAC;
        cbZeroRsrc1 = cbRsrcMAC;
        pbZeroRsrc2 = rgbZeroSig;
        cbZeroRsrc2 = cbRsrcSig;
    }
    else                        // Sig is first Rsrc
    {
        cbCRCToRsrc1 = (DWORD)(pbRsrcSig - pbPostCRC);
        pbRsrc1ToRsrc2 = pbRsrcSig + cbRsrcSig;
        cbRsrc1ToRsrc2 = (DWORD)(pbRsrcMAC - pbRsrc1ToRsrc2);
        pbPostRsrc = pbRsrcMAC + cbRsrcMAC;
        cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart));

        // zero pointers
        pbZeroRsrc1 = rgbZeroSig;
        cbZeroRsrc1 = cbRsrcSig;
        pbZeroRsrc2 = rgbZeroMAC;
        cbZeroRsrc2 = cbRsrcMAC;
    }

    // init the key table
    deskey(&DESKeyTable, rgbDESKey);

    // MAC up to the CRC
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), dwCRCOffset, &DESKeyTable, rgbTmp,
                        &cbTmp, rgbMAC, FALSE))
    {
        goto Ret;
    }

    // pretend CRC is zeroed
    MACBytes(&DESKeyTable, (BYTE*)&dwZeroCRC, sizeof(DWORD), rgbTmp, &cbTmp,
             rgbMAC, FALSE);
    if (!SetFilePointer((HANDLE)IntToPtr(hFile), sizeof(DWORD), NULL, FILE_CURRENT))
    {
        goto Ret;
    }

    // MAC from CRC to first resource
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbCRCToRsrc1, &DESKeyTable, rgbTmp,
                        &cbTmp, rgbMAC, FALSE))
    {
        goto Ret;
    }

    // pretend image has zeroed first resource
    MACBytes(&DESKeyTable, (BYTE*)pbZeroRsrc1, cbZeroRsrc1, rgbTmp, &cbTmp,
             rgbMAC, FALSE);
    if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbZeroRsrc1, NULL, FILE_CURRENT))
    {
        goto Ret;
    }

    // MAC from first resource to second
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbRsrc1ToRsrc2, &DESKeyTable, rgbTmp,
                        &cbTmp, rgbMAC, FALSE))
    {
        goto Ret;
    }

    // pretend image has zeroed second Resource
    MACBytes(&DESKeyTable, (BYTE*)pbZeroRsrc2, cbZeroRsrc2, rgbTmp, &cbTmp,
             rgbMAC, FALSE);
    if (!SetFilePointer((HANDLE)IntToPtr(hFile), cbZeroRsrc2, NULL, FILE_CURRENT))
    {
        goto Ret;
    }

    // MAC after the resource
    if (!MACBytesOfFile((HANDLE)IntToPtr(hFile), cbPostRsrc, &DESKeyTable, rgbTmp, &cbTmp,
                        rgbMAC, TRUE))
    {
        goto Ret;
    }

    memcpy(pbMAC, rgbMAC, DES_BLOCKLEN);

    fRet = TRUE;
Ret:
    if (pbRsrcMAC)
        FreeResource(pbRsrcMAC);
    if (pbRsrcSig)
        FreeResource(pbRsrcSig);
    if(hInst)
        UnmapViewOfFile(hInst);
    if(hMapping)
        CloseHandle(hMapping);
    if (HFILE_ERROR != hFile)
        _lclose(hFile);

    return fRet;
}

DWORD GetCRCOffset(
                   LPCSTR szFile,
                   DWORD cbImage,
                   DWORD *pdwCRCOffset
                   )
{
    DWORD               dwErr = 0x1;

    HANDLE              hFileProv = NULL;
    PBYTE               pbFilePtr = NULL;
    DWORD               OldCheckSum;
    DWORD               NewCheckSum;
    PIMAGE_NT_HEADERS   pImageNTHdrs;

    HANDLE              hFileMap = NULL;


    if (INVALID_HANDLE_VALUE == (hFileProv = CreateFile(szFile,
                                GENERIC_READ | GENERIC_WRITE,
                                0,  // don't share
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                0)))
    {
        printf("Couldn't CreateFile: 0x%x\n", GetLastError());
        goto Ret;
    }

    if (NULL == (hFileMap = CreateFileMapping(
                                hFileProv,
                                NULL,
                                PAGE_READWRITE,
                                0,
                                0,
                                NULL)))
    {
        printf("Couldn't map file\n");
        goto Ret;
    }

    if (NULL == (pbFilePtr = (PBYTE)MapViewOfFile(
                                hFileMap,
                                FILE_MAP_ALL_ACCESS,
                                0,
                                0,
                                0)))
    {
        printf("Couldn't create view\n");
        goto Ret;
    }

    // compute a new checksum
    if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage,
                                                   &OldCheckSum, &NewCheckSum)))
        goto Ret;

    *pdwCRCOffset = (DWORD)((BYTE*)&pImageNTHdrs->OptionalHeader.CheckSum - pbFilePtr);
    dwErr = ERROR_SUCCESS;
Ret:
    if (pbFilePtr)
        UnmapViewOfFile(pbFilePtr);

    if (hFileMap)
        CloseHandle(hFileMap);

    if (hFileProv)
        CloseHandle(hFileProv);

    return dwErr;
}

// SetCryptMACResource
//
// slams MAC resource in file with the new MAC
//
DWORD SetCryptMACResource(
                          IN LPCSTR szFile,
                          IN DWORD dwMACVersion,
                          IN DWORD dwCRCOffset,
                          IN PBYTE pbNewMAC,
                          IN DWORD cbImage
                          )
{
    DWORD   dwErr = 0x1;

    HANDLE  hFileProv = NULL;
    HMODULE hInst = NULL;

    PBYTE   pbFilePtr = NULL;
    DWORD   cbMACOffset;

    PBYTE   pbMAC;
    DWORD   cbMAC;

    MEMORY_BASIC_INFORMATION    MemInfo;
    BYTE                        *pbStart;

    DWORD               OldCheckSum;
    DWORD               NewCheckSum;
    PIMAGE_NT_HEADERS   pImageNTHdrs;

    HANDLE  hFileMap = NULL;

    memset(&MemInfo, 0, sizeof(MemInfo));

    // Load the file as a datafile
    if (NULL == (hInst = LoadLibraryEx(szFile, NULL, LOAD_LIBRARY_AS_DATAFILE)))
    {
        printf("Couldn't load file\n");
        goto Ret;
    }
    if (!GetResourcePtr(hInst, MAC_RESOURCE_NAME, &pbMAC, &cbMAC))
    {
        printf("Couldn't find MAC placeholder\n");
        goto Ret;
    }

    // get image start address
    VirtualQuery(hInst, &MemInfo, sizeof(MemInfo));
    pbStart = (BYTE*)MemInfo.BaseAddress;

    FreeLibrary(hInst); hInst = NULL;

    cbMACOffset = (DWORD)(pbMAC - pbStart);

    if (cbMAC != (DES_BLOCKLEN + sizeof(DWORD) * 2))
    {
        printf("Attempt to replace %d zeros with new MAC!\n", cbMAC);
        goto Ret;
    }

    if (INVALID_HANDLE_VALUE == (hFileProv = CreateFile(szFile,
                                GENERIC_READ | GENERIC_WRITE,
                                0,  // don't share
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                0)))
    {
        printf("Couldn't CreateFile: 0x%x\n", GetLastError());
        goto Ret;
    }

    if (NULL == (hFileMap = CreateFileMapping(
                                hFileProv,
                                NULL,
                                PAGE_READWRITE,
                                0,
                                0,
                                NULL)))
    {
        printf("Couldn't map file\n");
        goto Ret;
    }

    if (NULL == (pbFilePtr = (PBYTE)MapViewOfFile(
                                hFileMap,
                                FILE_MAP_ALL_ACCESS,
                                0,
                                0,
                                0)))
    {
        printf("Couldn't create view\n");
        goto Ret;
    }

    // copy version, CRC offset and new sig
    CopyMemory(pbFilePtr+cbMACOffset, &dwMACVersion, sizeof(dwMACVersion));
    cbMACOffset += sizeof(dwMACVersion);
    CopyMemory(pbFilePtr+cbMACOffset, &dwCRCOffset, sizeof(dwCRCOffset));
    cbMACOffset += sizeof(dwCRCOffset);
    CopyMemory(pbFilePtr+cbMACOffset, pbNewMAC, DES_BLOCKLEN);

    // compute a new checksum
    if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage,
                                                   &OldCheckSum, &NewCheckSum)))
        goto Ret;

    CopyMemory(&pImageNTHdrs->OptionalHeader.CheckSum, &NewCheckSum, sizeof(DWORD));

    if (NULL == (pImageNTHdrs = CheckSumMappedFile(pbFilePtr, cbImage,
                                                   &OldCheckSum, &NewCheckSum)))
        goto Ret;

    if (OldCheckSum != NewCheckSum)
        goto Ret;

    dwErr = ERROR_SUCCESS;
Ret:
    if (pbFilePtr)
        UnmapViewOfFile(pbFilePtr);

    if (hFileMap)
        CloseHandle(hFileMap);

    if (hInst)
        FreeLibrary(hInst);

    if (hFileProv)
        CloseHandle(hFileProv);

    return dwErr;
}

void ShowHelp()
{
    printf("CryptoAPI Internal CSP MACing Utility\n");
    printf("maccsp <option> <filename>\n");
    printf("    options\n");
    printf("        m     MAC with no sig resource\n");
    printf("        s     MAC with sig resource\n");
    printf("        ?     Show this message\n");
}

void __cdecl main( int argc, char *argv[])
{
    LPCSTR  szInFile = NULL;
    DWORD   cbImage;
    DWORD   dwCRCOffset;
    HANDLE  hFileProv = 0;
    BYTE    rgbMAC[DES_BLOCKLEN];
    BOOL    fSigInFile = FALSE;
    DWORD   dwRet = 1;

    memset(rgbMAC, 0, sizeof(rgbMAC));

    //
    // Parse the command line.
    //

    if ((argc != 3) || (argv[1][0] == '?'))
    {
        ShowHelp();
        goto Ret;
    }
    else if ('s' == argv[1][0])
    {
        fSigInFile = TRUE;
    }
    else if ('m' == argv[1][0])
    {
        fSigInFile = FALSE;
    }
    else
    {
        ShowHelp();
        goto Ret;
    }


    szInFile = &argv[2][0];

    //
    // Command consistency checks.
    //

    if (NULL == szInFile)
    {
        printf("No input file specified.\n");
        goto Ret;
    }


    // get the file size
    if ((hFileProv = CreateFile(szInFile,
                                GENERIC_READ,
                                FILE_SHARE_READ,
                                NULL,
                                OPEN_EXISTING,
                                FILE_ATTRIBUTE_NORMAL,
                                0)) == INVALID_HANDLE_VALUE)
    {
        printf("CSP specified was not found!\n");
        goto Ret;
    }

    if (0xffffffff == (cbImage = GetFileSize(hFileProv, NULL)))
    {
        printf("CSP specified was not found!\n");
        goto Ret;
    }

    CloseHandle(hFileProv);
    hFileProv = NULL;

    if (0 != GetCRCOffset(szInFile, cbImage, &dwCRCOffset))
    {
        printf("Unable to get CRC!\n");
        goto Ret;
    }

    // calculate the MAC
    if (fSigInFile)
    {
        if (!MACTheFileWithSig(szInFile, cbImage, dwMACInFileVersion,
                               dwCRCOffset, rgbMAC))
        {
            printf("MAC failed!\n");
            goto Ret;
        }
    }
    else
    {
        if (!MACTheFileNoSig(szInFile, cbImage, dwMACInFileVersion,
                             dwCRCOffset, rgbMAC))
        {
            printf("MAC failed!\n");
            goto Ret;
        }
    }

    //
    // Place the MAC into the resource in the file
    //

    if (ERROR_SUCCESS != SetCryptMACResource(szInFile, dwMACInFileVersion,
                                             dwCRCOffset, rgbMAC, cbImage))
    {
        printf("Unable to set the MAC into the file resource!\n");
        goto Ret;
    }

    //
    // Clean up and return.
    //

    dwRet = 0;


Ret:
    exit(dwRet);

}