Commit dc54dd14 authored by Kees Cook's avatar Kees Cook Committed by Alexandre Julliard

Implement CryptUnprotectData counterpart to CryptProtectData.

parent 1970e467
......@@ -149,7 +149,7 @@
@ stub CryptSignHashU
@ stub CryptSignMessage
@ stub CryptSignMessageWithKey
@ stub CryptUnprotectData
@ stdcall CryptUnprotectData(ptr ptr ptr ptr ptr long ptr)
@ stub CryptUnregisterDefaultOIDFunction
@ stub CryptUnregisterOIDFunction
@ stub CryptUnregisterOIDInfo
......
......@@ -963,3 +963,172 @@ finished:
return rc;
}
/***************************************************************************
* CryptUnprotectData [CRYPT32.@]
*
* Generate Plain data and Description from given Cipher and Entropy data.
*
* PARAMS
* pDataIn [I] Cipher data to be decoded
* ppszDataDescr [O] 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 decoding
* dwFlags [I] Flags describing options to the decoding
* pDataOut [O] Resulting Plain data, from calls to CryptProtectData
*
* RETURNS
* TRUE If a Plain was generated.
* FALSE If something failed and no Plain is available.
*
* FIXME
* The true Windows encryption and keying mechanisms are unknown.
*
* dwFlags and pPromptStruct are currently ignored.
*
* NOTES
* Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
* with LocalFree.
*
*/
BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
LPWSTR * ppszDataDescr,
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;
const char * announce_bad_opaque_data = "CryptUnprotectData received a DATA_BLOB that seems to have NOT been generated by Wine. Please enable tracing ('export WINEDEBUG=crypt') to see details.";
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("\tppszDataDescr: 0x%x\n",(unsigned int)ppszDataDescr);
/* take apart the opaque blob */
if (!unserialize(pDataIn, &protect_data))
{
SetLastError(ERROR_INVALID_DATA);
FIXME("%s\n",announce_bad_opaque_data);
goto finished;
}
/* perform basic validation on the resulting structure */
if (!valid_protect_data(&protect_data))
{
SetLastError(ERROR_INVALID_DATA);
FIXME("%s\n",announce_bad_opaque_data);
goto free_protect_data;
}
/* get a crypt context */
if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,0))
{
ERR("CryptAcquireContextW failed\n");
goto free_protect_data;
}
/* load key */
if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
{
goto free_context;
}
/* create a hash for the decryption validation */
if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
{
ERR("CryptCreateHash\n");
goto free_key;
}
/* prepare for plaintext */
pDataOut->cbData=protect_data.cipher.cbData;
if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
{
ERR("HeapAlloc\n");
goto free_hash;
}
memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
/* decrypt! */
if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
&pDataOut->cbData) ||
/* check the hash fingerprint */
pDataOut->cbData > protect_data.cipher.cbData ||
!hash_matches_blob(hHash, &protect_data.fingerprint))
{
SetLastError(ERROR_INVALID_DATA);
LocalFree( pDataOut->pbData );
pDataOut->pbData = NULL;
pDataOut->cbData = 0;
goto free_hash;
}
/* Copy out the description */
dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
if (ppszDataDescr)
{
if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
{
ERR("LocalAlloc (ppszDataDescr)\n");
goto free_hash;
}
else {
memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
}
}
/* success! */
rc = TRUE;
free_hash:
CryptDestroyHash(hHash);
free_key:
CryptDestroyKey(hKey);
free_context:
CryptReleaseContext(hProv,0);
free_protect_data:
free_protect_data(&protect_data);
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);
if (ppszDataDescr)
{
TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
}
TRACE_DATA_BLOB(pDataOut);
}
TRACE("returning %s\n", rc ? "ok" : "FAIL");
return rc;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment