[crypt32] CryptUnprotectData function
Kees Cook
kees at outflux.net
Wed May 18 07:55:12 CDT 2005
Removes the CryptUnprotectData stub and implements it in "protectdata.c"
ChangeLog:
Implement CryptUnprotectData.
--
Kees Cook @outflux.net
-------------- next part --------------
Index: dlls/crypt32/crypt32.spec
===================================================================
RCS file: /home/wine/wine/dlls/crypt32/crypt32.spec,v
retrieving revision 1.19
diff -u -p -r1.19 crypt32.spec
--- dlls/crypt32/crypt32.spec 10 Nov 2004 01:31:50 -0000 1.19
+++ dlls/crypt32/crypt32.spec 18 May 2005 12:53:18 -0000
@@ -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
--- dlls/crypt32/protectdata.c.orig 2005-05-18 05:49:39.168438158 -0700
+++ dlls/crypt32/protectdata.c 2005-05-18 05:52:58.780758628 -0700
@@ -976,3 +976,179 @@
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;
+
+ TRACE("called\n");
+
+ SetLastError(ERROR_SUCCESS);
+
+ if (!pDataIn || !pDataOut)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto finished;
+ }
+
+ /* debug: show our arguments */
+ if (WINE_TRACE_ON(crypt)) {
+ crypt_report_func_input(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+ wine_dbg_printf("\tppszDataDescr: 0x%x\n",(unsigned int)ppszDataDescr);
+ }
+
+ /* take apart the opaque blob */
+ if (!unserialize(pDataIn, &protect_data))
+ {
+ SetLastError(ERROR_INVALID_DATA);
+ announce_bad_opaque_data(pDataIn,pOptionalEntropy);
+ crypt_report_func_input(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+ goto finished;
+ }
+
+ /* perform basic validation on the resulting structure */
+ if (!valid_protect_data(&protect_data))
+ {
+ SetLastError(ERROR_INVALID_DATA);
+ announce_bad_opaque_data(pDataIn,pOptionalEntropy);
+ crypt_report_func_input(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+ 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);
+ }
+
+ TRACE("returning %s\n", rc ? "ok" : "FAIL");
+
+ if (rc) {
+ SetLastError(ERROR_SUCCESS);
+
+ if (WINE_TRACE_ON(crypt))
+ {
+ if (ppszDataDescr)
+ {
+ wine_dbg_printf("\tszDataDescr: %s\n",debugstr_w(*ppszDataDescr));
+ }
+ wine_dbg_printf("\tpDataOut->cbData: %u\n",(unsigned int)pDataOut->cbData);
+ wine_dbg_printf("\tpDataOut->pbData: 0x%x\n",(unsigned int)pDataOut->pbData);
+ hexprint("pbData", pDataOut->pbData, pDataOut->cbData);
+ }
+ }
+
+ return rc;
+}
+
+/* vi:set ai ts=4 sw=4 expandtab: */
More information about the wine-patches
mailing list