crypt32 [2/4]: protectdata function

Kees Cook kees at outflux.net
Thu May 19 05:18:58 CDT 2005


ChangeLog:
	Implement CryptProtectData with best-guess encryption.

-- 
Kees Cook                                            @outflux.net
-------------- next part --------------
Index: dlls/crypt32/main.c
===================================================================
RCS file: /home/wine/wine/dlls/crypt32/main.c,v
retrieving revision 1.19
diff -u -p -r1.19 main.c
--- dlls/crypt32/main.c	30 Nov 2004 21:39:00 -0000	1.19
+++ dlls/crypt32/main.c	19 May 2005 10:10:35 -0000
@@ -56,14 +56,6 @@ BOOL WINAPI I_CryptFreeLruCache(DWORD x)
     return FALSE;
 }
 
-BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, DATA_BLOB* pOptionalEntropy,
-                             PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
-                             DWORD dwFlags, DATA_BLOB* pDataOut)
-{
-    FIXME("stub!\n");
-    return FALSE;
-}
-
 BOOL WINAPI CryptSIPRemoveProvider(GUID *pgProv)
 {
     FIXME("stub!\n");
--- dlls/crypt32/protectdata.c.orig	2005-05-19 03:10:38.095462748 -0700
+++ dlls/crypt32/protectdata.c	2005-05-19 03:10:00.499743037 -0700
@@ -796,3 +796,170 @@ report(DATA_BLOB* pDataIn, DATA_BLOB* pO
 
 }
 
+/***************************************************************************
+ * CryptProtectData     [CRYPT32.@]
+ *
+ * Generate Cipher data from given Plain and Entropy data.
+ *
+ * PARAMS
+ *  pDataIn          [I] Plain data to be enciphered
+ *  szDataDescr      [I] 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 ciphering
+ *  dwFlags          [I] Flags describing options to the ciphering
+ *  pDataOut         [O] Resulting Cipher data, for calls to CryptUnprotectData
+ *
+ * RETURNS
+ *  TRUE  If a Cipher was generated.
+ *  FALSE If something failed and no Cipher is available.
+ *
+ * FIXME
+ *  The true Windows encryption and keying mechanisms are unknown.
+ *
+ *  dwFlags and pPromptStruct are currently ignored.
+ *
+ * NOTES
+ *  Memory allocated in pDataOut must be freed with LocalFree.
+ *
+ */
+BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
+                             LPCWSTR szDataDescr,
+                             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 */
+    report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+    TRACE("\tszDataDescr: 0x%x %s\n",(unsigned int)szDataDescr,
+          szDataDescr ? debugstr_w(szDataDescr) : "");
+
+    /* Windows appears to create an empty szDataDescr instead of maintaining
+     * a NULL */
+    if (!szDataDescr)
+        szDataDescr=(WCHAR[]){'\0'};
+
+    /* get crypt context */
+    if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,0))
+    {
+        ERR("CryptAcquireContextW failed\n");
+        goto finished;
+    }
+
+    /* populate our structure */
+    if (!fill_protect_data(&protect_data,szDataDescr,hProv))
+    {
+        ERR("fill_protect_data\n");
+        goto free_context;
+    }
+
+    /* load key */
+    if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
+    {
+        goto free_protect_data;
+    }
+
+    /* create a hash for the encryption validation */
+    if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
+    {
+        ERR("CryptCreateHash\n");
+        goto free_key;
+    }
+
+    /* calculate storage required */
+    dwLength=pDataIn->cbData;
+    if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
+        GetLastError()!=ERROR_MORE_DATA)
+    {
+        ERR("CryptEncrypt\n");
+        goto free_hash;
+    }
+    TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
+
+    /* copy plain text into cipher area for CryptEncrypt call */
+    protect_data.cipher.cbData=dwLength;
+    if (!(protect_data.cipher.pbData=HeapAlloc( GetProcessHeap(), 0,
+                                                protect_data.cipher.cbData)))
+    {
+        ERR("HeapAlloc\n");
+        goto free_hash;
+    }
+    memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
+
+    /* encrypt! */
+    dwLength=pDataIn->cbData;
+    if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
+                      &dwLength, protect_data.cipher.cbData))
+    {
+        ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
+        goto free_hash;
+    }
+    protect_data.cipher.cbData=dwLength;
+
+    /* debug: show the cipher */
+    TRACE_DATA_BLOB(&protect_data.cipher);
+
+    /* attach our fingerprint */
+    if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
+    {
+        ERR("convert_hash_to_blob\n");
+        goto free_hash;
+    }
+
+    /* serialize into an opaque blob */
+    if (!serialize(&protect_data, pDataOut))
+    {
+        ERR("serialize\n");
+        goto free_hash;
+    }
+
+    /* success! */
+    rc=TRUE;
+
+free_hash:
+    CryptDestroyHash(hHash);
+free_key:
+    CryptDestroyKey(hKey);
+free_protect_data:
+    free_protect_data(&protect_data);
+free_context:
+    CryptReleaseContext(hProv,0);
+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);
+
+        TRACE_DATA_BLOB(pDataOut);
+    }
+
+    TRACE("returning %s\n", rc ? "ok" : "FAIL");
+
+    return rc;
+}
+


More information about the wine-patches mailing list