Implement CryptUnprotectData counterpart to CryptProtectData.
This commit is contained in:
parent
1970e467d4
commit
dc54dd1439
|
@ -149,7 +149,7 @@
|
||||||
@ stub CryptSignHashU
|
@ stub CryptSignHashU
|
||||||
@ stub CryptSignMessage
|
@ stub CryptSignMessage
|
||||||
@ stub CryptSignMessageWithKey
|
@ stub CryptSignMessageWithKey
|
||||||
@ stub CryptUnprotectData
|
@ stdcall CryptUnprotectData(ptr ptr ptr ptr ptr long ptr)
|
||||||
@ stub CryptUnregisterDefaultOIDFunction
|
@ stub CryptUnregisterDefaultOIDFunction
|
||||||
@ stub CryptUnregisterOIDFunction
|
@ stub CryptUnregisterOIDFunction
|
||||||
@ stub CryptUnregisterOIDInfo
|
@ stub CryptUnregisterOIDInfo
|
||||||
|
|
|
@ -963,3 +963,172 @@ finished:
|
||||||
|
|
||||||
return rc;
|
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