[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