kernel32: Fix off by one error.
[wine/wine-kai.git] / dlls / crypt32 / protectdata.c
bloba1a3369dcb5088db87250a0b26e91f8bb74a8713
1 /*
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.
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
42 #include "windef.h"
43 #include "winbase.h"
44 #include "wincrypt.h"
45 #include "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
49 #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL
50 #define CRYPT32_PROTECTDATA_HASH_CALG CALG_MD5
51 #define CRYPT32_PROTECTDATA_KEY_CALG CALG_RC2
52 #define CRYPT32_PROTECTDATA_SALT_LEN 16
54 static const BYTE crypt32_protectdata_secret[] = {
55 'I','\'','m',' ','h','u','n','t','i','n','g',' ',
56 'w','a','b','b','i','t','s',0
60 * The data format returned by the real Windows CryptProtectData seems
61 * to be something like this:
63 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1)
64 BYTE info0_0[16]; - unknown information
65 ...
66 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1)
67 BYTE info1_0[16]; - unknown information
68 ...
69 DWORD null0; - NULL "end of records"?
70 DWORD str_len; - length of WCHAR string including term
71 WCHAR str[str_len]; - The "dataDescription" value
72 DWORD unknown0; - unknown value (seems large, but only WORD large)
73 DWORD unknown1; - unknown value (seems small, less than a BYTE)
74 DWORD data_len; - length of data (was 16 in samples)
75 BYTE data[data_len]; - unknown data (fingerprint?)
76 DWORD null1; - NULL ?
77 DWORD unknown2; - unknown value (seems large, but only WORD large)
78 DWORD unknown3; - unknown value (seems small, less than a BYTE)
79 DWORD salt_len; - length of salt(?) data
80 BYTE salt[salt_len]; - salt(?) for symmetric encryption
81 DWORD cipher_len; - length of cipher(?) data - was close to plain len
82 BYTE cipher[cipher_len]; - cipher text?
83 DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1
84 BYTE crc[crc_len]; - fingerprint of record?
86 * The data structures used in Wine are modelled after this guess.
89 struct protect_data_t
91 DWORD count0;
92 DATA_BLOB info0; /* using this to hold crypt_magic_str */
93 DWORD count1;
94 DATA_BLOB info1;
95 DWORD null0;
96 WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */
97 DWORD unknown0; /* perhaps the HASH alg const should go here? */
98 DWORD unknown1;
99 DATA_BLOB data0;
100 DWORD null1;
101 DWORD unknown2; /* perhaps the KEY alg const should go here? */
102 DWORD unknown3;
103 DATA_BLOB salt;
104 DATA_BLOB cipher;
105 DATA_BLOB fingerprint;
108 /* this is used to check if an incoming structure was built by Wine */
109 static const char crypt_magic_str[] = "Wine Crypt32 ok";
111 /* debugging tool to print strings of hex chars */
112 static const char *
113 hex_str(const unsigned char *p, int n)
115 const char * ptr;
116 char report[80];
117 int r=-1;
118 report[0]='\0';
119 ptr = wine_dbg_sprintf("%s","");
120 while (--n >= 0)
122 if (r++ % 20 == 19)
124 ptr = wine_dbg_sprintf("%s%s",ptr,report);
125 report[0]='\0';
127 sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
129 return wine_dbg_sprintf("%s%s",ptr,report);
132 #define TRACE_DATA_BLOB(blob) do { \
133 TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
134 TRACE("%s pbData @ %p:%s\n", #blob ,(blob)->pbData, \
135 hex_str((blob)->pbData, (blob)->cbData)); \
136 } while (0)
138 static
139 void serialize_dword(DWORD value,BYTE ** ptr)
141 /*TRACE("called\n");*/
143 memcpy(*ptr,&value,sizeof(DWORD));
144 *ptr+=sizeof(DWORD);
147 static
148 void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width,
149 BOOL prepend_len)
151 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
153 if (prepend_len)
155 serialize_dword(len,ptr);
157 memcpy(*ptr,str,len*width);
158 *ptr+=len*width;
161 static
162 BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value)
164 /*TRACE("called\n");*/
166 if (!ptr || !index || !value) return FALSE;
168 if (*index+sizeof(DWORD)>size)
170 return FALSE;
173 memcpy(value,&(ptr[*index]),sizeof(DWORD));
174 *index+=sizeof(DWORD);
176 return TRUE;
179 static
180 BOOL unserialize_string(const BYTE *ptr, DWORD *index, DWORD size,
181 DWORD len, DWORD width, BOOL inline_len,
182 BYTE ** data, DWORD * stored)
184 /*TRACE("called\n");*/
186 if (!ptr || !data) return FALSE;
188 if (inline_len) {
189 if (!unserialize_dword(ptr,index,size,&len))
190 return FALSE;
193 if (*index+len*width>size)
195 return FALSE;
198 if (!(*data = CryptMemAlloc( len*width)))
200 return FALSE;
203 memcpy(*data,&(ptr[*index]),len*width);
204 if (stored)
206 *stored = len;
208 *index+=len*width;
210 return TRUE;
213 static
214 BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial)
216 BYTE * ptr;
217 DWORD dwStrLen;
218 DWORD dwStruct;
220 TRACE("called\n");
222 if (!pInfo || !pInfo->szDataDescr || !pSerial ||
223 !pInfo->info0.pbData || !pInfo->info1.pbData ||
224 !pInfo->data0.pbData || !pInfo->salt.pbData ||
225 !pInfo->cipher.pbData || !pInfo->fingerprint.pbData)
227 return FALSE;
230 if (pInfo->info0.cbData!=16)
232 ERR("protect_data_t info0 not 16 bytes long\n");
235 if (pInfo->info1.cbData!=16)
237 ERR("protect_data_t info1 not 16 bytes long\n");
240 dwStrLen=lstrlenW(pInfo->szDataDescr);
242 pSerial->cbData=0;
243 pSerial->cbData+=sizeof(DWORD)*8; /* 8 raw DWORDs */
244 pSerial->cbData+=sizeof(DWORD)*4; /* 4 BLOBs with size */
245 pSerial->cbData+=pInfo->info0.cbData;
246 pSerial->cbData+=pInfo->info1.cbData;
247 pSerial->cbData+=(dwStrLen+1)*sizeof(WCHAR) + 4; /* str, null, size */
248 pSerial->cbData+=pInfo->data0.cbData;
249 pSerial->cbData+=pInfo->salt.cbData;
250 pSerial->cbData+=pInfo->cipher.cbData;
251 pSerial->cbData+=pInfo->fingerprint.cbData;
253 /* save the actual structure size */
254 dwStruct = pSerial->cbData;
255 /* There may be a 256 byte minimum, but I can't prove it. */
256 /*if (pSerial->cbData<256) pSerial->cbData=256;*/
258 pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
259 if (!pSerial->pbData) return FALSE;
261 ptr=pSerial->pbData;
263 /* count0 */
264 serialize_dword(pInfo->count0,&ptr);
265 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
267 /* info0 */
268 serialize_string(pInfo->info0.pbData,&ptr,
269 pInfo->info0.cbData,sizeof(BYTE),FALSE);
270 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
272 /* count1 */
273 serialize_dword(pInfo->count1,&ptr);
274 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
276 /* info1 */
277 serialize_string(pInfo->info1.pbData,&ptr,
278 pInfo->info1.cbData,sizeof(BYTE),FALSE);
279 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
281 /* null0 */
282 serialize_dword(pInfo->null0,&ptr);
283 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
285 /* szDataDescr */
286 serialize_string((BYTE*)pInfo->szDataDescr,&ptr,
287 (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE);
288 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
290 /* unknown0 */
291 serialize_dword(pInfo->unknown0,&ptr);
292 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
293 /* unknown1 */
294 serialize_dword(pInfo->unknown1,&ptr);
295 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
297 /* data0 */
298 serialize_string(pInfo->data0.pbData,&ptr,
299 pInfo->data0.cbData,sizeof(BYTE),TRUE);
300 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
302 /* null1 */
303 serialize_dword(pInfo->null1,&ptr);
304 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
306 /* unknown2 */
307 serialize_dword(pInfo->unknown2,&ptr);
308 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
309 /* unknown3 */
310 serialize_dword(pInfo->unknown3,&ptr);
311 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
313 /* salt */
314 serialize_string(pInfo->salt.pbData,&ptr,
315 pInfo->salt.cbData,sizeof(BYTE),TRUE);
316 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
318 /* cipher */
319 serialize_string(pInfo->cipher.pbData,&ptr,
320 pInfo->cipher.cbData,sizeof(BYTE),TRUE);
321 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
323 /* fingerprint */
324 serialize_string(pInfo->fingerprint.pbData,&ptr,
325 pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
326 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
328 if (ptr - pSerial->pbData != dwStruct)
330 ERR("struct size changed!? %u != expected %u\n",
331 ptr - pSerial->pbData, (unsigned int)dwStruct);
332 LocalFree(pSerial->pbData);
333 pSerial->pbData=NULL;
334 pSerial->cbData=0;
335 return FALSE;
338 return TRUE;
341 static
342 BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
344 BYTE * ptr;
345 DWORD index;
346 DWORD size;
347 BOOL status=TRUE;
349 TRACE("called\n");
351 if (!pInfo || !pSerial || !pSerial->pbData)
352 return FALSE;
354 index=0;
355 ptr=pSerial->pbData;
356 size=pSerial->cbData;
358 /* count0 */
359 if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
361 ERR("reading count0 failed!\n");
362 return FALSE;
365 /* info0 */
366 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
367 &pInfo->info0.pbData, &pInfo->info0.cbData))
369 ERR("reading info0 failed!\n");
370 return FALSE;
373 /* count1 */
374 if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
376 ERR("reading count1 failed!\n");
377 return FALSE;
380 /* info1 */
381 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
382 &pInfo->info1.pbData, &pInfo->info1.cbData))
384 ERR("reading info1 failed!\n");
385 return FALSE;
388 /* null0 */
389 if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
391 ERR("reading null0 failed!\n");
392 return FALSE;
395 /* szDataDescr */
396 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
397 (BYTE**)&pInfo->szDataDescr, NULL))
399 ERR("reading szDataDescr failed!\n");
400 return FALSE;
403 /* unknown0 */
404 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0))
406 ERR("reading unknown0 failed!\n");
407 return FALSE;
410 /* unknown1 */
411 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1))
413 ERR("reading unknown1 failed!\n");
414 return FALSE;
417 /* data0 */
418 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
419 &pInfo->data0.pbData, &pInfo->data0.cbData))
421 ERR("reading data0 failed!\n");
422 return FALSE;
425 /* null1 */
426 if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
428 ERR("reading null1 failed!\n");
429 return FALSE;
432 /* unknown2 */
433 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2))
435 ERR("reading unknown2 failed!\n");
436 return FALSE;
439 /* unknown3 */
440 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3))
442 ERR("reading unknown3 failed!\n");
443 return FALSE;
446 /* salt */
447 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
448 &pInfo->salt.pbData, &pInfo->salt.cbData))
450 ERR("reading salt failed!\n");
451 return FALSE;
454 /* cipher */
455 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
456 &pInfo->cipher.pbData, &pInfo->cipher.cbData))
458 ERR("reading cipher failed!\n");
459 return FALSE;
462 /* fingerprint */
463 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
464 &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
466 ERR("reading fingerprint failed!\n");
467 return FALSE;
470 /* allow structure size to be too big (since some applications
471 * will pad this up to 256 bytes, it seems) */
472 if (index>size)
474 /* this is an impossible-to-reach test, but if the padding
475 * issue is ever understood, this may become more useful */
476 ERR("loaded corrupt structure! (used %u expected %u)\n",
477 (unsigned int)index, (unsigned int)size);
478 status=FALSE;
481 return status;
484 /* perform sanity checks */
485 static
486 BOOL valid_protect_data(const struct protect_data_t *pInfo)
488 BOOL status=TRUE;
490 TRACE("called\n");
492 if (pInfo->count0 != 0x0001)
494 ERR("count0 != 0x0001 !\n");
495 status=FALSE;
497 if (pInfo->count1 != 0x0001)
499 ERR("count0 != 0x0001 !\n");
500 status=FALSE;
502 if (pInfo->null0 != 0x0000)
504 ERR("null0 != 0x0000 !\n");
505 status=FALSE;
507 if (pInfo->null1 != 0x0000)
509 ERR("null1 != 0x0000 !\n");
510 status=FALSE;
512 /* since we have no idea what info0 is used for, and it seems
513 * rather constant, we can test for a Wine-specific magic string
514 * there to be reasonably sure we're using data created by the Wine
515 * implementation of CryptProtectData.
517 if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
518 strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
520 ERR("info0 magic value not matched !\n");
521 status=FALSE;
524 if (!status)
526 ERR("unrecognized CryptProtectData block\n");
529 return status;
532 static
533 void free_protect_data(struct protect_data_t * pInfo)
535 TRACE("called\n");
537 if (!pInfo) return;
539 CryptMemFree(pInfo->info0.pbData);
540 CryptMemFree(pInfo->info1.pbData);
541 CryptMemFree(pInfo->szDataDescr);
542 CryptMemFree(pInfo->data0.pbData);
543 CryptMemFree(pInfo->salt.pbData);
544 CryptMemFree(pInfo->cipher.pbData);
545 CryptMemFree(pInfo->fingerprint.pbData);
548 /* copies a string into a data blob */
549 static
550 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
552 if (!str || !blob) return NULL;
554 blob->cbData=strlen(str)+1;
555 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
557 blob->cbData=0;
559 else {
560 strcpy((LPSTR)blob->pbData, str);
563 return blob->pbData;
567 * Populates everything except "cipher" and "fingerprint".
569 static
570 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
571 HCRYPTPROV hProv)
573 DWORD dwStrLen;
575 TRACE("called\n");
577 if (!pInfo) return FALSE;
579 dwStrLen=lstrlenW(szDataDescr);
581 memset(pInfo,0,sizeof(*pInfo));
583 pInfo->count0=0x0001;
585 convert_str_to_blob(crypt_magic_str, &pInfo->info0);
587 pInfo->count1=0x0001;
589 convert_str_to_blob(crypt_magic_str, &pInfo->info1);
591 pInfo->null0=0x0000;
593 if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
595 memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
598 pInfo->unknown0=0x0000;
599 pInfo->unknown1=0x0000;
601 convert_str_to_blob(crypt_magic_str, &pInfo->data0);
603 pInfo->null1=0x0000;
604 pInfo->unknown2=0x0000;
605 pInfo->unknown3=0x0000;
607 /* allocate memory to hold a salt */
608 pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
609 if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
611 /* generate random salt */
612 if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
614 ERR("CryptGenRandom\n");
615 free_protect_data(pInfo);
616 return FALSE;
620 /* debug: show our salt */
621 TRACE_DATA_BLOB(&pInfo->salt);
623 pInfo->cipher.cbData=0;
624 pInfo->cipher.pbData=NULL;
626 pInfo->fingerprint.cbData=0;
627 pInfo->fingerprint.pbData=NULL;
629 /* check all the allocations at once */
630 if (!pInfo->info0.pbData ||
631 !pInfo->info1.pbData ||
632 !pInfo->szDataDescr ||
633 !pInfo->data0.pbData ||
634 !pInfo->salt.pbData
637 ERR("could not allocate protect_data structures\n");
638 free_protect_data(pInfo);
639 return FALSE;
642 return TRUE;
645 static
646 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
648 DWORD dwSize;
650 TRACE("called\n");
652 if (!blob) return FALSE;
654 dwSize=sizeof(DWORD);
655 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
656 &dwSize, 0))
658 ERR("failed to get hash size\n");
659 return FALSE;
662 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
664 ERR("failed to allocate blob memory\n");
665 return FALSE;
668 dwSize=blob->cbData;
669 if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
671 ERR("failed to get hash value\n");
672 CryptMemFree(blob->pbData);
673 blob->pbData=NULL;
674 blob->cbData=0;
675 return FALSE;
678 return TRUE;
681 /* test that a given hash matches an exported-to-blob hash value */
682 static
683 BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two)
685 BOOL rc = FALSE;
686 DATA_BLOB one;
688 if (!two || !two->pbData) return FALSE;
690 if (!convert_hash_to_blob(hHash,&one)) {
691 return FALSE;
694 if ( one.cbData == two->cbData &&
695 memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
697 rc = TRUE;
700 CryptMemFree(one.pbData);
701 return rc;
704 /* create an encryption key from a given salt and optional entropy */
705 static
706 BOOL load_encryption_key(HCRYPTPROV hProv, const DATA_BLOB *salt,
707 const DATA_BLOB *pOptionalEntropy, HCRYPTKEY *phKey)
709 BOOL rc = TRUE;
710 HCRYPTHASH hSaltHash;
711 char * szUsername = NULL;
712 DWORD dwUsernameLen;
713 DWORD dwError;
715 /* create hash for salt */
716 if (!salt || !phKey ||
717 !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
719 ERR("CryptCreateHash\n");
720 return FALSE;
723 /* This should be the "logon credentials" instead of username */
724 dwError=GetLastError();
725 dwUsernameLen = 0;
726 if (!GetUserNameA(NULL,&dwUsernameLen) &&
727 GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
728 (szUsername = CryptMemAlloc(dwUsernameLen)))
730 szUsername[0]='\0';
731 GetUserNameA( szUsername, &dwUsernameLen );
733 SetLastError(dwError);
735 /* salt the hash with:
736 * - the user id
737 * - an "internal secret"
738 * - randomness (from the salt)
739 * - user-supplied entropy
741 if ((szUsername && !CryptHashData(hSaltHash,(LPBYTE)szUsername,dwUsernameLen,0)) ||
742 !CryptHashData(hSaltHash,crypt32_protectdata_secret,
743 sizeof(crypt32_protectdata_secret)-1,0) ||
744 !CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
745 (pOptionalEntropy && !CryptHashData(hSaltHash,
746 pOptionalEntropy->pbData,
747 pOptionalEntropy->cbData,0)))
749 ERR("CryptHashData\n");
750 rc = FALSE;
753 /* produce a symmetric key */
754 if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
755 hSaltHash,CRYPT_EXPORTABLE,phKey))
757 ERR("CryptDeriveKey\n");
758 rc = FALSE;
761 /* clean up */
762 CryptDestroyHash(hSaltHash);
763 CryptMemFree(szUsername);
765 return rc;
768 /* debugging tool to print the structures of a ProtectData call */
769 static void
770 report(const DATA_BLOB* pDataIn, const DATA_BLOB* pOptionalEntropy,
771 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags)
773 TRACE("pPromptStruct: %p\n", pPromptStruct);
774 if (pPromptStruct)
776 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize);
777 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags);
778 TRACE(" hwndApp: %p\n", pPromptStruct->hwndApp);
779 TRACE(" szPrompt: %p %s\n",
780 pPromptStruct->szPrompt,
781 pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
782 : "");
784 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags);
785 TRACE_DATA_BLOB(pDataIn);
786 if (pOptionalEntropy)
788 TRACE_DATA_BLOB(pOptionalEntropy);
789 TRACE(" %s\n",debugstr_an((LPCSTR)pOptionalEntropy->pbData,pOptionalEntropy->cbData));
795 /***************************************************************************
796 * CryptProtectData [CRYPT32.@]
798 * Generate Cipher data from given Plain and Entropy data.
800 * PARAMS
801 * pDataIn [I] Plain data to be enciphered
802 * szDataDescr [I] Optional Unicode string describing the Plain data
803 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
804 * pvReserved [I] Reserved, must be NULL
805 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
806 * dwFlags [I] Flags describing options to the ciphering
807 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
809 * RETURNS
810 * TRUE If a Cipher was generated.
811 * FALSE If something failed and no Cipher is available.
813 * FIXME
814 * The true Windows encryption and keying mechanisms are unknown.
816 * dwFlags and pPromptStruct are currently ignored.
818 * NOTES
819 * Memory allocated in pDataOut must be freed with LocalFree.
822 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
823 LPCWSTR szDataDescr,
824 DATA_BLOB* pOptionalEntropy,
825 PVOID pvReserved,
826 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
827 DWORD dwFlags,
828 DATA_BLOB* pDataOut)
830 static const WCHAR empty_str[1];
831 BOOL rc = FALSE;
832 HCRYPTPROV hProv;
833 struct protect_data_t protect_data;
834 HCRYPTHASH hHash;
835 HCRYPTKEY hKey;
836 DWORD dwLength;
838 TRACE("called\n");
840 SetLastError(ERROR_SUCCESS);
842 if (!pDataIn || !pDataOut)
844 SetLastError(ERROR_INVALID_PARAMETER);
845 goto finished;
848 /* debug: show our arguments */
849 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
850 TRACE("\tszDataDescr: %p %s\n", szDataDescr,
851 szDataDescr ? debugstr_w(szDataDescr) : "");
853 /* Windows appears to create an empty szDataDescr instead of maintaining
854 * a NULL */
855 if (!szDataDescr)
856 szDataDescr = empty_str;
858 /* get crypt context */
859 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
861 ERR("CryptAcquireContextW failed\n");
862 goto finished;
865 /* populate our structure */
866 if (!fill_protect_data(&protect_data,szDataDescr,hProv))
868 ERR("fill_protect_data\n");
869 goto free_context;
872 /* load key */
873 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
875 goto free_protect_data;
878 /* create a hash for the encryption validation */
879 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
881 ERR("CryptCreateHash\n");
882 goto free_key;
885 /* calculate storage required */
886 dwLength=pDataIn->cbData;
887 if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
888 GetLastError()!=ERROR_MORE_DATA)
890 ERR("CryptEncrypt\n");
891 goto free_hash;
893 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
895 /* copy plain text into cipher area for CryptEncrypt call */
896 protect_data.cipher.cbData=dwLength;
897 if (!(protect_data.cipher.pbData=CryptMemAlloc(
898 protect_data.cipher.cbData)))
900 ERR("CryptMemAlloc\n");
901 goto free_hash;
903 memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
905 /* encrypt! */
906 dwLength=pDataIn->cbData;
907 if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
908 &dwLength, protect_data.cipher.cbData))
910 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
911 goto free_hash;
913 protect_data.cipher.cbData=dwLength;
915 /* debug: show the cipher */
916 TRACE_DATA_BLOB(&protect_data.cipher);
918 /* attach our fingerprint */
919 if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
921 ERR("convert_hash_to_blob\n");
922 goto free_hash;
925 /* serialize into an opaque blob */
926 if (!serialize(&protect_data, pDataOut))
928 ERR("serialize\n");
929 goto free_hash;
932 /* success! */
933 rc=TRUE;
935 free_hash:
936 CryptDestroyHash(hHash);
937 free_key:
938 CryptDestroyKey(hKey);
939 free_protect_data:
940 free_protect_data(&protect_data);
941 free_context:
942 CryptReleaseContext(hProv,0);
943 finished:
944 /* If some error occurred, and no error code was set, force one. */
945 if (!rc && GetLastError()==ERROR_SUCCESS)
947 SetLastError(ERROR_INVALID_DATA);
950 if (rc)
952 SetLastError(ERROR_SUCCESS);
954 TRACE_DATA_BLOB(pDataOut);
957 TRACE("returning %s\n", rc ? "ok" : "FAIL");
959 return rc;
963 /***************************************************************************
964 * CryptUnprotectData [CRYPT32.@]
966 * Generate Plain data and Description from given Cipher and Entropy data.
968 * PARAMS
969 * pDataIn [I] Cipher data to be decoded
970 * ppszDataDescr [O] Optional Unicode string describing the Plain data
971 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
972 * pvReserved [I] Reserved, must be NULL
973 * pPromptStruct [I] Structure describing if/how to prompt during decoding
974 * dwFlags [I] Flags describing options to the decoding
975 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
977 * RETURNS
978 * TRUE If a Plain was generated.
979 * FALSE If something failed and no Plain is available.
981 * FIXME
982 * The true Windows encryption and keying mechanisms are unknown.
984 * dwFlags and pPromptStruct are currently ignored.
986 * NOTES
987 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
988 * with LocalFree.
991 BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
992 LPWSTR * ppszDataDescr,
993 DATA_BLOB* pOptionalEntropy,
994 PVOID pvReserved,
995 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
996 DWORD dwFlags,
997 DATA_BLOB* pDataOut)
999 BOOL rc = FALSE;
1001 HCRYPTPROV hProv;
1002 struct protect_data_t protect_data;
1003 HCRYPTHASH hHash;
1004 HCRYPTKEY hKey;
1005 DWORD dwLength;
1007 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.";
1009 TRACE("called\n");
1011 SetLastError(ERROR_SUCCESS);
1013 if (!pDataIn || !pDataOut)
1015 SetLastError(ERROR_INVALID_PARAMETER);
1016 goto finished;
1019 /* debug: show our arguments */
1020 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1021 TRACE("\tppszDataDescr: %p\n", ppszDataDescr);
1023 /* take apart the opaque blob */
1024 if (!unserialize(pDataIn, &protect_data))
1026 SetLastError(ERROR_INVALID_DATA);
1027 FIXME("%s\n",announce_bad_opaque_data);
1028 goto finished;
1031 /* perform basic validation on the resulting structure */
1032 if (!valid_protect_data(&protect_data))
1034 SetLastError(ERROR_INVALID_DATA);
1035 FIXME("%s\n",announce_bad_opaque_data);
1036 goto free_protect_data;
1039 /* get a crypt context */
1040 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1042 ERR("CryptAcquireContextW failed\n");
1043 goto free_protect_data;
1046 /* load key */
1047 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
1049 goto free_context;
1052 /* create a hash for the decryption validation */
1053 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1055 ERR("CryptCreateHash\n");
1056 goto free_key;
1059 /* prepare for plaintext */
1060 pDataOut->cbData=protect_data.cipher.cbData;
1061 if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1063 ERR("CryptMemAlloc\n");
1064 goto free_hash;
1066 memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1068 /* decrypt! */
1069 if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
1070 &pDataOut->cbData) ||
1071 /* check the hash fingerprint */
1072 pDataOut->cbData > protect_data.cipher.cbData ||
1073 !hash_matches_blob(hHash, &protect_data.fingerprint))
1075 SetLastError(ERROR_INVALID_DATA);
1077 LocalFree( pDataOut->pbData );
1078 pDataOut->pbData = NULL;
1079 pDataOut->cbData = 0;
1081 goto free_hash;
1084 /* Copy out the description */
1085 dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1086 if (ppszDataDescr)
1088 if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1090 ERR("LocalAlloc (ppszDataDescr)\n");
1091 goto free_hash;
1093 else {
1094 memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1098 /* success! */
1099 rc = TRUE;
1101 free_hash:
1102 CryptDestroyHash(hHash);
1103 free_key:
1104 CryptDestroyKey(hKey);
1105 free_context:
1106 CryptReleaseContext(hProv,0);
1107 free_protect_data:
1108 free_protect_data(&protect_data);
1109 finished:
1110 /* If some error occurred, and no error code was set, force one. */
1111 if (!rc && GetLastError()==ERROR_SUCCESS)
1113 SetLastError(ERROR_INVALID_DATA);
1116 if (rc) {
1117 SetLastError(ERROR_SUCCESS);
1119 if (ppszDataDescr)
1121 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1123 TRACE_DATA_BLOB(pDataOut);
1126 TRACE("returning %s\n", rc ? "ok" : "FAIL");
1128 return rc;