Leaked source code of windows server 2003
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.
 
 
 
 
 
 

817 lines
25 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: fencrypt.cpp
//
// Contents: File encryption tool. Encrypts a file looking in the MY
// system certificate store for the specifed subject common name
// with exchange private keys.
//
//--------------------------------------------------------------------------
#include <windows.h>
#include <assert.h>
#include "wincrypt.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <memory.h>
//+-------------------------------------------------------------------------
// Helper function to make MBCS from Unicode string
//--------------------------------------------------------------------------
BOOL WINAPI MkMBStr(PBYTE pbBuff, DWORD cbBuff, LPCWSTR wsz, char ** pszMB) {
DWORD cbConverted;
assert(pszMB != NULL);
*pszMB = NULL;
if(wsz == NULL)
return(TRUE);
// how long is the mb string
cbConverted = WideCharToMultiByte( 0,
0,
wsz,
-1,
NULL,
0,
NULL,
NULL);
// get a buffer long enough
if(pbBuff != NULL && cbConverted < cbBuff)
*pszMB = (char *) pbBuff;
else
*pszMB = (char *) malloc(cbConverted);
if(*pszMB == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return(FALSE);
}
// now convert to MB
WideCharToMultiByte(0,
0,
wsz,
-1,
*pszMB,
cbConverted,
NULL,
NULL);
return(TRUE);
}
//+-------------------------------------------------------------------------
// Frees string allocated by the above function
//--------------------------------------------------------------------------
void WINAPI FreeMBStr(PBYTE pbBuff, char * szMB) {
if((szMB != NULL) && (pbBuff != (PBYTE)szMB))
free(szMB);
}
//+-------------------------------------------------------------------------
// Win95 only supports CryptAcquireContextA. This function converts the
// unicode parameters to multibyte.
//--------------------------------------------------------------------------
BOOL WINAPI CryptAcquireContextU(
HCRYPTPROV *phProv,
LPCWSTR lpContainer,
LPCWSTR lpProvider,
DWORD dwProvType,
DWORD dwFlags) {
BYTE rgb1[_MAX_PATH];
BYTE rgb2[_MAX_PATH];
char * szContainer = NULL;
char * szProvider = NULL;
LONG err;
err = FALSE;
if(
MkMBStr(rgb1, _MAX_PATH, lpContainer, &szContainer) &&
MkMBStr(rgb2, _MAX_PATH, lpProvider, &szProvider) )
err = CryptAcquireContextA (
phProv,
szContainer,
szProvider,
dwProvType,
dwFlags
);
FreeMBStr(rgb1, szContainer);
FreeMBStr(rgb2, szProvider);
return(err);
}
//+-------------------------------------------------------------------------
// Helper function to allocated the output buffer
// and call CryptDecodeObject.
//--------------------------------------------------------------------------
BOOL
WINAPI
MDecodeObject(
IN DWORD dwEncodingType,
IN LPCSTR lpszStructureType,
IN const PBYTE pbEncoded,
IN DWORD cbEncoded,
OUT PVOID * ppvoid
)
{
DWORD cb = 0;
assert(ppvoid != NULL);
*ppvoid = NULL;
// get the size
if(!CryptDecodeObject(
dwEncodingType,
lpszStructureType,
pbEncoded,
cbEncoded,
0, // dwFlags
NULL,
&cb
))
return(FALSE);
// allocate the buffer
if( (*ppvoid = malloc(cb)) == NULL )
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
// Decode the data
if(!CryptDecodeObject(
dwEncodingType,
lpszStructureType,
pbEncoded,
cbEncoded,
0, // dwFlags
*ppvoid,
&cb
))
{
free(*ppvoid);
*ppvoid = NULL;
return(FALSE);
}
return(TRUE);
}
//+-------------------------------------------------------------------------
// Helper function to allocated the output buffer
// and call CertRDNValueToStr.
//--------------------------------------------------------------------------
DWORD
WINAPI
MCertRDNValueToStr(
IN DWORD dwValueType,
IN PCERT_RDN_VALUE_BLOB pValue,
OUT OPTIONAL LPSTR * ppsz
)
{
DWORD cb = 0;
assert(ppsz != NULL);
*ppsz = NULL;
// get the size
cb = CertRDNValueToStrA(
dwValueType,
pValue,
NULL,
0);
// allocate the buffer
if( (*ppsz = (LPSTR) malloc(cb)) == NULL )
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(0);
}
// now convert the CERT_RDN Value to an
// ascii string based on the specified
// ASN value type.
// This shouldn't fail.
return(CertRDNValueToStrA(
dwValueType,
pValue,
*ppsz,
cb));
}
//+-------------------------------------------------------------------------
// Helper function to get and allocate the exported public key info
//--------------------------------------------------------------------------
BOOL
WINAPI
MCryptExportPublicKeyInfo(
HCRYPTPROV hProv,
DWORD dwKeySpec,
PCERT_PUBLIC_KEY_INFO *ppPubKeyInfo
)
{
DWORD cbPubKeyInfo;
assert(ppPubKeyInfo != NULL);
*ppPubKeyInfo = NULL;
// get the size
if(!CryptExportPublicKeyInfo(
hProv,
dwKeySpec,
X509_ASN_ENCODING,
NULL, // pPubKeyInfo
&cbPubKeyInfo
)
)
return(FALSE);
// allocate the buffer
if( (*ppPubKeyInfo = (PCERT_PUBLIC_KEY_INFO) malloc(cbPubKeyInfo)) == NULL )
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
if(!CryptExportPublicKeyInfo(
hProv,
dwKeySpec,
X509_ASN_ENCODING,
*ppPubKeyInfo,
&cbPubKeyInfo
)
)
{
free(*ppPubKeyInfo);
*ppPubKeyInfo = NULL;
return(FALSE);
}
return(TRUE);
}
//+-------------------------------------------------------------------------
// Helper function to allocated the output buffer
// and call CertGetCertificateContextProperty.
//--------------------------------------------------------------------------
BOOL
WINAPI
MCertGetCertificateContextProperty(
IN PCCERT_CONTEXT pCertContext,
IN DWORD dwPropId,
OUT void ** ppvData
)
{
DWORD cb = 0;
assert(ppvData != NULL);
*ppvData = NULL;
// get the size
if( !CertGetCertificateContextProperty(
pCertContext,
dwPropId,
NULL,
&cb))
return(FALSE);
// allocate the buffer
if( (*ppvData = malloc(cb)) == NULL )
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
// Get the property out of the cert
if( !CertGetCertificateContextProperty(
pCertContext,
dwPropId,
*ppvData,
&cb))
{
free(*ppvData);
*ppvData = NULL;
return(FALSE);
}
return(TRUE);
}
//+-------------------------------------------------------------------------
// Helper function to allocated the output buffer
// and call CryptEncryptMessage.
//--------------------------------------------------------------------------
BOOL
WINAPI
MCryptEncryptMessage(
IN PCRYPT_ENCRYPT_MESSAGE_PARA pEncryptPara,
IN DWORD cRecipientCert,
IN PCCERT_CONTEXT rgpRecipientCert[],
IN const BYTE *pbToBeEncrypted,
IN DWORD cbToBeEncrypted,
OUT BYTE **ppbEncryptedBlob,
OUT DWORD *pcbEncryptedBlob
)
{
assert(ppbEncryptedBlob != NULL);
*ppbEncryptedBlob = NULL;
assert(pcbEncryptedBlob != NULL);
*pcbEncryptedBlob = 0;
// get the size
if(!CryptEncryptMessage(
pEncryptPara,
cRecipientCert,
rgpRecipientCert,
pbToBeEncrypted,
cbToBeEncrypted,
NULL,
pcbEncryptedBlob
))
return(FALSE);
// allocate the buffer
if( (*ppbEncryptedBlob = (BYTE *) malloc(*pcbEncryptedBlob)) == NULL )
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(FALSE);
}
// encrypt the data
if(!CryptEncryptMessage(
pEncryptPara,
cRecipientCert,
rgpRecipientCert,
pbToBeEncrypted,
cbToBeEncrypted,
*ppbEncryptedBlob,
pcbEncryptedBlob))
{
free(*ppbEncryptedBlob);
*ppbEncryptedBlob = NULL;
*pcbEncryptedBlob = 0;
return(FALSE);
}
return(TRUE);
}
//+-------------------------------------------------------------------------
// Display FEncrypt usage.
//--------------------------------------------------------------------------
void
Usage(void)
{
printf("Usage: FEncrypt [options] <SubjectName> <ClearTextFileName> <EncryptedFileName>\n");
printf("Options are:\n");
printf(" -RC2 - RC2 encryption\n");
printf(" -RC4 - RC4 encryption\n");
printf(" -SP3 - SP3 compatible encryption\n");
printf(" -FIX - Fix by loading sp3crmsg.dll\n");
exit(1);
}
//+-------------------------------------------------------------------------
// Generalized error routine
//--------------------------------------------------------------------------
#define PRINTERROR(psz, err) _PrintError((psz), (err), __LINE__)
void
_PrintError(char *pszMsg, DWORD err, DWORD line)
{
printf("%s failed on line %u: %u(%x)\n", pszMsg, line, err, err);
}
//+-------------------------------------------------------------------------
// Grovels the cert store looking for a cert with the specified
// subject common name. Then checks to see that there are private
// and public exchange keys.
//--------------------------------------------------------------------------
PCCERT_CONTEXT GetSubjectCertFromStore(
HCERTSTORE hMyStore,
const char * szSubjectName,
HCRYPTPROV * phProv
)
{
DWORD i, j;
PCCERT_CONTEXT pCertContext = NULL;
PCCERT_CONTEXT pCertContextLast = NULL;
PCERT_NAME_INFO pNameInfo = NULL;
LPSTR sz = NULL;
PCRYPT_KEY_PROV_INFO pProvInfo = NULL;
HCRYPTPROV hProv = NULL;
PCERT_PUBLIC_KEY_INFO pPubKeyInfo = NULL;
assert(hMyStore != NULL);
assert(phProv != NULL);
*phProv = NULL;
// Enum all certs looking for the requested common
// subject name that has private keys (so we know we can decrypt)
while( hProv == NULL &&
(pCertContext = CertEnumCertificatesInStore(
hMyStore,
pCertContextLast)) != NULL)
{
// decode the subject name into RDNs
if(MDecodeObject(X509_ASN_ENCODING, X509_NAME,
pCertContext->pCertInfo->Subject.pbData,
pCertContext->pCertInfo->Subject.cbData,
(void **) &pNameInfo)
)
{
// loop thru looking for an CERT_RDN and COMMON Name that works
for(i=0; i<pNameInfo->cRDN && hProv == NULL; i++)
{
for(j=0; j<pNameInfo->rgRDN[i].cRDNAttr && hProv == NULL; j++)
{
// check to see if this is the common name
if( !strcmp(pNameInfo->rgRDN[i].rgRDNAttr[j].pszObjId,
szOID_COMMON_NAME) )
{
// convert the string to something I can read
MCertRDNValueToStr(
pNameInfo->rgRDN[i].rgRDNAttr[j].dwValueType,
&pNameInfo->rgRDN[i].rgRDNAttr[j].Value,
&sz);
// see if this is a viable certificate to use
if( sz == NULL ||
// see if it is the common name we are looking for
_stricmp(sz, szSubjectName) ||
// see if there are associated private keys
// to ensure we can decrypt the data later
!MCertGetCertificateContextProperty(
pCertContext,
CERT_KEY_PROV_INFO_PROP_ID,
(void **) &pProvInfo) ||
// Make sure it is an exchange key for encryption
pProvInfo->dwKeySpec != AT_KEYEXCHANGE ||
// see if the keys are really there
!CryptAcquireContextU(
&hProv,
pProvInfo->pwszContainerName,
pProvInfo->pwszProvName,
pProvInfo->dwProvType,
pProvInfo->dwFlags &
~CERT_SET_KEY_CONTEXT_PROP_ID)
)
{
// On an error we didn't find a valid
// key provider. Unfortunately, the CSP
// may not leave the prov handle NULL
// so clear it out
hProv = NULL;
}
// Make sure the public keys in the
// CSP match the public key in the certificate
else if(
// export the public key blob
!MCryptExportPublicKeyInfo(
hProv,
pProvInfo->dwKeySpec,
&pPubKeyInfo
) ||
// see if the public keys compare with
// what is in the certificate
!CertComparePublicKeyInfo(
X509_ASN_ENCODING,
&pCertContext->pCertInfo->SubjectPublicKeyInfo,
pPubKeyInfo
)
)
// if the keys didn't compare, then we don't
// want to use this ceritificate
{
// close the hProv, we didn't find a valid cert
assert(hProv != NULL);
CryptReleaseContext(hProv, 0);
hProv = NULL;
}
// free public key info
if(pPubKeyInfo != NULL)
{
free(pPubKeyInfo);
pPubKeyInfo = NULL;
}
// clean up opened prov info
if(pProvInfo != NULL)
{
free(pProvInfo);
pProvInfo = NULL;
}
// free the space for the ascii common name
if(sz != NULL)
{
free(sz);
sz = NULL;
}
}
}
}
// free the name info data
if(pNameInfo != NULL)
{
free(pNameInfo);
pNameInfo = NULL;
}
}
// go to the next certificate
pCertContextLast = pCertContext;
}
assert(pProvInfo == NULL);
assert(sz == NULL);
assert(pNameInfo == NULL);
// There is a good cert in the store, return it
if(hProv != NULL)
{
*phProv = hProv;
assert(pCertContext != NULL);
return(pCertContext);
}
return(NULL);
}
//+-------------------------------------------------------------------------
// Main program. Open a file to encrypt,
// encrypts it and then writes the encrypted
// data to the output file.
//--------------------------------------------------------------------------
int __cdecl
main(int argc, char * argv[])
{
DWORD dwExitValue = 0;
HCERTSTORE hMyStore = NULL;
PCCERT_CONTEXT pCertContext = NULL;
HCRYPTPROV hProv = NULL;
HANDLE hFileOut = INVALID_HANDLE_VALUE;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD cbFile = 0;
HANDLE hMap = NULL;
PBYTE pbFile = NULL;
BOOL fResult;
HMODULE hDll = NULL;
CMSG_SP3_COMPATIBLE_AUX_INFO SP3AuxInfo;
BOOL fSP3 = FALSE;
BOOL fFix = FALSE;
CRYPT_ALGORITHM_IDENTIFIER encryptAlgId = {szOID_RSA_RC4, 0};
CRYPT_ENCRYPT_MESSAGE_PARA encryptInfo;
PBYTE pbEncryptedBlob = NULL;
DWORD cbEncryptedBlob = 0;
DWORD cb = 0;
// Advance past fencrypt.exe and check for leading options
while (--argc > 0) {
if (**++argv != '-')
break;
if (0 == _stricmp(argv[0], "-RC2"))
encryptAlgId.pszObjId = szOID_RSA_RC2CBC;
else if (0 == _stricmp(argv[0], "-RC4"))
encryptAlgId.pszObjId = szOID_RSA_RC4;
else if (0 == _stricmp(argv[0], "-SP3"))
fSP3 = TRUE;
else if (0 == _stricmp(argv[0], "-FIX"))
fFix = TRUE;
else {
printf("Bad option: %s\n", argv[0]);
Usage();
}
}
// must have the parameters
if (argc != 3)
Usage();
if (fFix) {
if (NULL == (hDll = LoadLibraryA("sp3crmsg.dll")))
{
PRINTERROR("LoadLibraryA(sp3crmsg.dll)", GetLastError());
goto ErrCleanUp;
}
}
// Open the MY store
if( (hMyStore = CertOpenSystemStore(NULL, "My")) == NULL )
{
PRINTERROR("CertOpenSystemStore", GetLastError());
goto ErrCleanUp;
}
// Find a certificate in the MY store that
// matches the subject name and has private keys
if( (pCertContext = GetSubjectCertFromStore(hMyStore, argv[0], &hProv)) == NULL)
{
printf("Unable to find certificate %s with valid keys.\n", argv[0]);
goto ErrCleanUp;
}
// At this point we have a provider, Cert and a public key.
// We should be able to encrypt
// Read in the clear text file
if(
// read in the file to encrypt
(hFile = CreateFileA(
argv[1], // pointer to name of the file
GENERIC_READ, // access (read-write) mode
FILE_SHARE_READ, // share mode
NULL, // pointer to security descriptor
OPEN_EXISTING, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL // handle to file with attributes to copy
)) == INVALID_HANDLE_VALUE ||
// create a file mapping object
(hMap = CreateFileMapping(
hFile, // handle to file to map
NULL, // optional security attributes
PAGE_READONLY, // protection for mapping object
0, // high-order 32 bits of object size
0, // low-order 32 bits of object size
NULL // name of file-mapping object
)) == NULL ||
// Map the file into the address space
(pbFile = (PBYTE) MapViewOfFileEx(
hMap, // file-mapping object to map into address space
FILE_MAP_READ, // access mode
0, // high-order 32 bits of file offset
0, // low-order 32 bits of file offset
0, // number of bytes to map
NULL // suggested starting address for mapped view
)) == NULL
)
{
PRINTERROR("File Open", GetLastError());
goto ErrCleanUp;
}
// get the size of the file
if( (cbFile = GetFileSize(
hFile, // handle of file to get size of
NULL // address of high-order word for file size
)) == 0
)
{
printf("File %s has a 0 length.\n", argv[1]);
goto ErrCleanUp;
}
// at this point we have a file mapping, go ahead and encrypt the file
// Do rc4 encryption
memset(&encryptInfo, 0, sizeof(CRYPT_ENCRYPT_MESSAGE_PARA));
encryptInfo.cbSize =
sizeof(CRYPT_ENCRYPT_MESSAGE_PARA);
encryptInfo.dwMsgEncodingType = PKCS_7_ASN_ENCODING;
encryptInfo.hCryptProv = hProv;
encryptInfo.ContentEncryptionAlgorithm = encryptAlgId;
if (fSP3) {
memset(&SP3AuxInfo, 0, sizeof(CMSG_SP3_COMPATIBLE_AUX_INFO));
SP3AuxInfo.cbSize = sizeof(CMSG_SP3_COMPATIBLE_AUX_INFO);
SP3AuxInfo.dwFlags = CMSG_SP3_COMPATIBLE_ENCRYPT_FLAG;
encryptInfo.pvEncryptionAuxInfo = &SP3AuxInfo;
}
// encrypt it
fResult = MCryptEncryptMessage(
&encryptInfo,
1,
&pCertContext,
pbFile,
cbFile,
&pbEncryptedBlob,
&cbEncryptedBlob
);
if (!fResult && fSP3 && (DWORD) E_INVALIDARG == GetLastError()) {
printf(
"Non-NULL pvEncryptionAuxInfo not supported in SP3 crypt32.dll\n");
encryptInfo.pvEncryptionAuxInfo = NULL;
fResult = MCryptEncryptMessage(
&encryptInfo,
1,
&pCertContext,
pbFile,
cbFile,
&pbEncryptedBlob,
&cbEncryptedBlob
);
}
if (!fResult) {
PRINTERROR("MCryptEncryptMessage", GetLastError());
goto ErrCleanUp;
}
// write the encrypted file out
if(
// open the output file
(hFileOut = CreateFileA(
argv[2], // pointer to name of the file
GENERIC_WRITE, // access (read-write) mode
FILE_SHARE_READ, // share mode
NULL, // pointer to security descriptor
CREATE_ALWAYS, // how to create
FILE_ATTRIBUTE_NORMAL, // file attributes
NULL // handle to file with attributes to copy
)) == INVALID_HANDLE_VALUE ||
//write to the file
!WriteFile(
hFileOut, // handle to file to write to
pbEncryptedBlob, // pointer to data to write to file
cbEncryptedBlob, // number of bytes to write
&cb, // pointer to number of bytes written
NULL // pointer to structure needed for overlapped I/O
)
)
{
PRINTERROR("File Write", GetLastError());
goto ErrCleanUp;
}
CleanUp:
if(hDll)
FreeLibrary(hDll);
if(hMap != NULL)
CloseHandle(hMap);
if(hFile != INVALID_HANDLE_VALUE && hFile != NULL)
CloseHandle(hFile);
if(hFileOut != INVALID_HANDLE_VALUE && hFile != NULL)
CloseHandle(hFileOut);
if(pCertContext != NULL)
CertFreeCertificateContext(pCertContext);
if(hProv != NULL)
CryptReleaseContext(hProv, 0);
if(hMyStore != NULL)
CertCloseStore(hMyStore, 0);
if(pbEncryptedBlob != NULL)
free(pbEncryptedBlob);
return(dwExitValue);
ErrCleanUp:
dwExitValue = 1;
goto CleanUp;
}