2 * Copyright 2005 Kees Cook <kees@outflux.net>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 * The Win32 CryptProtectData and CryptUnprotectData functions are meant
22 * to provide a mechanism for encrypting data on a machine where other users
23 * of the system can't be trusted. It is used in many examples as a way
24 * to store username and password information to the registry, but store
25 * it not in the clear.
27 * The encryption is symmetric, but the method is unknown. However, since
28 * it is keyed to the machine and the user, it is unlikely that the values
29 * would be portable. Since programs must first call CryptProtectData to
30 * get a cipher text, the underlying system doesn't have to exactly
31 * match the real Windows version. However, attempts have been made to
32 * at least try to look like the Windows version, including guesses at the
33 * purpose of various portions of the "opaque data blob" that is used.
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
50 #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL
51 #define CRYPT32_PROTECTDATA_HASH_CALG CALG_MD5
52 #define CRYPT32_PROTECTDATA_KEY_CALG CALG_RC2
53 #define CRYPT32_PROTECTDATA_SALT_LEN 16
55 static const BYTE crypt32_protectdata_secret[] = {
56 'I','\'','m',' ','h','u','n','t','i','n','g',' ',
57 'w','a','b','b','i','t','s',0
61 * The data format returned by the real Windows CryptProtectData seems
62 * to be something like this:
64 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1)
65 BYTE info0_0[16]; - unknown information
67 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1)
68 BYTE info1_0[16]; - unknown information
70 DWORD null0; - NULL "end of records"?
71 DWORD str_len; - length of WCHAR string including term
72 WCHAR str[str_len]; - The "dataDescription" value
73 DWORD unknown0; - unknown value (seems large, but only WORD large)
74 DWORD unknown1; - unknown value (seems small, less than a BYTE)
75 DWORD data_len; - length of data (was 16 in samples)
76 BYTE data[data_len]; - unknown data (fingerprint?)
78 DWORD unknown2; - unknown value (seems large, but only WORD large)
79 DWORD unknown3; - unknown value (seems small, less than a BYTE)
80 DWORD salt_len; - length of salt(?) data
81 BYTE salt[salt_len]; - salt(?) for symmetric encryption
82 DWORD cipher_len; - length of cipher(?) data - was close to plain len
83 BYTE cipher[cipher_len]; - cipher text?
84 DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1
85 BYTE crc[crc_len]; - fingerprint of record?
87 * The data structures used in Wine are modelled after this guess.
93 DATA_BLOB info0; /* using this to hold crypt_magic_str */
97 WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */
98 DWORD unknown0; /* perhaps the HASH alg const should go here? */
102 DWORD unknown2; /* perhaps the KEY alg const should go here? */
106 DATA_BLOB fingerprint;
109 /* this is used to check if an incoming structure was built by Wine */
110 static const char crypt_magic_str[] = "Wine Crypt32 ok";
112 /* debugging tool to print strings of hex chars */
114 hex_str(unsigned char *p, int n)
120 ptr = wine_dbg_sprintf("%s","");
125 ptr = wine_dbg_sprintf("%s%s",ptr,report);
128 sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
130 return wine_dbg_sprintf("%s%s",ptr,report);
133 #define TRACE_DATA_BLOB(blob) do { \
134 TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
135 TRACE("%s pbData @ %p:%s\n", #blob ,(blob)->pbData, \
136 hex_str((blob)->pbData, (blob)->cbData)); \
140 void serialize_dword(DWORD value,BYTE ** ptr)
142 /*TRACE("called\n");*/
144 memcpy(*ptr,&value,sizeof(DWORD));
149 void serialize_string(BYTE * str,BYTE ** ptr,DWORD len, DWORD width,
152 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
156 serialize_dword(len,ptr);
158 memcpy(*ptr,str,len*width);
163 BOOL unserialize_dword(BYTE * ptr, DWORD *index, DWORD size, DWORD * value)
165 /*TRACE("called\n");*/
167 if (!ptr || !index || !value) return FALSE;
169 if (*index+sizeof(DWORD)>size)
174 memcpy(value,&(ptr[*index]),sizeof(DWORD));
175 *index+=sizeof(DWORD);
181 BOOL unserialize_string(BYTE * ptr, DWORD *index, DWORD size,
182 DWORD len, DWORD width, BOOL inline_len,
183 BYTE ** data, DWORD * stored)
185 /*TRACE("called\n");*/
187 if (!ptr || !data) return FALSE;
190 if (!unserialize_dword(ptr,index,size,&len))
194 if (*index+len*width>size)
199 if (!(*data = CryptMemAlloc( len*width)))
204 memcpy(*data,&(ptr[*index]),len*width);
215 BOOL serialize(struct protect_data_t * pInfo, DATA_BLOB * pSerial)
223 if (!pInfo || !pInfo->szDataDescr || !pSerial ||
224 !pInfo->info0.pbData || !pInfo->info1.pbData ||
225 !pInfo->data0.pbData || !pInfo->salt.pbData ||
226 !pInfo->cipher.pbData || !pInfo->fingerprint.pbData)
231 if (pInfo->info0.cbData!=16)
233 ERR("protect_data_t info0 not 16 bytes long\n");
236 if (pInfo->info1.cbData!=16)
238 ERR("protect_data_t info1 not 16 bytes long\n");
241 dwStrLen=lstrlenW(pInfo->szDataDescr);
244 pSerial->cbData+=sizeof(DWORD)*8; /* 8 raw DWORDs */
245 pSerial->cbData+=sizeof(DWORD)*4; /* 4 BLOBs with size */
246 pSerial->cbData+=pInfo->info0.cbData;
247 pSerial->cbData+=pInfo->info1.cbData;
248 pSerial->cbData+=(dwStrLen+1)*sizeof(WCHAR) + 4; /* str, null, size */
249 pSerial->cbData+=pInfo->data0.cbData;
250 pSerial->cbData+=pInfo->salt.cbData;
251 pSerial->cbData+=pInfo->cipher.cbData;
252 pSerial->cbData+=pInfo->fingerprint.cbData;
254 /* save the actual structure size */
255 dwStruct = pSerial->cbData;
256 /* There may be a 256 byte minimum, but I can't prove it. */
257 /*if (pSerial->cbData<256) pSerial->cbData=256;*/
259 pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
260 if (!pSerial->pbData) return FALSE;
265 serialize_dword(pInfo->count0,&ptr);
266 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
269 serialize_string(pInfo->info0.pbData,&ptr,
270 pInfo->info0.cbData,sizeof(BYTE),FALSE);
271 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
274 serialize_dword(pInfo->count1,&ptr);
275 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
278 serialize_string(pInfo->info1.pbData,&ptr,
279 pInfo->info1.cbData,sizeof(BYTE),FALSE);
280 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
283 serialize_dword(pInfo->null0,&ptr);
284 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
287 serialize_string((BYTE*)pInfo->szDataDescr,&ptr,
288 (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE);
289 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
292 serialize_dword(pInfo->unknown0,&ptr);
293 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
295 serialize_dword(pInfo->unknown1,&ptr);
296 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
299 serialize_string(pInfo->data0.pbData,&ptr,
300 pInfo->data0.cbData,sizeof(BYTE),TRUE);
301 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
304 serialize_dword(pInfo->null1,&ptr);
305 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
308 serialize_dword(pInfo->unknown2,&ptr);
309 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
311 serialize_dword(pInfo->unknown3,&ptr);
312 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
315 serialize_string(pInfo->salt.pbData,&ptr,
316 pInfo->salt.cbData,sizeof(BYTE),TRUE);
317 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
320 serialize_string(pInfo->cipher.pbData,&ptr,
321 pInfo->cipher.cbData,sizeof(BYTE),TRUE);
322 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
325 serialize_string(pInfo->fingerprint.pbData,&ptr,
326 pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
327 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
329 if (ptr - pSerial->pbData != dwStruct)
331 ERR("struct size changed!? %u != expected %u\n",
332 ptr - pSerial->pbData, (unsigned int)dwStruct);
333 LocalFree(pSerial->pbData);
334 pSerial->pbData=NULL;
343 BOOL unserialize(DATA_BLOB * pSerial, struct protect_data_t * pInfo)
352 if (!pInfo || !pSerial || !pSerial->pbData)
357 size=pSerial->cbData;
360 if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
362 ERR("reading count0 failed!\n");
367 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
368 &pInfo->info0.pbData, &pInfo->info0.cbData))
370 ERR("reading info0 failed!\n");
375 if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
377 ERR("reading count1 failed!\n");
382 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
383 &pInfo->info1.pbData, &pInfo->info1.cbData))
385 ERR("reading info1 failed!\n");
390 if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
392 ERR("reading null0 failed!\n");
397 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
398 (BYTE**)&pInfo->szDataDescr, NULL))
400 ERR("reading szDataDescr failed!\n");
405 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0))
407 ERR("reading unknown0 failed!\n");
412 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1))
414 ERR("reading unknown1 failed!\n");
419 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
420 &pInfo->data0.pbData, &pInfo->data0.cbData))
422 ERR("reading data0 failed!\n");
427 if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
429 ERR("reading null1 failed!\n");
434 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2))
436 ERR("reading unknown2 failed!\n");
441 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3))
443 ERR("reading unknown3 failed!\n");
448 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
449 &pInfo->salt.pbData, &pInfo->salt.cbData))
451 ERR("reading salt failed!\n");
456 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
457 &pInfo->cipher.pbData, &pInfo->cipher.cbData))
459 ERR("reading cipher failed!\n");
464 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
465 &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
467 ERR("reading fingerprint failed!\n");
471 /* allow structure size to be too big (since some applications
472 * will pad this up to 256 bytes, it seems) */
475 /* this is an impossible-to-reach test, but if the padding
476 * issue is ever understood, this may become more useful */
477 ERR("loaded corrupt structure! (used %u expected %u)\n",
478 (unsigned int)index, (unsigned int)size);
485 /* perform sanity checks */
487 BOOL valid_protect_data(struct protect_data_t * pInfo)
493 if (pInfo->count0 != 0x0001)
495 ERR("count0 != 0x0001 !\n");
498 if (pInfo->count1 != 0x0001)
500 ERR("count0 != 0x0001 !\n");
503 if (pInfo->null0 != 0x0000)
505 ERR("null0 != 0x0000 !\n");
508 if (pInfo->null1 != 0x0000)
510 ERR("null1 != 0x0000 !\n");
513 /* since we have no idea what info0 is used for, and it seems
514 * rather constant, we can test for a Wine-specific magic string
515 * there to be reasonably sure we're using data created by the Wine
516 * implementation of CryptProtectData.
518 if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
519 strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
521 ERR("info0 magic value not matched !\n");
527 ERR("unrecognized CryptProtectData block\n");
534 void free_protect_data(struct protect_data_t * pInfo)
540 CryptMemFree(pInfo->info0.pbData);
541 CryptMemFree(pInfo->info1.pbData);
542 CryptMemFree(pInfo->szDataDescr);
543 CryptMemFree(pInfo->data0.pbData);
544 CryptMemFree(pInfo->salt.pbData);
545 CryptMemFree(pInfo->cipher.pbData);
546 CryptMemFree(pInfo->fingerprint.pbData);
549 /* copies a string into a data blob */
551 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
553 if (!str || !blob) return NULL;
555 blob->cbData=strlen(str)+1;
556 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
561 strcpy((LPSTR)blob->pbData, str);
568 * Populates everything except "cipher" and "fingerprint".
571 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
578 if (!pInfo) return FALSE;
580 dwStrLen=lstrlenW(szDataDescr);
582 memset(pInfo,0,sizeof(*pInfo));
584 pInfo->count0=0x0001;
586 convert_str_to_blob(crypt_magic_str, &pInfo->info0);
588 pInfo->count1=0x0001;
590 convert_str_to_blob(crypt_magic_str, &pInfo->info1);
594 if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
596 memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
599 pInfo->unknown0=0x0000;
600 pInfo->unknown1=0x0000;
602 convert_str_to_blob(crypt_magic_str, &pInfo->data0);
605 pInfo->unknown2=0x0000;
606 pInfo->unknown3=0x0000;
608 /* allocate memory to hold a salt */
609 pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
610 if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
612 /* generate random salt */
613 if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
615 ERR("CryptGenRandom\n");
616 free_protect_data(pInfo);
621 /* debug: show our salt */
622 TRACE_DATA_BLOB(&pInfo->salt);
624 pInfo->cipher.cbData=0;
625 pInfo->cipher.pbData=NULL;
627 pInfo->fingerprint.cbData=0;
628 pInfo->fingerprint.pbData=NULL;
630 /* check all the allocations at once */
631 if (!pInfo->info0.pbData ||
632 !pInfo->info1.pbData ||
633 !pInfo->szDataDescr ||
634 !pInfo->data0.pbData ||
638 ERR("could not allocate protect_data structures\n");
639 free_protect_data(pInfo);
647 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
653 if (!blob) return FALSE;
655 dwSize=sizeof(DWORD);
656 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
659 ERR("failed to get hash size\n");
663 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
665 ERR("failed to allocate blob memory\n");
670 if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
672 ERR("failed to get hash value\n");
673 CryptMemFree(blob->pbData);
682 /* test that a given hash matches an exported-to-blob hash value */
684 BOOL hash_matches_blob(HCRYPTHASH hHash, DATA_BLOB * two)
689 if (!two || !two->pbData) return FALSE;
691 if (!convert_hash_to_blob(hHash,&one)) {
695 if ( one.cbData == two->cbData &&
696 memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
701 CryptMemFree(one.pbData);
705 /* create an encryption key from a given salt and optional entropy */
707 BOOL load_encryption_key(HCRYPTPROV hProv, DATA_BLOB * salt,
708 DATA_BLOB * pOptionalEntropy, HCRYPTKEY * phKey)
711 HCRYPTHASH hSaltHash;
712 char * szUsername = NULL;
716 /* create hash for salt */
717 if (!salt || !phKey ||
718 !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
720 ERR("CryptCreateHash\n");
724 /* This should be the "logon credentials" instead of username */
725 dwError=GetLastError();
727 if (!GetUserNameA(NULL,&dwUsernameLen) &&
728 GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
729 (szUsername = CryptMemAlloc(dwUsernameLen)))
732 GetUserNameA( szUsername, &dwUsernameLen );
734 SetLastError(dwError);
736 /* salt the hash with:
738 * - an "internal secret"
739 * - randomness (from the salt)
740 * - user-supplied entropy
742 if ((szUsername && !CryptHashData(hSaltHash,(LPBYTE)szUsername,dwUsernameLen,0)) ||
743 !CryptHashData(hSaltHash,crypt32_protectdata_secret,
744 sizeof(crypt32_protectdata_secret)-1,0) ||
745 !CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
746 (pOptionalEntropy && !CryptHashData(hSaltHash,
747 pOptionalEntropy->pbData,
748 pOptionalEntropy->cbData,0)))
750 ERR("CryptHashData\n");
754 /* produce a symmetric key */
755 if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
756 hSaltHash,CRYPT_EXPORTABLE,phKey))
758 ERR("CryptDeriveKey\n");
763 CryptDestroyHash(hSaltHash);
764 CryptMemFree(szUsername);
769 /* debugging tool to print the structures of a ProtectData call */
771 report(DATA_BLOB* pDataIn, DATA_BLOB* pOptionalEntropy,
772 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags)
774 TRACE("pPromptStruct: %p\n", pPromptStruct);
777 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize);
778 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags);
779 TRACE(" hwndApp: %p\n", pPromptStruct->hwndApp);
780 TRACE(" szPrompt: %p %s\n",
781 pPromptStruct->szPrompt,
782 pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
785 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags);
786 TRACE_DATA_BLOB(pDataIn);
787 if (pOptionalEntropy)
789 TRACE_DATA_BLOB(pOptionalEntropy);
790 TRACE(" %s\n",debugstr_an((LPCSTR)pOptionalEntropy->pbData,pOptionalEntropy->cbData));
796 /***************************************************************************
797 * CryptProtectData [CRYPT32.@]
799 * Generate Cipher data from given Plain and Entropy data.
802 * pDataIn [I] Plain data to be enciphered
803 * szDataDescr [I] Optional Unicode string describing the Plain data
804 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
805 * pvReserved [I] Reserved, must be NULL
806 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
807 * dwFlags [I] Flags describing options to the ciphering
808 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
811 * TRUE If a Cipher was generated.
812 * FALSE If something failed and no Cipher is available.
815 * The true Windows encryption and keying mechanisms are unknown.
817 * dwFlags and pPromptStruct are currently ignored.
820 * Memory allocated in pDataOut must be freed with LocalFree.
823 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
825 DATA_BLOB* pOptionalEntropy,
827 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
831 static const WCHAR empty_str[1];
834 struct protect_data_t protect_data;
841 SetLastError(ERROR_SUCCESS);
843 if (!pDataIn || !pDataOut)
845 SetLastError(ERROR_INVALID_PARAMETER);
849 /* debug: show our arguments */
850 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
851 TRACE("\tszDataDescr: %p %s\n", szDataDescr,
852 szDataDescr ? debugstr_w(szDataDescr) : "");
854 /* Windows appears to create an empty szDataDescr instead of maintaining
857 szDataDescr = empty_str;
859 /* get crypt context */
860 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
862 ERR("CryptAcquireContextW failed\n");
866 /* populate our structure */
867 if (!fill_protect_data(&protect_data,szDataDescr,hProv))
869 ERR("fill_protect_data\n");
874 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
876 goto free_protect_data;
879 /* create a hash for the encryption validation */
880 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
882 ERR("CryptCreateHash\n");
886 /* calculate storage required */
887 dwLength=pDataIn->cbData;
888 if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
889 GetLastError()!=ERROR_MORE_DATA)
891 ERR("CryptEncrypt\n");
894 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
896 /* copy plain text into cipher area for CryptEncrypt call */
897 protect_data.cipher.cbData=dwLength;
898 if (!(protect_data.cipher.pbData=CryptMemAlloc(
899 protect_data.cipher.cbData)))
901 ERR("CryptMemAlloc\n");
904 memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
907 dwLength=pDataIn->cbData;
908 if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
909 &dwLength, protect_data.cipher.cbData))
911 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
914 protect_data.cipher.cbData=dwLength;
916 /* debug: show the cipher */
917 TRACE_DATA_BLOB(&protect_data.cipher);
919 /* attach our fingerprint */
920 if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
922 ERR("convert_hash_to_blob\n");
926 /* serialize into an opaque blob */
927 if (!serialize(&protect_data, pDataOut))
937 CryptDestroyHash(hHash);
939 CryptDestroyKey(hKey);
941 free_protect_data(&protect_data);
943 CryptReleaseContext(hProv,0);
945 /* If some error occurred, and no error code was set, force one. */
946 if (!rc && GetLastError()==ERROR_SUCCESS)
948 SetLastError(ERROR_INVALID_DATA);
953 SetLastError(ERROR_SUCCESS);
955 TRACE_DATA_BLOB(pDataOut);
958 TRACE("returning %s\n", rc ? "ok" : "FAIL");
964 /***************************************************************************
965 * CryptUnprotectData [CRYPT32.@]
967 * Generate Plain data and Description from given Cipher and Entropy data.
970 * pDataIn [I] Cipher data to be decoded
971 * ppszDataDescr [O] Optional Unicode string describing the Plain data
972 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
973 * pvReserved [I] Reserved, must be NULL
974 * pPromptStruct [I] Structure describing if/how to prompt during decoding
975 * dwFlags [I] Flags describing options to the decoding
976 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
979 * TRUE If a Plain was generated.
980 * FALSE If something failed and no Plain is available.
983 * The true Windows encryption and keying mechanisms are unknown.
985 * dwFlags and pPromptStruct are currently ignored.
988 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
992 BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
993 LPWSTR * ppszDataDescr,
994 DATA_BLOB* pOptionalEntropy,
996 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
1003 struct protect_data_t protect_data;
1008 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.";
1012 SetLastError(ERROR_SUCCESS);
1014 if (!pDataIn || !pDataOut)
1016 SetLastError(ERROR_INVALID_PARAMETER);
1020 /* debug: show our arguments */
1021 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1022 TRACE("\tppszDataDescr: %p\n", ppszDataDescr);
1024 /* take apart the opaque blob */
1025 if (!unserialize(pDataIn, &protect_data))
1027 SetLastError(ERROR_INVALID_DATA);
1028 FIXME("%s\n",announce_bad_opaque_data);
1032 /* perform basic validation on the resulting structure */
1033 if (!valid_protect_data(&protect_data))
1035 SetLastError(ERROR_INVALID_DATA);
1036 FIXME("%s\n",announce_bad_opaque_data);
1037 goto free_protect_data;
1040 /* get a crypt context */
1041 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1043 ERR("CryptAcquireContextW failed\n");
1044 goto free_protect_data;
1048 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
1053 /* create a hash for the decryption validation */
1054 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1056 ERR("CryptCreateHash\n");
1060 /* prepare for plaintext */
1061 pDataOut->cbData=protect_data.cipher.cbData;
1062 if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1064 ERR("CryptMemAlloc\n");
1067 memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1070 if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
1071 &pDataOut->cbData) ||
1072 /* check the hash fingerprint */
1073 pDataOut->cbData > protect_data.cipher.cbData ||
1074 !hash_matches_blob(hHash, &protect_data.fingerprint))
1076 SetLastError(ERROR_INVALID_DATA);
1078 LocalFree( pDataOut->pbData );
1079 pDataOut->pbData = NULL;
1080 pDataOut->cbData = 0;
1085 /* Copy out the description */
1086 dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1089 if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1091 ERR("LocalAlloc (ppszDataDescr)\n");
1095 memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1103 CryptDestroyHash(hHash);
1105 CryptDestroyKey(hKey);
1107 CryptReleaseContext(hProv,0);
1109 free_protect_data(&protect_data);
1111 /* If some error occurred, and no error code was set, force one. */
1112 if (!rc && GetLastError()==ERROR_SUCCESS)
1114 SetLastError(ERROR_INVALID_DATA);
1118 SetLastError(ERROR_SUCCESS);
1122 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1124 TRACE_DATA_BLOB(pDataOut);
1127 TRACE("returning %s\n", rc ? "ok" : "FAIL");