Implement CryptUnprotectData counterpart to CryptProtectData.
This commit is contained in:
parent
1970e467d4
commit
dc54dd1439
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue