crypt32: CryptProtectData/CryptUnprotectData take 2

Kees Cook kees at outflux.net
Mon Apr 4 13:06:47 CDT 2005


ChangeLog:
    Black-box implementation of CryptProtectData/CryptUnprotectData.

Here is an updated patch with various recommendations implemented.

-- 
Kees Cook                                            @outflux.net
-------------- next part --------------
Index: dlls/crypt32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/crypt32/Makefile.in,v
retrieving revision 1.8
diff -u -p -u -p -r1.8 Makefile.in
--- dlls/crypt32/Makefile.in	1 Mar 2004 21:19:37 -0000	1.8
+++ dlls/crypt32/Makefile.in	4 Apr 2005 17:55:23 -0000
@@ -8,6 +8,7 @@ IMPORTS   = advapi32 kernel32
 
 C_SRCS = \
 	cert.c \
+	protectdata.c \
 	main.c
 
 @MAKE_DLL_RULES@
Index: dlls/crypt32/crypt32.spec
===================================================================
RCS file: /home/wine/wine/dlls/crypt32/crypt32.spec,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 crypt32.spec
--- dlls/crypt32/crypt32.spec	10 Nov 2004 01:31:50 -0000	1.19
+++ dlls/crypt32/crypt32.spec	4 Apr 2005 17:55:23 -0000
@@ -133,6 +133,7 @@
 @ stub CryptMsgUpdate
 @ stub CryptMsgVerifyCountersignatureEncoded
 @ stdcall CryptProtectData(ptr wstr ptr ptr ptr long ptr)
+@ stdcall CryptUnprotectData(ptr ptr ptr ptr ptr long ptr)
 @ stdcall CryptRegisterDefaultOIDFunction(long str long wstr)
 @ stdcall CryptRegisterOIDFunction(long str str wstr str)
 @ stub CryptRegisterOIDInfo
@@ -149,7 +150,6 @@
 @ stub CryptSignHashU
 @ stub CryptSignMessage
 @ stub CryptSignMessageWithKey
-@ stub CryptUnprotectData
 @ stub CryptUnregisterDefaultOIDFunction
 @ stub CryptUnregisterOIDFunction
 @ stub CryptUnregisterOIDInfo
