Implement CryptProtectData with best-guess encryption.
This commit is contained in:
parent
25ab9f2c0f
commit
146be8071f
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue