From 146be8071fe14678c7124a12e91d658599e3cdf6 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Fri, 20 May 2005 19:15:55 +0000 Subject: [PATCH] Implement CryptProtectData with best-guess encryption. --- dlls/crypt32/main.c | 8 -- dlls/crypt32/protectdata.c | 168 +++++++++++++++++++++++++++++++++++++ 2 files changed, 168 insertions(+), 8 deletions(-) diff --git a/dlls/crypt32/main.c b/dlls/crypt32/main.c index 2160fa3aa6f..722e0edabad 100644 --- a/dlls/crypt32/main.c +++ b/dlls/crypt32/main.c @@ -56,14 +56,6 @@ BOOL WINAPI I_CryptFreeLruCache(DWORD x) return FALSE; } -BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, DATA_BLOB* pOptionalEntropy, - PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, - DWORD dwFlags, DATA_BLOB* pDataOut) -{ - FIXME("stub!\n"); - return FALSE; -} - BOOL WINAPI CryptSIPRemoveProvider(GUID *pgProv) { FIXME("stub!\n"); diff --git a/dlls/crypt32/protectdata.c b/dlls/crypt32/protectdata.c index 000d256d340..060393ae4d3 100644 --- a/dlls/crypt32/protectdata.c +++ b/dlls/crypt32/protectdata.c @@ -795,3 +795,171 @@ report(DATA_BLOB* pDataIn, DATA_BLOB* pOptionalEntropy, } } + + +/*************************************************************************** + * CryptProtectData [CRYPT32.@] + * + * Generate Cipher data from given Plain and Entropy data. + * + * PARAMS + * pDataIn [I] Plain data to be enciphered + * szDataDescr [I] Optional Unicode string describing the Plain data + * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL + * pvReserved [I] Reserved, must be NULL + * pPromptStruct [I] Structure describing if/how to prompt during ciphering + * dwFlags [I] Flags describing options to the ciphering + * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData + * + * RETURNS + * TRUE If a Cipher was generated. + * FALSE If something failed and no Cipher is available. + * + * FIXME + * The true Windows encryption and keying mechanisms are unknown. + * + * dwFlags and pPromptStruct are currently ignored. + * + * NOTES + * Memory allocated in pDataOut must be freed with LocalFree. + * + */ +BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, + LPCWSTR szDataDescr, + DATA_BLOB* pOptionalEntropy, + PVOID pvReserved, + CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, + DWORD dwFlags, + DATA_BLOB* pDataOut) +{ + BOOL rc = FALSE; + + HCRYPTPROV hProv; + struct protect_data_t protect_data; + HCRYPTHASH hHash; + HCRYPTKEY hKey; + DWORD dwLength; + + TRACE("called\n"); + + SetLastError(ERROR_SUCCESS); + + if (!pDataIn || !pDataOut) + { + SetLastError(ERROR_INVALID_PARAMETER); + goto finished; + } + + /* debug: show our arguments */ + report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags); + TRACE("\tszDataDescr: 0x%x %s\n",(unsigned int)szDataDescr, + szDataDescr ? debugstr_w(szDataDescr) : ""); + + /* Windows appears to create an empty szDataDescr instead of maintaining + * a NULL */ + if (!szDataDescr) + szDataDescr=(WCHAR[]){'\0'}; + + /* get crypt context */ + if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,0)) + { + ERR("CryptAcquireContextW failed\n"); + goto finished; + } + + /* populate our structure */ + if (!fill_protect_data(&protect_data,szDataDescr,hProv)) + { + ERR("fill_protect_data\n"); + goto free_context; + } + + /* load key */ + if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey)) + { + goto free_protect_data; + } + + /* create a hash for the encryption validation */ + if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash)) + { + ERR("CryptCreateHash\n"); + goto free_key; + } + + /* calculate storage required */ + dwLength=pDataIn->cbData; + if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) || + GetLastError()!=ERROR_MORE_DATA) + { + ERR("CryptEncrypt\n"); + goto free_hash; + } + TRACE("required encrypted storage: %u\n",(unsigned int)dwLength); + + /* copy plain text into cipher area for CryptEncrypt call */ + protect_data.cipher.cbData=dwLength; + if (!(protect_data.cipher.pbData=HeapAlloc( GetProcessHeap(), 0, + protect_data.cipher.cbData))) + { + ERR("HeapAlloc\n"); + goto free_hash; + } + memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData); + + /* encrypt! */ + dwLength=pDataIn->cbData; + if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData, + &dwLength, protect_data.cipher.cbData)) + { + ERR("CryptEncrypt %u\n",(unsigned int)GetLastError()); + goto free_hash; + } + protect_data.cipher.cbData=dwLength; + + /* debug: show the cipher */ + TRACE_DATA_BLOB(&protect_data.cipher); + + /* attach our fingerprint */ + if (!convert_hash_to_blob(hHash, &protect_data.fingerprint)) + { + ERR("convert_hash_to_blob\n"); + goto free_hash; + } + + /* serialize into an opaque blob */ + if (!serialize(&protect_data, pDataOut)) + { + ERR("serialize\n"); + goto free_hash; + } + + /* success! */ + rc=TRUE; + +free_hash: + CryptDestroyHash(hHash); +free_key: + CryptDestroyKey(hKey); +free_protect_data: + free_protect_data(&protect_data); +free_context: + CryptReleaseContext(hProv,0); +finished: + /* If some error occured, and no error code was set, force one. */ + if (!rc && GetLastError()==ERROR_SUCCESS) + { + SetLastError(ERROR_INVALID_DATA); + } + + if (rc) + { + SetLastError(ERROR_SUCCESS); + + TRACE_DATA_BLOB(pDataOut); + } + + TRACE("returning %s\n", rc ? "ok" : "FAIL"); + + return rc; +}