Index: dlls/crypt32/main.c
===================================================================
RCS file: /home/wine/wine/dlls/crypt32/main.c,v
retrieving revision 1.19
diff -u -p -u -p -r1.19 main.c
--- dlls/crypt32/main.c	30 Nov 2004 21:39:00 -0000	1.19
+++ dlls/crypt32/main.c	4 Apr 2005 17:55:23 -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");
--- /dev/null	2005-02-11 19:52:11.491673144 -0800
+++ dlls/crypt32/protectdata.c	2005-04-04 10:52:29.268502372 -0700
@@ -0,0 +1,654 @@
+/*
+ * Copyright 2005 Kees Cook <kees at outflux.net>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "config.h"
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wincrypt.h"
+#include "winreg.h"
+#include "winnls.h"
+#include "mssip.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(crypt);
+
+#define CRYPT_MAX_REGISTRY_NAME_LENGTH 255
+static const WCHAR wszProtectDataMap[] = {
+    'S','o','f','t','w','a','r','e','\\',
+    'W','i','n','e','\\',
+    'C','r','y','p','t','\\',
+    'P','r','o','t','e','c','t','D','a','t','a','\\',
+    'M','a','p',
+    0};
+static const WCHAR wszCipher[] = {'C','i','p','h','e','r',0};
+static const WCHAR wszPlain[] = {'P','l','a','i','n',0};
+static const WCHAR wszEntropy[] = {'E','n','t','r','o','p','y',0};
+static const WCHAR wszDataDescr[] = {'D','a','t','a','D','e','s','c','r',0};
+
+/*
+ * The Win32 CryptProtectData and CryptUnprotectData functions are meant
+ * to provide a mechanism for encrypting data on a machine where other users
+ * of the system can't be trusted.  It is used in many examples as a way
+ * to store username and password information to the registry, but store
+ * it not in the clear.
+ *
+ * The encryption is symmetric, but the method is unknown.  However, since
+ * it is keyed to the machine and the user, it is unlikely that the values
+ * would be portable.  Since programs must first call CryptProtectData to
+ * get a cipher text, the underlying system just has to track the
+ * plain/entropy/cipher triplet to be able to return the plain text on a
+ * later call to CryptUnprotectData.
+ *
+ * These functions DO NOT encrypt the data, but rather, track the calls
+ * in the registry, so that programs that rely on this mechanism will
+ * still function.  Some programs refuse to run unless they can successfully
+ * call CryptProtectData and CryptUnprotectData, getting the expected values
+ * back.
+ *
+ * To store the triplets, these functions use the registry:
+ *
+ * Registry Layout:
+ *     HKEY_CURRENT_USER\Software\Wine\Crypt\ProtectData\Map\[index]
+ *         Cipher:          HEX string
+ *         Entropy:         HEX string
+ *         DataDescription: WCHAR
+ *         Plain:           HEX string
+ *
+ * If a call is made to CryptUnprotectData for an unknown cipher/entropy
+ * pair, a new registry entry is created with a plain text of "[unknown]".
+ *
+ */
+
+
+
+/* 
+ * Top-level searching function, which uses a callback to evaluate
+ * if a given registry item matches.  If the callback returns TRUE,
+ * this function stores the dwMaxValueLen & hkey, and returns TRUE.
+ * It is up to the caller to close the open registry item hkey.
+ */
+static BOOL
+crypt_search_registry(HKEY *phkeyOut,
+                      DWORD *pMaxValueLen,
+                      BOOL (*reg_match_callback)(HKEY hkey,
+                                                  DWORD maxValueLen,
+                                                 DATA_BLOB *pDataMatch,
+                                                 DATA_BLOB *pOptionalEntropy),
+                      DATA_BLOB *pDataToMatch,
+                      DATA_BLOB *pOptionalEntropy)
+{
+    LONG r;
+    HKEY hkeyMap = NULL;
+    BOOL bFound = FALSE;
+    DWORD dwIndex;
+
+    TRACE("called\n");
+
+    if (!pDataToMatch || !phkeyOut || !reg_match_callback)
+        return FALSE;
+
+    r = RegOpenKeyExW(HKEY_CURRENT_USER, wszProtectDataMap, 0, KEY_READ, &hkeyMap);
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("ProtectData registry not found\n");
+        return FALSE;
+    }        
+
+    for (dwIndex = 0; !bFound; dwIndex++)
+    {
+        HKEY hkeyIndex;
+        WCHAR wszIndexKey[CRYPT_MAX_REGISTRY_NAME_LENGTH];
+        DWORD dwIndexKeyLength=CRYPT_MAX_REGISTRY_NAME_LENGTH;
+        DWORD dwMaxValueLen;
+
+        r = RegEnumKeyExW(hkeyMap, dwIndex, wszIndexKey, &dwIndexKeyLength, NULL, NULL, NULL, NULL);
+        if (r != ERROR_SUCCESS)
+            break;
+        r = RegOpenKeyExW(hkeyMap, wszIndexKey, 0, KEY_READ, &hkeyIndex);
+        if (r != ERROR_SUCCESS)
+            break;
+
+        /* don't want the function-name prefixing from "TRACE" */
+        if (WINE_TRACE_ON(crypt))
+            wine_dbg_printf("\tChecking Map Index %s\n", debugstr_w(wszIndexKey));
+
+        r = RegQueryInfoKeyW(hkeyIndex, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &dwMaxValueLen, NULL, NULL);
+        if (r != ERROR_SUCCESS)
+        {
+            CloseHandle(hkeyIndex);
+            break;
+        }
+
+        if (reg_match_callback(hkeyIndex,dwMaxValueLen,
+                               pDataToMatch,pOptionalEntropy))
+        {
+            bFound=TRUE;
+            if (phkeyOut) *phkeyOut=hkeyIndex;
+            if (pMaxValueLen) *pMaxValueLen=dwMaxValueLen;
+        }
+        else
+        {
+            CloseHandle(hkeyIndex);
+        }
+    }
+
+    if (!bFound)
+    {
+        TRACE("no matches\n");
+    }
+
+    CloseHandle(hkeyMap);
+    return bFound;
+}
+
+
+/*
+ * Utility function for matching Entropy against a given registry item.
+ */
+static BOOL
+crypt_reg_match_entropy(HKEY hkeyIndex,
+                    DWORD maxValueLen,
+                    DATA_BLOB *pOptionalEntropy)
+{
+    /* assume that lack of Entropy means "match" */
+    if (pOptionalEntropy)
+    {
+         LONG r;
+        BYTE * pbValue;
+        DWORD dwValueLen;
+
+        dwValueLen = maxValueLen;
+        pbValue = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
+
+        r = RegQueryValueExW(hkeyIndex, wszEntropy, NULL, NULL, pbValue, &dwValueLen);
+        if (r != ERROR_SUCCESS)
+        {
+            HeapFree(GetProcessHeap(), 0, pbValue);
+            return FALSE;
+        }
+    
+        /* Does the Entropy match? */
+        if (dwValueLen!=pOptionalEntropy->cbData ||
+            memcmp(pOptionalEntropy->pbData,pbValue,dwValueLen))
+        {
+            HeapFree(GetProcessHeap(), 0, pbValue);
+            return FALSE;
+        }
+
+        HeapFree(GetProcessHeap(), 0, pbValue);
+    }
+
+    /* don't want the function-name prefix that "TRACE" writes */
+    if (WINE_TRACE_ON(crypt))
+        wine_dbg_printf("\tEntropy matched\n");
+    return TRUE;
+}
+
+/*
+ * registry matching callback for plain-text searches.  This is used
+ * to find already "encrypted" items.
+ */
+static BOOL crypt_reg_callback_match_plain(HKEY hkeyIndex,
+                                           DWORD maxValueLen,
+                                            DATA_BLOB *pDataMatch,
+                                            DATA_BLOB *pOptionalEntropy)
+{
+    LONG r;
+    BYTE * pbValue;
+    DWORD dwValueLen;
+
+    if (!pDataMatch)
+        return FALSE;
+
+    pbValue = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
+
+    dwValueLen = maxValueLen;
+    r = RegQueryValueExW(hkeyIndex, wszPlain, NULL, NULL, pbValue, &dwValueLen);
+    if (r != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, pbValue);
+        return FALSE;
+    }
+
+    /* Does the Plain match? */
+    if (dwValueLen!=pDataMatch->cbData ||
+        memcmp(pDataMatch->pbData,pbValue,dwValueLen))
+    {
+        HeapFree(GetProcessHeap(), 0, pbValue);
+        return FALSE;
+    }
+    /* don't want the function-name prefix that "TRACE" writes */
+    if (WINE_TRACE_ON(crypt))
+        wine_dbg_printf("\tPlain matched\n");
+
+    HeapFree(GetProcessHeap(), 0, pbValue);
+
+    if (!crypt_reg_match_entropy(hkeyIndex,maxValueLen,pOptionalEntropy))
+        return FALSE;
+
+    return TRUE;
+}
+
+/*
+ * registry matching callback for cipher-text searches.  This is used
+ * to find "encrypted" items based on their cipher text.
+ * One thing different here is that cipher may sometimes be NULL padded
+ * if they are unexpectedly small (<256 bytes).
+ */
+static BOOL crypt_reg_callback_match_cipher(HKEY hkeyIndex,
+                                            DWORD maxValueLen,
+                                            DATA_BLOB *pDataMatch,
+                                            DATA_BLOB *pOptionalEntropy)
+{
+    LONG r;
+    BYTE * pbValue;
+    DWORD dwValueLen;
+
+    if (!pDataMatch)
+        return FALSE;
+
+    /* Need to NULL-pad ciphers */
+    if (maxValueLen<pDataMatch->cbData)
+        maxValueLen=pDataMatch->cbData;
+    pbValue = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
+
+    dwValueLen = maxValueLen;
+    r = RegQueryValueExW(hkeyIndex, wszCipher, NULL, NULL, pbValue, &dwValueLen);
+    if (r != ERROR_SUCCESS)
+    {
+        HeapFree(GetProcessHeap(), 0, pbValue);
+        return FALSE;
+    }
+    /* Perform NULL padding */
+    for (; dwValueLen<pDataMatch->cbData; dwValueLen++)
+        pbValue[dwValueLen]=0;
+
+    /* Does the Cipher match? */
+    if (dwValueLen!=pDataMatch->cbData ||
+        memcmp(pDataMatch->pbData,pbValue,dwValueLen))
+    {
+        HeapFree(GetProcessHeap(), 0, pbValue);
+        return FALSE;
+    }
+
+    /* don't want the function-name prefix that "TRACE" writes */
+    if (WINE_TRACE_ON(crypt))
+        wine_dbg_printf("\tCipher matched\n");
+
+    HeapFree(GetProcessHeap(), 0, pbValue);
+
+    if (!crypt_reg_match_entropy(hkeyIndex,maxValueLen,pOptionalEntropy))
+        return FALSE;
+
+    return TRUE;
+}
+
+static BOOL
+crypt_find_cipher_by_plain(DATA_BLOB* pDataOut, DATA_BLOB* pDataIn,
+                   DATA_BLOB* pOptionalEntropy, LPCWSTR szDataDescr)
+{
+    LONG r;
+    HKEY hkeyIndex;
+    DWORD maxValueLen;
+    DWORD dwValueLen;
+    BYTE * pbValue;
+    BOOL result=FALSE;
+
+    TRACE("called\n");
+
+    if (!crypt_search_registry(&hkeyIndex,&maxValueLen,
+                               crypt_reg_callback_match_plain,
+                               pDataIn,pOptionalEntropy))
+    {
+        return result;
+    }
+    /* found the registry entry */
+
+       pbValue = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
+
+    dwValueLen = maxValueLen;
+    r = RegQueryValueExW(hkeyIndex, wszCipher, NULL, NULL, pbValue, &dwValueLen);
+    if (r == ERROR_SUCCESS)
+    {
+        /* make a copy of the cipher text */
+        pDataOut->cbData=dwValueLen;
+        pDataOut->pbData=LocalAlloc(LPTR,pDataOut->cbData);
+        memcpy(pDataOut->pbData,pbValue,pDataOut->cbData);
+
+        result=TRUE;
+    }
+    else
+    {
+        ERR("\tCipher value not found\n");
+    }
+
+    HeapFree(GetProcessHeap(), 0, pbValue);
+    CloseHandle(hkeyIndex);
+    return result;
+}
+
+static BOOL
+crypt_find_plain_by_cipher(DATA_BLOB* pDataOut, LPWSTR *ppszDataDescr,
+                   DATA_BLOB* pDataIn, DATA_BLOB* pOptionalEntropy)
+{
+    LONG r;
+    HKEY hkeyIndex;
+    DWORD maxValueLen;
+    DWORD dwValueLen;
+    BYTE * pbValue;
+    BOOL result=FALSE;
+
+    TRACE("called\n");
+
+    if (!crypt_search_registry(&hkeyIndex,&maxValueLen,
+                               crypt_reg_callback_match_cipher,
+                               pDataIn,pOptionalEntropy))
+    {
+        return result;
+    }
+    /* found the registry entry */
+
+       pbValue = HeapAlloc(GetProcessHeap(), 0, maxValueLen);
+
+    dwValueLen = maxValueLen;
+    r = RegQueryValueExW(hkeyIndex, wszPlain, NULL, NULL, pbValue, &dwValueLen);
+    if (r == ERROR_SUCCESS)
+    {
+        /* copy the plain text */
+        pDataOut->cbData=dwValueLen;
+        pDataOut->pbData=LocalAlloc(LPTR,pDataOut->cbData);
+        memcpy(pDataOut->pbData,pbValue,pDataOut->cbData);
+
+        /* copy the DataDescription */
+        if (ppszDataDescr)
+        {
+            dwValueLen = maxValueLen;
+            r = RegQueryValueExW(hkeyIndex, wszDataDescr, NULL, NULL, pbValue, &dwValueLen);
+            if (r != ERROR_SUCCESS)
+            {
+                /* if we don't have one stored, just return an empty string */
+                dwValueLen=2;
+                pbValue[0]='\0';
+            }
+
+            *ppszDataDescr=LocalAlloc(LPTR,dwValueLen);
+            memcpy(*ppszDataDescr,pbValue,dwValueLen);
+        }
+
+        result = TRUE;
+    }
+    else
+    {
+        ERR("\tPlain value not found\n");
+    }
+
+    HeapFree(GetProcessHeap(), 0, pbValue);
+    CloseHandle(hkeyIndex);
+    return result;
+}
+
+/*
+ * Creates a registry value, falling back to a string default.
+ * If fallback happens, the stored value is written to pDataOut
+ * if it isn't NULL
+ */
+static BOOL
+crypt_write_registry_value(HKEY hkeyOpen,
+                           const WCHAR * wszName,
+                           DWORD dwType,
+                           DATA_BLOB *pDataIn,
+                           WCHAR * wszDefault,
+                           DATA_BLOB *pDataOut)
+{
+    LONG r;
+    DATA_BLOB pData;
+
+    if (pDataIn)
+    {
+        pData.pbData=pDataIn->pbData;
+        pData.cbData=pDataIn->cbData;
+    }
+    else
+    {
+        pData.pbData=(void*)wszDefault;
+        pData.cbData=(lstrlenW(wszDefault)+1)*sizeof(WCHAR);
+
+        if (pDataOut)
+        {
+            pDataOut->cbData=pData.cbData;
+            pDataOut->pbData=LocalAlloc(LPTR,pDataOut->cbData);
+            memcpy(pDataOut->pbData,pData.pbData,pData.cbData);
+        }
+    }
+
+    r = RegSetValueExW(hkeyOpen,wszName,0,dwType, pData.pbData,pData.cbData);
+    return (r == ERROR_SUCCESS);
+}
+
+static BOOL
+crypt_create_registry_item(DATA_BLOB *pDataCipher,
+                           DATA_BLOB *pDataPlain,
+                           DATA_BLOB *pOptionalEntropy,
+                           WCHAR * szDataDescr,
+                           DATA_BLOB *pDataOut)
+{
+    LONG r;
+    BOOL okay=TRUE;
+    BOOL bFound=FALSE;
+    HKEY hkeyMap;
+    DWORD dwIndex;
+    HKEY hkeyOpen;
+    WCHAR wszIndexKey[CRYPT_MAX_REGISTRY_NAME_LENGTH];
+    WCHAR wszUnknown[] = {'[','u','n','k','n','o','w','n',']',0};
+
+    r = RegOpenKeyExW(HKEY_CURRENT_USER, wszProtectDataMap, 0, KEY_ALL_ACCESS, &hkeyMap);
+    if (r != ERROR_SUCCESS)
+    {
+        ERR("ProtectData registry not found\n");
+        return FALSE;
+    }        
+
+    /* set our search limit to 1024, arbitrarily */
+    for (dwIndex = 0; !bFound && dwIndex<1024; dwIndex++)
+    {
+        DWORD dwDisposition;
+        int i, len;
+        char buf[CRYPT_MAX_REGISTRY_NAME_LENGTH];
+        sprintf(buf,"%u",(unsigned int)dwIndex);
+        len=strlen(buf)+1;
+        for (i=0; i<len; i++) {
+            wszIndexKey[i]=buf[i];
+        }
+
+        r = RegCreateKeyExW(hkeyMap, wszIndexKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkeyOpen, &dwDisposition);
+        if (r != ERROR_SUCCESS)
+           continue;
+        if (dwDisposition == REG_OPENED_EXISTING_KEY)
+        {
+            /* already exists, skip */
+            CloseHandle(hkeyOpen);
+            continue;
+        }
+
+        bFound=TRUE;
+    }
+    CloseHandle(hkeyMap);
+
+    if (!bFound)
+    {
+        ERR("Cannot find room for new ProtectData registry item\n");
+        return FALSE;
+    }
+
+    if (!crypt_write_registry_value(hkeyOpen, wszCipher, REG_BINARY,
+                               pDataCipher, wszIndexKey, pDataOut))
+        okay=FALSE;
+    if (!crypt_write_registry_value(hkeyOpen, wszPlain, REG_BINARY,
+                               pDataPlain, wszUnknown, pDataOut))
+        okay=FALSE;
+    if (szDataDescr)
+    {
+        if (!crypt_write_registry_value(hkeyOpen, wszDataDescr, REG_SZ,
+                                   NULL, szDataDescr, NULL))
+            okay=FALSE;
+    }
+    if (pOptionalEntropy)
+    {
+        if (!crypt_write_registry_value(hkeyOpen, wszEntropy, REG_BINARY,
+                                   pOptionalEntropy, NULL, NULL))
+            okay=FALSE;
+    }
+
+    CloseHandle(hkeyOpen);
+    return okay;
+}
+
+
+static BOOL
+crypt_create_cipher_from_plain(DATA_BLOB* pDataOut, DATA_BLOB* pDataIn,
+                       DATA_BLOB* pOptionalEntropy, LPCWSTR szDataDescr)
+{
+    TRACE("called\n");
+
+    return crypt_create_registry_item(NULL,pDataIn,pOptionalEntropy,(WCHAR*)szDataDescr,pDataOut);
+}
+
+static void
+crypt_create_unknown_from_cipher(DATA_BLOB * pDataIn,
+                         DATA_BLOB* pOptionalEntropy)
+{
+    TRACE("called\n");
+
+    crypt_create_registry_item(pDataIn,NULL,pOptionalEntropy,NULL,NULL);
+}
+
+static int
+hexprint(const char *s, unsigned char *p, int n)
+{
+    char report[80];
+    int r=-1;
+    snprintf(report,16,"%14s:", s);
+    while (--n >= 0)
+    {
+        if (r++ % 20 == 19)
+        {
+            wine_dbg_printf("%s\n",report);
+            snprintf(report,16,"%14s ", "");
+        }
+        sprintf(report+strlen(report)," %02x", *p++);
+    }
+    wine_dbg_printf("%s\n",report);
+    return 0;
+}
+
+static void
+crypt_report_func_input(DATA_BLOB* pDataIn,
+                        DATA_BLOB* pOptionalEntropy,
+                        CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
+                        DWORD dwFlags)
+{
+    wine_dbg_printf("\tpPromptStruct: 0x%x\n",(unsigned int)pPromptStruct);
+    if (pPromptStruct)
+    {
+        wine_dbg_printf("\t\tcbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize);
+        wine_dbg_printf("\t\tdwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags);
+        wine_dbg_printf("\t\thwndApp: 0x%x\n",(unsigned int)pPromptStruct->hwndApp);
+        wine_dbg_printf("\t\tszPrompt: 0x%x %s\n",
+                (unsigned int)pPromptStruct->szPrompt,
+                pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
+                : "");
+    }
+    wine_dbg_printf("\tdwFlags: 0x%04x\n",(unsigned int)dwFlags);
+    wine_dbg_printf("\tpDataIn->cbData: %u\n",(unsigned int)pDataIn->cbData);
+    hexprint("pbData", pDataIn->pbData, pDataIn->cbData);
+    if (pOptionalEntropy)
+    {
+        wine_dbg_printf("\tpOptionalEntropy->cbData: %u\n",(unsigned int)pOptionalEntropy->cbData);
+        hexprint("pbData", pOptionalEntropy->pbData, pOptionalEntropy->cbData);
+        wine_dbg_printf("\t\t%s\n",debugstr_an(pOptionalEntropy->pbData,pOptionalEntropy->cbData));
+    }
+
+}
+
+BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
+                             LPCWSTR szDataDescr,
+                             DATA_BLOB* pOptionalEntropy,
+                             PVOID pvReserved,
+                             CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
+                             DWORD dwFlags,
+                             DATA_BLOB* pDataOut)
+{
+    TRACE("called\n");
+
+    if (WINE_TRACE_ON(crypt))
+    {
+        crypt_report_func_input(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+        wine_dbg_printf("\tszDataDescr: 0x%x %s\n",(unsigned int)szDataDescr,
+                szDataDescr ? debugstr_w(szDataDescr) : "");
+    }
+
+    if (crypt_find_cipher_by_plain(pDataOut, pDataIn, pOptionalEntropy, szDataDescr))
+    {
+        return TRUE;
+    }
+    if (crypt_create_cipher_from_plain(pDataOut, pDataIn, pOptionalEntropy, szDataDescr))
+    {
+        return TRUE;
+    }
+    return FALSE;
+}
+
+BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
+                               LPWSTR * ppszDataDescr,
+                               DATA_BLOB* pOptionalEntropy,
+                               PVOID pvReserved,
+                               CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
+                               DWORD dwFlags,
+                               DATA_BLOB* pDataOut)
+{
+    TRACE("called\n");
+
+    if (WINE_TRACE_ON(crypt)) {
+        crypt_report_func_input(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
+        wine_dbg_printf("\tppszDataDescr: 0x%x\n",(unsigned int)ppszDataDescr);
+    }
+
+    if (crypt_find_plain_by_cipher(pDataOut, ppszDataDescr, pDataIn, pOptionalEntropy))
+    {
+        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);
+            hexprint("pbData", pDataOut->pbData, pDataOut->cbData);
+        }
+        return TRUE;
+    }
+    /* Record the cipher and entropy for the future */
+    crypt_create_unknown_from_cipher(pDataIn, pOptionalEntropy);
+
+    return FALSE;
+}
+
+


More information about the wine-patches mailing list