Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1567 lines
42 KiB

/////////////////////////////////////////////////////////////////////////////
// FILE : showsig.cpp //
// DESCRIPTION : Crypto API interface //
// AUTHOR : //
// HISTORY : //
// May 4 1998 jeffspel //
// //
// Copyright (C) 1998 Microsoft Corporation All Rights Reserved //
/////////////////////////////////////////////////////////////////////////////
#include <windows.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <rsa.h>
#include <md5.h>
#include <rc4.h>
#include <des.h>
#include <modes.h>
#define MS_INTERNAL_KEY
#define RC4_KEYSIZE 5
#define KEYSIZE512 0x48
#define KEYSIZE1024 0x88
#define SIG_RESOURCE_NUM 1
// designatred resource for in file signatures
#define CRYPT_SIG_RESOURCE_NUMBER "#666"
// MAC in file
#define MAC_RESOURCE_NUMBER "#667"
typedef struct _SECONDTIER_SIG
{
DWORD dwMagic;
DWORD cbSig;
BSAFE_PUB_KEY Pub;
} SECOND_TIER_SIG, *PSECOND_TIER_SIG;
BOOL g_fUseTestKey = TRUE;
#ifdef TEST_BUILD_EXPONENT
#pragma message("WARNING: building showsig.exe with TESTKEY enabled!")
static struct _TESTKEY
{
BSAFE_PUB_KEY PUB;
unsigned char pubmodulus[KEYSIZE512];
} TESTKEY = {
{
0x66b8443b,
0x6f5fc900,
0xa12132fe,
0xff1b06cf,
0x2f4826eb,
},
{
0x3e, 0x69, 0x4f, 0x45, 0x31, 0x95, 0x60, 0x6c,
0x80, 0xa5, 0x41, 0x99, 0x3e, 0xfc, 0x92, 0x2c,
0x93, 0xf9, 0x86, 0x23, 0x3d, 0x48, 0x35, 0x81,
0x19, 0xb6, 0x7c, 0x04, 0x43, 0xe6, 0x3e, 0xd4,
0xd5, 0x43, 0xaf, 0x52, 0xdd, 0x51, 0x20, 0xac,
0xc3, 0xca, 0xee, 0x21, 0x9b, 0x4a, 0x2d, 0xf7,
0xd8, 0x5f, 0x32, 0xeb, 0x49, 0x72, 0xb9, 0x8d,
0x2e, 0x1a, 0x76, 0x7f, 0xde, 0xc6, 0x75, 0xab,
0xaf, 0x67, 0xe0, 0xf0, 0x8b, 0x30, 0x20, 0x92,
}
};
#endif
static struct _mskey
{
BSAFE_PUB_KEY PUB;
unsigned char pubmodulus[KEYSIZE1024];
} MSKEY = {
{
0x2bad85ae,
0x883adacc,
0xb32ebd68,
0xa7ec8b06,
0x58dbeb81,
},
{
0x42, 0x34, 0xb7, 0xab, 0x45, 0x0f, 0x60, 0xcd,
0x8f, 0x77, 0xb5, 0xd1, 0x79, 0x18, 0x34, 0xbe,
0x66, 0xcb, 0x5c, 0x66, 0x4a, 0x9f, 0x03, 0x18,
0x13, 0x36, 0x8e, 0x88, 0x21, 0x78, 0xb1, 0x94,
0xa1, 0xd5, 0x8f, 0x8c, 0xa5, 0xd3, 0x9f, 0x86,
0x43, 0x89, 0x05, 0xa0, 0xe3, 0xee, 0xe2, 0xd0,
0xe5, 0x1d, 0x5f, 0xaf, 0xff, 0x85, 0x71, 0x7a,
0x0a, 0xdb, 0x2e, 0xd8, 0xc3, 0x5f, 0x2f, 0xb1,
0xf0, 0x53, 0x98, 0x3b, 0x44, 0xee, 0x7f, 0xc9,
0x54, 0x26, 0xdb, 0xdd, 0xfe, 0x1f, 0xd0, 0xda,
0x96, 0x89, 0xc8, 0x9e, 0x2b, 0x5d, 0x96, 0xd1,
0xf7, 0x52, 0x14, 0x04, 0xfb, 0xf8, 0xee, 0x4d,
0x92, 0xd1, 0xb6, 0x37, 0x6a, 0xe0, 0xaf, 0xde,
0xc7, 0x41, 0x06, 0x7a, 0xe5, 0x6e, 0xb1, 0x8c,
0x8f, 0x17, 0xf0, 0x63, 0x8d, 0xaf, 0x63, 0xfd,
0x22, 0xc5, 0xad, 0x1a, 0xb1, 0xe4, 0x7a, 0x6b,
0x1e, 0x0e, 0xea, 0x60, 0x56, 0xbd, 0x49, 0xd0,
}
};
static struct _key
{
BSAFE_PUB_KEY PUB;
unsigned char pubmodulus[KEYSIZE1024];
} KEY = {
{
0x3fcbf1a9,
0x08f597db,
0xe4aecab4,
0x75360f90,
0x9d6c0f00,
},
{
0x85, 0xdd, 0x9b, 0xf4, 0x4d, 0x0b, 0xc4, 0x96,
0x3e, 0x79, 0x86, 0x30, 0x6d, 0x27, 0x31, 0xee,
0x4a, 0x85, 0xf5, 0xff, 0xbb, 0xa9, 0xbd, 0x81,
0x86, 0xf2, 0x4f, 0x87, 0x6c, 0x57, 0x55, 0x19,
0xe4, 0xf4, 0x49, 0xa3, 0x19, 0x27, 0x08, 0x82,
0x9e, 0xf9, 0x8a, 0x8e, 0x41, 0xd6, 0x91, 0x71,
0x47, 0x48, 0xee, 0xd6, 0x24, 0x2d, 0xdd, 0x22,
0x72, 0x08, 0xc6, 0xa7, 0x34, 0x6f, 0x93, 0xd2,
0xe7, 0x72, 0x57, 0x78, 0x7a, 0x96, 0xc1, 0xe1,
0x47, 0x38, 0x78, 0x43, 0x53, 0xea, 0xf3, 0x88,
0x82, 0x66, 0x41, 0x43, 0xd4, 0x62, 0x44, 0x01,
0x7d, 0xb2, 0x16, 0xb3, 0x50, 0x89, 0xdb, 0x0a,
0x93, 0x17, 0x02, 0x02, 0x46, 0x49, 0x79, 0x76,
0x59, 0xb6, 0xb1, 0x2b, 0xfc, 0xb0, 0x9a, 0x21,
0xe6, 0xfa, 0x2d, 0x56, 0x07, 0x36, 0xbc, 0x13,
0x7f, 0x1c, 0xde, 0x55, 0xfb, 0x0d, 0x67, 0x0f,
0xc2, 0x17, 0x45, 0x8a, 0x14, 0x2b, 0xba, 0x55,
}
};
static struct _key2
{
BSAFE_PUB_KEY PUB;
unsigned char pubmodulus[KEYSIZE1024];
} KEY2 = {
{
0x685fc690,
0x97d49b6b,
0x1dccd9d2,
0xa5ec9b52,
0x64fd29d7,
},
{
0x03, 0x8c, 0xa3, 0x9e, 0xfb, 0x93, 0xb6, 0x72,
0x2a, 0xda, 0x6f, 0xa5, 0xec, 0x26, 0x39, 0x58,
0x41, 0xcd, 0x3f, 0x49, 0x10, 0x4c, 0xcc, 0x7e,
0x23, 0x94, 0xf9, 0x5d, 0x9b, 0x2b, 0xa3, 0x6b,
0xe8, 0xec, 0x52, 0xd9, 0x56, 0x64, 0x74, 0x7c,
0x44, 0x6f, 0x36, 0xb7, 0x14, 0x9d, 0x02, 0x3c,
0x0e, 0x32, 0xb6, 0x38, 0x20, 0x25, 0xbd, 0x8c,
0x9b, 0xd1, 0x46, 0xa7, 0xb3, 0x58, 0x4a, 0xb7,
0xdd, 0x0e, 0x38, 0xb6, 0x16, 0x44, 0xbf, 0xc1,
0xca, 0x4d, 0x6a, 0x9f, 0xcb, 0x6f, 0x3c, 0x5f,
0x03, 0xab, 0x7a, 0xb8, 0x16, 0x70, 0xcf, 0x98,
0xd0, 0xca, 0x8d, 0x25, 0x57, 0x3a, 0x22, 0x8b,
0x44, 0x96, 0x37, 0x51, 0x30, 0x00, 0x92, 0x1b,
0x03, 0xb9, 0xf9, 0x0d, 0xb3, 0x1a, 0xe2, 0xb4,
0xc5, 0x7b, 0xc9, 0x4b, 0xe2, 0x42, 0x25, 0xfe,
0x3d, 0x42, 0xfa, 0x45, 0xc6, 0x94, 0xc9, 0x8e,
0x87, 0x7e, 0xf6, 0x68, 0x90, 0x30, 0x65, 0x10,
}
};
void
EncryptKey(
BYTE *pdata,
DWORD size,
BYTE val)
{
RC4_KEYSTRUCT key;
BYTE RealKey[RC4_KEYSIZE] = {0xa2, 0x17, 0x9c, 0x98, 0xca};
DWORD index;
for (index = 0; index < RC4_KEYSIZE; index++)
{
RealKey[index] = RealKey[index] ^ val;
}
rc4_key(&key, RC4_KEYSIZE, RealKey);
rc4(&key, size, pdata);
}
void
MD5HashData(
BYTE *pb,
DWORD cb,
BYTE *pbHash)
{
MD5_CTX HashState;
MD5Init(&HashState);
MD5Update(&HashState, pb, cb);
// Finish the hash
MD5Final(&HashState);
memcpy(pbHash, HashState.digest, 16);
}
BOOL
CheckSignature(
BYTE *pbKey,
DWORD cbKey,
BYTE *pbSig,
DWORD cbSig,
BYTE *pbHash,
BOOL fUnknownLen)
{
BYTE rgbResult[KEYSIZE1024];
BYTE rgbSig[KEYSIZE1024];
BYTE rgbKey[sizeof(BSAFE_PUB_KEY) + KEYSIZE1024];
BYTE rgbKeyHash[16];
BYTE *pbSecondKey;
DWORD cbSecondKey;
BYTE *pbKeySig;
PSECOND_TIER_SIG pSecondTierSig;
LPBSAFE_PUB_KEY pTmp;
BOOL fRet = FALSE;
memset(rgbResult, 0, KEYSIZE1024);
memset(rgbSig, 0, KEYSIZE1024);
// just check the straight signature if version is 1
pTmp = (LPBSAFE_PUB_KEY)pbKey;
// check if sig length is the same as the key length
if (fUnknownLen || (cbSig == pTmp->keylen))
{
memcpy(rgbSig, pbSig, pTmp->keylen);
BSafeEncPublic(pTmp, rgbSig, rgbResult);
if (RtlEqualMemory(pbHash, rgbResult, 16) &&
rgbResult[cbKey-1] == 0 &&
rgbResult[cbKey-2] == 1 &&
rgbResult[16] == 0 &&
rgbResult[17] == 0xFF)
{
fRet = TRUE;
goto Ret;
}
}
// check the the second tier signature if the magic equals 2
pSecondTierSig = (PSECOND_TIER_SIG)pbSig;
if (0x00000002 != pSecondTierSig->dwMagic)
goto Ret;
if (0x31415352 != pSecondTierSig->Pub.magic)
goto Ret;
// assign the pointers
cbSecondKey = sizeof(BSAFE_PUB_KEY) + pSecondTierSig->Pub.keylen;
pbSecondKey = pbSig + (sizeof(SECOND_TIER_SIG) - sizeof(BSAFE_PUB_KEY));
pbKeySig = pbSecondKey + cbSecondKey;
// hash the second tier key
MD5HashData(pbSecondKey, cbSecondKey, rgbKeyHash);
// Decrypt the signature data on the second tier key
memset(rgbResult, 0, sizeof(rgbResult));
memset(rgbSig, 0, sizeof(rgbSig));
memcpy(rgbSig, pbKeySig, pSecondTierSig->cbSig);
BSafeEncPublic(pTmp, rgbSig, rgbResult);
if ((FALSE == RtlEqualMemory(rgbKeyHash, rgbResult, 16)) ||
rgbResult[cbKey-1] != 0 ||
rgbResult[cbKey-2] != 1 ||
rgbResult[16] != 0 ||
rgbResult[17] != 0)
{
goto Ret;
}
// Decrypt the signature data on the CSP
memset(rgbResult, 0, sizeof(rgbResult));
memset(rgbSig, 0, sizeof(rgbSig));
memset(rgbKey, 0, sizeof(rgbKey));
memcpy(rgbSig, pbKeySig + pSecondTierSig->cbSig, pSecondTierSig->cbSig);
memcpy(rgbKey, pbSecondKey, cbSecondKey);
pTmp = (LPBSAFE_PUB_KEY)rgbKey;
BSafeEncPublic(pTmp, rgbSig, rgbResult);
if (RtlEqualMemory(pbHash, rgbResult, 16) &&
rgbResult[cbKey-1] == 0 &&
rgbResult[cbKey-2] == 1 &&
rgbResult[16] == 0)
{
fRet = TRUE;
if (0xff != rgbResult[18])
{
DWORD dwI;
printf("2nd Tier signature performed by ");
for (dwI = 18; 0xff != rgbResult[dwI]; dwI += 1)
printf("%c", rgbResult[dwI]);
printf(".\n");
}
}
Ret:
return fRet;
}
// Given hInst, allocs and returns pointers to SIG and 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;
}
// GetCryptSignatureResource
//
DWORD
GetCryptSignatureResource(
LPCSTR szFile,
PBYTE *ppbNewSig,
DWORD *pcbNewSig)
{
DWORD dwErr = 0x1;
BYTE *pbSig;
HMODULE hInst = NULL;
// 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,
CRYPT_SIG_RESOURCE_NUMBER,
&pbSig,
pcbNewSig))
{
printf("Couldn't find signature placeholder\n");
goto Ret;
}
if (NULL == (*ppbNewSig = (BYTE*)LocalAlloc(LMEM_ZEROINIT, *pcbNewSig)))
goto Ret;
memcpy(*ppbNewSig, pbSig, *pcbNewSig);
dwErr = ERROR_SUCCESS;
Ret:
if (hInst)
FreeLibrary(hInst);
return dwErr;
}
#define CSP_TO_BE_MACED_CHUNK 4096
// 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;
}
}
}
// 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;
}
BYTE rgbMACDESKey[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
BOOL
MACTheFile(
LPCSTR pszImage,
DWORD cbImage)
{
HMODULE hInst = 0;
MEMORY_BASIC_INFORMATION MemInfo;
BYTE *pbRsrcMAC;
DWORD cbRsrcMAC;
BYTE *pbRsrcSig;
DWORD cbRsrcSig;
BYTE *pbStart;
BYTE rgbMAC[DES_BLOCKLEN];
BYTE *pbZeroRsrc = NULL;
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 *pdwMACInFileVer;
DWORD *pdwCRCOffset;
DWORD dwCRCOffset;
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;
DWORD i;
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 = (HMODULE)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_NUMBER, &pbRsrcMAC, &cbRsrcMAC))
goto Ret;
// display the MAC
printf("--- MAC Resource ---\n");
for (i = 0; i < cbRsrcMAC; i++)
{
printf("0x%02X ", pbRsrcMAC[i]);
if (((i + 1) % 8) == 0)
printf("\n");
}
if (0 != (i % 8))
printf("\n");
// the Signature resource
if (!GetResourcePtr(hInst, CRYPT_SIG_RESOURCE_NUMBER, &pbRsrcSig, &cbRsrcSig))
{
pbRsrcSig = NULL;
cbRsrcSig = 0;
}
if (cbRsrcMAC < (sizeof(DWORD) * 2))
goto Ret;
// check the MAC in file version and get the CRC offset
pdwMACInFileVer = (DWORD*)pbRsrcMAC;
pdwCRCOffset = (DWORD*)(pbRsrcMAC + sizeof(DWORD));
dwCRCOffset = *pdwCRCOffset;
if ((0x00000100 != *pdwMACInFileVer) || (dwCRCOffset > cbImage))
goto Ret;
if (DES_BLOCKLEN != (cbRsrcMAC - (sizeof(DWORD) * 2)))
{
goto Ret;
}
// create a zero byte Sig
pbZeroRsrc = (LPBYTE)LocalAlloc(LPTR, max(cbRsrcMAC, cbRsrcSig));
// set up the pointers
pbPostCRC = pbStart + *pdwCRCOffset + sizeof(DWORD);
if (NULL == pbRsrcSig) // No sig resource
{
cbCRCToRsrc1 = (DWORD)(pbRsrcMAC - pbPostCRC);
pbRsrc1ToRsrc2 = pbRsrcMAC + cbRsrcMAC;
cbRsrc1ToRsrc2 = 0;
pbPostRsrc = pbRsrcMAC + cbRsrcMAC;
cbPostRsrc = (cbImage - (DWORD)(pbPostRsrc - pbStart));
// zero pointers
pbZeroRsrc1 = pbZeroRsrc;
cbZeroRsrc1 = cbRsrcMAC;
pbZeroRsrc2 = pbZeroRsrc;
cbZeroRsrc2 = 0;
}
else 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 = pbZeroRsrc;
cbZeroRsrc1 = cbRsrcMAC;
pbZeroRsrc2 = pbZeroRsrc;
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 = pbZeroRsrc;
cbZeroRsrc1 = cbRsrcSig;
pbZeroRsrc2 = pbZeroRsrc;
cbZeroRsrc2 = cbRsrcMAC;
}
// init the key table
deskey(&DESKeyTable, rgbMACDESKey);
// 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;
}
if (0 != memcmp(rgbMAC, pbRsrcMAC + sizeof(DWORD) * 2, DES_BLOCKLEN))
goto Ret;
fRet = TRUE;
Ret:
if (hInst)
UnmapViewOfFile(hInst);
if (hMapping)
CloseHandle(hMapping);
if (HFILE_ERROR != hFile)
_lclose(hFile);
if (NULL != pbZeroRsrc)
LocalFree(pbZeroRsrc);
return fRet;
}
// **********************************************************************
// SelfMACCheck performs a DES MAC on the binary image of this DLL
// **********************************************************************
BOOL
SelfMACCheck(
IN LPCSTR pszImage)
{
HFILE hFileProv = HFILE_ERROR;
DWORD cbImage;
OFSTRUCT ImageInfoBuf;
HMODULE hInst = NULL;
PBYTE pbMAC;
DWORD cbMAC;
BOOL fRet = FALSE;
// check if the MAC resource is in the CSP and exit if not
// Load the file as a datafile
if (NULL == (hInst = LoadLibraryEx(pszImage,
NULL,
LOAD_LIBRARY_AS_DATAFILE)))
{
fRet = TRUE;
goto Ret;
}
if (!GetResourcePtr(hInst, MAC_RESOURCE_NUMBER, &pbMAC, &cbMAC))
{
fRet = TRUE;
goto Ret;
}
FreeLibrary(hInst);
hInst = NULL;
// Check file size
if (HFILE_ERROR == (hFileProv = OpenFile(pszImage, &ImageInfoBuf, OF_READ)))
{
printf("FAILURE - Unable to open the requested file\n");
goto Ret;
}
if (0xffffffff == (cbImage = GetFileSize((HANDLE)IntToPtr(hFileProv), NULL)))
{
printf("FAILURE - Unable to open the requested file\n");
goto Ret;
}
_lclose(hFileProv);
hFileProv = HFILE_ERROR;
if (!MACTheFile(pszImage, cbImage))
{
printf("FAILURE - The MAC resource does not verify!\n");
goto Ret;
}
else
printf("MAC Verifies.\n\n");
fRet = TRUE;
Ret:
if (hInst)
{
FreeLibrary(hInst);
}
if (HFILE_ERROR != hFileProv)
_lclose(hFileProv);
return fRet;
}
#define CSP_TO_BE_HASHED_CHUNK 4096
// Given hFile, reads the specified number of bytes (cbToBeHashed) from the file
// and hashes these bytes. The function does this in chunks.
BOOL
HashBytesOfFile(
IN HFILE hFile,
IN DWORD cbToBeHashed,
IN OUT MD5_CTX *pMD5Hash)
{
BYTE rgbChunk[CSP_TO_BE_HASHED_CHUNK];
DWORD cbRemaining = cbToBeHashed;
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_HASHED_CHUNK)
cbToRead = cbRemaining;
else
cbToRead = CSP_TO_BE_HASHED_CHUNK;
if (!ReadFile((HANDLE)IntToPtr(hFile), rgbChunk, cbToRead, &dwBytesRead, NULL))
goto Ret;
if (dwBytesRead != cbToRead)
goto Ret;
MD5Update(pMD5Hash, rgbChunk, dwBytesRead);
cbRemaining -= cbToRead;
}
fRet = TRUE;
Ret:
return fRet;
}
BOOL
HashTheFile(
LPCSTR pszImage,
DWORD cbImage,
BYTE **ppbSig,
DWORD *pcbSig,
BYTE *pbHash)
{
HMODULE hInst = 0;
MEMORY_BASIC_INFORMATION MemInfo;
BYTE *pbRsrcSig;
DWORD cbRsrcSig;
BYTE *pbStart;
BYTE *pbZeroRsrc = NULL;
MD5_CTX MD5Hash;
BYTE *pbPostCRC; // pointer to just after CRC
DWORD cbCRCToSig; // number of bytes from CRC to sig
DWORD cbPostSig; // size - (already hashed + signature size)
BYTE *pbPostSig;
DWORD *pdwSigInFileVer;
DWORD *pdwCRCOffset;
DWORD dwCRCOffset;
DWORD dwZeroCRC = 0;
DWORD dwBytesRead = 0;
OFSTRUCT ImageInfoBuf;
HFILE hFile = HFILE_ERROR;
BOOL fRet = FALSE;
memset(&MD5Hash, 0, sizeof(MD5Hash));
memset(&MemInfo, 0, sizeof(MemInfo));
// Load the file as a datafile
if (NULL == (hInst = LoadLibraryEx(pszImage, NULL, LOAD_LIBRARY_AS_DATAFILE)))
goto Ret;
// get image start address
VirtualQuery(hInst, &MemInfo, sizeof(MemInfo));
pbStart = (BYTE*)MemInfo.BaseAddress;
// the resources signature
if ((NULL == ppbSig) || !GetResourcePtr(hInst, CRYPT_SIG_RESOURCE_NUMBER, &pbRsrcSig, &cbRsrcSig))
{
dwCRCOffset = 0;
pbPostCRC = NULL;
cbCRCToSig = 0;
pbPostSig = NULL;
cbPostSig = cbImage;
cbRsrcSig = 0;
if (NULL != pcbSig)
*pcbSig = 0;
}
else
{
if (cbRsrcSig < (sizeof(DWORD) * 2))
goto Ret;
// check the sig in file version and get the CRC offset
pdwSigInFileVer = (DWORD*)pbRsrcSig;
pdwCRCOffset = (DWORD*)(pbRsrcSig + sizeof(DWORD));
dwCRCOffset = *pdwCRCOffset;
if ((0x00000100 != *pdwSigInFileVer) || (dwCRCOffset > cbImage))
goto Ret;
// create a zero byte signature
if (NULL == (pbZeroRsrc = (BYTE*)LocalAlloc(LMEM_ZEROINIT, cbRsrcSig)))
goto Ret;
memcpy(pbZeroRsrc, pbRsrcSig, sizeof(DWORD) * 2);
pbPostCRC = pbStart + *pdwCRCOffset + sizeof(DWORD);
cbCRCToSig = (DWORD)(pbRsrcSig - pbPostCRC);
pbPostSig = pbRsrcSig + cbRsrcSig;
cbPostSig = (cbImage - (DWORD)(pbPostSig - pbStart));
// allocate the real signature and copy the resource sig into the real sig
*pcbSig = cbRsrcSig - (sizeof(DWORD) * 2);
if (NULL == (*ppbSig = (BYTE*)LocalAlloc(LMEM_ZEROINIT, *pcbSig)))
goto Ret;
memcpy(*ppbSig, pbRsrcSig + (sizeof(DWORD) * 2), *pcbSig);
}
FreeLibrary(hInst);
hInst = 0;
// hash over the relevant data
{
if (HFILE_ERROR == (hFile = OpenFile(pszImage, &ImageInfoBuf, OF_READ)))
{
goto Ret;
}
MD5Init(&MD5Hash);
if (0 != dwCRCOffset)
{
// hash up to the CRC
if (!HashBytesOfFile(hFile, dwCRCOffset, &MD5Hash))
goto Ret;
// pretend CRC is zeroed
MD5Update(&MD5Hash, (BYTE*)&dwZeroCRC, sizeof(DWORD));
if (!ReadFile((HANDLE)IntToPtr(hFile), (BYTE*)&dwZeroCRC, sizeof(DWORD),
&dwBytesRead, NULL))
{
goto Ret;
}
}
if (0 != cbRsrcSig)
{
// hash from CRC to sig resource
if (!HashBytesOfFile(hFile, cbCRCToSig, &MD5Hash))
goto Ret;
// pretend image has zeroed sig
MD5Update(&MD5Hash, pbZeroRsrc, cbRsrcSig);
if (!ReadFile((HANDLE)IntToPtr(hFile), (BYTE*)pbZeroRsrc, cbRsrcSig,
&dwBytesRead, NULL))
{
goto Ret;
}
}
// hash after the sig resource
if (!HashBytesOfFile(hFile, cbPostSig, &MD5Hash))
goto Ret;
// Finish the hash
MD5Final(&MD5Hash);
memcpy(pbHash, MD5Hash.digest, MD5DIGESTLEN);
}
fRet = TRUE;
Ret:
if (pbZeroRsrc)
LocalFree(pbZeroRsrc);
if (hInst)
FreeLibrary(hInst);
if (HFILE_ERROR != hFile)
_lclose(hFile);
return fRet;
}
/*
- CheckAllSignatures
-
* Purpose:
* Check signature against all keys
*
*
* Returns:
* BOOL
*/
BOOL
CheckAllSignatures(
BYTE *pbSig,
DWORD cbSig,
BYTE *pbHash,
BOOL fUnknownLen)
{
BYTE rgbKey[sizeof(BSAFE_PUB_KEY) + KEYSIZE1024];
BYTE rgbKey2[sizeof(BSAFE_PUB_KEY) + KEYSIZE1024];
BYTE rgbMSKey[sizeof(BSAFE_PUB_KEY) + KEYSIZE1024];
#ifdef TEST_BUILD_EXPONENT
BYTE rgbTestKey[sizeof(BSAFE_PUB_KEY) + KEYSIZE512];
HMODULE hMod;
HRSRC hRes;
HGLOBAL pRes;
DWORD dwSize;
#endif
BOOL fRet = FALSE;
// decrypt the keys once for each process
#ifdef TEST_BUILD_EXPONENT
hMod = GetModuleHandle("advapi32.dll");
if (hRes = FindResource(hMod, (LPCTSTR) IDR_PUBKEY1, RT_RCDATA))
{
if (pRes = LoadResource(hMod, hRes))
{
dwSize = SizeofResource(hMod, hRes);
memcpy(&TESTKEY, (CHAR *) pRes, dwSize);
}
}
#endif
memcpy(rgbKey, (BYTE*)&KEY, sizeof(BSAFE_PUB_KEY) + KEYSIZE1024);
EncryptKey(rgbKey, sizeof(BSAFE_PUB_KEY) + KEYSIZE1024, 0);
memcpy(rgbMSKey, (BYTE*)&MSKEY, sizeof(BSAFE_PUB_KEY) + KEYSIZE1024);
EncryptKey(rgbMSKey, sizeof(BSAFE_PUB_KEY) + KEYSIZE1024, 1);
memcpy(rgbKey2, (BYTE*)&KEY2, sizeof(BSAFE_PUB_KEY) + KEYSIZE1024);
EncryptKey(rgbKey2, sizeof(BSAFE_PUB_KEY) + KEYSIZE1024, 2);
#ifdef TEST_BUILD_EXPONENT
memcpy(rgbTestKey, (BYTE*)&TESTKEY, sizeof(BSAFE_PUB_KEY) + KEYSIZE512);
EncryptKey(rgbTestKey, sizeof(BSAFE_PUB_KEY) + KEYSIZE512, 3);
#ifdef WIN95
TESTKEY.PUB.pubexp = TEST_BUILD_EXPONENT;
#else
TESTKEY.PUB.pubexp = USER_SHARED_DATA->CryptoExponent;
#endif // WIN95
#endif // TEST_BUILD_EXPONENT
if (TRUE == (fRet = CheckSignature(rgbKey, 128, pbSig,
cbSig, pbHash, fUnknownLen)))
{
printf("Checked against the retail CSP key\n" );
fRet = TRUE;
goto Ret;
}
if (g_fUseTestKey)
{
if (TRUE == (fRet = CheckSignature(rgbMSKey, 128, pbSig,
cbSig, pbHash, fUnknownLen)))
{
printf("Checked against the Internal Only \"Enigma\" Key\n" );
fRet = TRUE;
goto Ret;
}
}
if (TRUE == (fRet = CheckSignature(rgbKey2, 128, pbSig,
cbSig, pbHash, fUnknownLen)))
{
printf("Checked against retail Key2\n" );
fRet = TRUE;
goto Ret;
}
#ifdef TEST_BUILD_EXPONENT
if (TRUE == (fRet = CheckSignature(rgbTestKey, 64, pbSig,
cbSig, pbHash, fUnknownLen)))
{
printf("Checked against Test key\n" );
fRet = TRUE;
goto Ret;
}
#endif // TEST_BUILD_EXPONENT
Ret:
return fRet;
}
/*
- CheckSignatureInFile
-
* Purpose:
* Check signature which is in the resource in the file
*
*
* Parameters:
* IN pszImage - address of file
*
* Returns:
* BOOL
*/
BOOL
CheckSignatureInFile(
LPCSTR pszImage)
{
HFILE hFileProv = HFILE_ERROR;
DWORD cbImage;
BYTE *pbSig = NULL;
DWORD cbSig;
BYTE rgbHash[MD5DIGESTLEN];
OFSTRUCT ImageInfoBuf;
BOOL fRet = FALSE;
// Check file size
{
if (HFILE_ERROR == (hFileProv = OpenFile(pszImage, &ImageInfoBuf, OF_READ)))
{
SetLastError((DWORD) NTE_PROV_DLL_NOT_FOUND);
goto Ret;
}
if (0xffffffff == (cbImage = GetFileSize((HANDLE)IntToPtr(hFileProv), NULL)))
goto Ret;
_lclose(hFileProv);
hFileProv = HFILE_ERROR;
}
if (!HashTheFile(pszImage, cbImage, &pbSig, &cbSig, rgbHash))
goto Ret;
// check signature against all public keys
if (!CheckAllSignatures(pbSig, cbSig, rgbHash, FALSE))
goto Ret;
fRet = TRUE;
Ret:
if (HFILE_ERROR != hFileProv)
_lclose(hFileProv);
if (pbSig)
LocalFree(pbSig);
return fRet;
}
/*++
ShowHelp:
This routine displays a short help message to the given output stream.
Arguments:
ostr - The output stream to receive the help message.
Return Value:
None
Author:
Jeff Spelman
--*/
void
ShowHelp(
void)
{
printf("CryptoAPI Display Signature Utility\n");
printf(" showsig <filename>\n");
printf("or\n");
printf(" showsig -s <rsrcfile> <filename>\n");
printf("or\n");
printf(" showsig -b <sigfile> <filename>\n");
printf("Other options:\n");
printf(" +t - Enable the use of the Enigma key\n");
printf(" (On by default).\n");
printf(" -t - Disable the use of the Enigma key\n");
}
/*++
main:
This is the main entry point of the application.
Arguments:
argc - Count of arguments
argv - array of arguments
Return Value:
0 - Success
1 - Error
Author:
Jeff Spelman
--*/
extern "C" void __cdecl
main(
int argc,
char *argv[])
{
TCHAR szFullPath[MAX_PATH];
HANDLE hFile = INVALID_HANDLE_VALUE;
HMODULE hResFile = NULL;
DWORD exStatus = 1;
LPCTSTR szInFile = NULL;
LPCTSTR szResFile = NULL;
LPCTSTR szSigFile = NULL;
LPTSTR szTail;
BOOL fOutput = FALSE;
DWORD i;
HRSRC hRes;
DWORD cbImage;
BOOL fFreeSignature = FALSE;
BYTE rgbHash[MD5DIGESTLEN];
LPBYTE pbSignature = NULL;
DWORD cbSignatureLen;
//
// Parse the command line.
//
for (i = 1; i < (DWORD)argc; i++)
{
if (0 == _stricmp("-h", argv[i]))
{
ShowHelp();
exStatus = 1;
goto ErrorExit;
}
else if (0 == _stricmp("-s", argv[i]))
{
i += 1;
if ((NULL != szResFile) || (i >= (DWORD)argc))
{
ShowHelp();
exStatus = 1;
goto ErrorExit;
}
szResFile = argv[i];
}
else if (0 == _stricmp("-b", argv[i]))
{
i += 1;
if ((NULL != szSigFile) || (i >= (DWORD)argc))
{
ShowHelp();
exStatus = 1;
goto ErrorExit;
}
szSigFile = argv[i];
}
else if (0 == _stricmp("-t", argv[i]))
{
g_fUseTestKey = FALSE;
}
else if (0 == _stricmp("+t", argv[i]))
{
g_fUseTestKey = TRUE;
}
else
{
if (NULL != szInFile)
{
ShowHelp();
exStatus = 1;
goto ErrorExit;
}
szInFile = argv[i];
}
}
//
// Command consistency checks.
//
if (NULL == szInFile)
{
printf("No input file specified.\n");
ShowHelp();
exStatus = 4 ;
goto ErrorExit;
}
i = GetFullPathName(szInFile,
sizeof(szFullPath) / sizeof(TCHAR),
szFullPath,
&szTail);
if (0 == i)
{
printf("Can't expand file name.\n");
exStatus = 4;
goto ErrorExit;
}
else if (sizeof(szFullPath) / sizeof(TCHAR) < i)
{
printf("File path too long.\n");
exStatus = 4;
goto ErrorExit;
}
szInFile = szFullPath;
//
// If the DLL has a FIPS 140-1 MAC resource then check it
//
if (!SelfMACCheck(szInFile))
exStatus = 3 ;
//
// Where's our signature?
//
if (NULL != szSigFile)
{
//
// This file has an accompanying binary signature file.
// Verify the file, and get its length.
//
hFile = CreateFile(szInFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
printf("Unable to open the CSP file!\n");
exStatus = 2 ;
goto ErrorExit;
}
cbImage = GetFileSize(hFile, NULL);
if (0 == cbImage)
{
printf("Unable to get size of CSP file!\n");
exStatus = 2 ;
goto ErrorExit;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
//
// Get the signature from the file.
//
hFile = CreateFile(szSigFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
printf("Unable to open the Signature file!\n");
exStatus = 2 ;
goto ErrorExit;
}
cbSignatureLen = GetFileSize(hFile, NULL);
if (0 == cbImage)
{
printf("Unable to get size of the Signature file!\n");
exStatus = 2 ;
goto ErrorExit;
}
pbSignature = (LPBYTE)LocalAlloc(LPTR, cbSignatureLen);
if (NULL == pbSignature)
{
printf("No memory!\n");
exStatus = 2;
goto ErrorExit;
}
fFreeSignature = TRUE;
if (!ReadFile(hFile,
pbSignature,
cbSignatureLen,
&cbSignatureLen,
NULL))
{
printf("Unable to read the Signature file!\n");
exStatus = 2 ;
goto ErrorExit;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
// display the signature
printf("--- Signature ---\n");
for (i = 0; i < cbSignatureLen; i++)
{
printf("0x%02X ", pbSignature[i]);
if (((i + 1) % 8) == 0)
printf("\n");
}
if (0 != (i % 8))
printf("\n");
if (!HashTheFile(szInFile, cbImage, NULL, NULL, rgbHash))
{
printf("Unable to hash the CSP file!\n");
exStatus = 2 ;
goto ErrorExit;
}
// check signature against all public keys
if (!CheckAllSignatures(pbSignature, cbSignatureLen, rgbHash, FALSE))
{
printf("The signature on %s FAILED to verify!\n", szInFile);
exStatus = 1 ;
}
else
{
printf("The signature on %s VERIFIED!\n", szInFile);
exStatus = 0;
}
}
else if (NULL != szResFile)
{
//
// This file has an accompanying signature resource file.
// Verify the file, and get its length.
//
hFile = CreateFile(szInFile,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
printf("Unable to open the CSP file!\n");
exStatus = 2 ;
goto ErrorExit;
}
cbImage = GetFileSize(hFile, NULL);
if (0 == cbImage)
{
printf("Unable to get size of CSP file!\n");
exStatus = 2 ;
goto ErrorExit;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
//
// Load the resource from the associated resource file.
//
hResFile = LoadLibraryEx(szResFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (NULL == hResFile)
{
printf("Unable to load the resource file!\n");
exStatus = 2 ;
goto ErrorExit;
}
hRes = FindResource(hResFile, (LPCTSTR)SIG_RESOURCE_NUM, RT_RCDATA);
if (NULL == hRes)
{
printf("Unable to find the signature in the resource file!\n");
exStatus = 2 ;
goto ErrorExit;
}
pbSignature = (LPBYTE)LoadResource(hResFile, hRes);
if (NULL == pbSignature)
{
printf("Unable to find the signature in the resource file!\n");
exStatus = 2 ;
goto ErrorExit;
}
cbSignatureLen = SizeofResource(hResFile, hRes);
// display the signature
printf("--- Signature ---\n");
for (i = 0; i < cbSignatureLen; i++)
{
printf("0x%02X ", pbSignature[i]);
if (((i + 1) % 8) == 0)
printf("\n");
}
if (0 != (i % 8))
printf("\n");
if (!HashTheFile(szInFile, cbImage, NULL, NULL, rgbHash))
{
printf("Unable to hash the CSP file!\n");
exStatus = 2 ;
goto ErrorExit;
}
// check signature against all public keys
if (!CheckAllSignatures(pbSignature, cbSignatureLen, rgbHash, FALSE))
{
printf("The signature on %s FAILED to verify!\n", szInFile);
exStatus = 1 ;
}
else
{
printf("The signature on %s VERIFIED!\n", szInFile);
exStatus = 0;
}
}
else
{
//
// Get the signature from the resource in the file
//
if (ERROR_SUCCESS != GetCryptSignatureResource(szInFile,
&pbSignature,
&cbSignatureLen))
{
printf("Unable to get the signature from the file resource!\n");
exStatus = 2 ;
goto ErrorExit;
}
// display the signature
printf("--- Signature ---\n");
for (i = 0; i < cbSignatureLen; i++)
{
printf("0x%02X ", pbSignature[i]);
if (((i + 1) % 8) == 0)
printf("\n");
}
if (0 != (i % 8))
printf("\n");
//
// check the signature against the file
//
if (CheckSignatureInFile(szInFile))
{
printf("The signature on %s VERIFIED!\n", szInFile);
exStatus = 0;
}
else
{
printf("The signature on %s FAILED to verify!\n", szInFile);
exStatus = 1 ;
}
}
//
// Clean up and return.
//
ErrorExit:
if (fFreeSignature && (NULL != pbSignature))
LocalFree(pbSignature);
if (INVALID_HANDLE_VALUE != hFile)
CloseHandle(hFile);
if (NULL != hResFile)
FreeLibrary(hResFile);
exit(exStatus);
}