Allow files other than C to be included in the projects
[reactos.git] / reactos / lib / crypt32 / protectdata.c
1 /*
2 * Copyright 2005 Kees Cook <kees@outflux.net>
3 *
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.
8 *
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.
13 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19
20 /*
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.
26 *
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.
34 *
35 */
36
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
41
42 #include "windef.h"
43 #include "winbase.h"
44 #include "wincrypt.h"
45 #include "winreg.h"
46 #include "wine/debug.h"
47
48 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
49
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
54
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
58 };
59
60 /*
61 * The data format returned by the real Windows CryptProtectData seems
62 * to be something like this:
63
64 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1)
65 BYTE info0_0[16]; - unknown information
66 ...
67 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1)
68 BYTE info1_0[16]; - unknown information
69 ...
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?)
77 DWORD null1; - NULL ?
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?
86
87 * The data structures used in Wine are modelled after this guess.
88 */
89
90 struct protect_data_t
91 {
92 DWORD count0;
93 DATA_BLOB info0; /* using this to hold crypt_magic_str */
94 DWORD count1;
95 DATA_BLOB info1;
96 DWORD null0;
97 WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */
98 DWORD unknown0; /* perhaps the HASH alg const should go here? */
99 DWORD unknown1;
100 DATA_BLOB data0;
101 DWORD null1;
102 DWORD unknown2; /* perhaps the KEY alg const should go here? */
103 DWORD unknown3;
104 DATA_BLOB salt;
105 DATA_BLOB cipher;
106 DATA_BLOB fingerprint;
107 };
108
109 /* this is used to check if an incoming structure was built by Wine */
110 static const char * crypt_magic_str = "Wine Crypt32 ok";
111
112 /* debugging tool to print strings of hex chars */
113 static const char *
114 hex_str(unsigned char *p, int n)
115 {
116 const char * ptr;
117 char report[80];
118 int r=-1;
119 report[0]='\0';
120 ptr = wine_dbg_sprintf("%s","");
121 while (--n >= 0)
122 {
123 if (r++ % 20 == 19)
124 {
125 ptr = wine_dbg_sprintf("%s%s",ptr,report);
126 report[0]='\0';
127 }
128 sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
129 }
130 return wine_dbg_sprintf("%s%s",ptr,report);
131 }
132
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)); \
137 } while (0)
138
139 static
140 void serialize_dword(DWORD value,BYTE ** ptr)
141 {
142 /*TRACE("called\n");*/
143
144 memcpy(*ptr,&value,sizeof(DWORD));
145 *ptr+=sizeof(DWORD);
146 }
147
148 static
149 void serialize_string(BYTE * str,BYTE ** ptr,DWORD len, DWORD width,
150 BOOL prepend_len)
151 {
152 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
153
154 if (prepend_len)
155 {
156 serialize_dword(len,ptr);
157 }
158 memcpy(*ptr,str,len*width);
159 *ptr+=len*width;
160 }
161
162 static
163 BOOL unserialize_dword(BYTE * ptr, DWORD *index, DWORD size, DWORD * value)
164 {
165 /*TRACE("called\n");*/
166
167 if (!ptr || !index || !value) return FALSE;
168
169 if (*index+sizeof(DWORD)>size)
170 {
171 return FALSE;
172 }
173
174 memcpy(value,&(ptr[*index]),sizeof(DWORD));
175 *index+=sizeof(DWORD);
176
177 return TRUE;
178 }
179
180 static
181 BOOL unserialize_string(BYTE * ptr, DWORD *index, DWORD size,
182 DWORD len, DWORD width, BOOL inline_len,
183 BYTE ** data, DWORD * stored)
184 {
185 /*TRACE("called\n");*/
186
187 if (!ptr || !data) return FALSE;
188
189 if (inline_len) {
190 if (!unserialize_dword(ptr,index,size,&len))
191 return FALSE;
192 }
193
194 if (*index+len*width>size)
195 {
196 return FALSE;
197 }
198
199 if (!(*data = CryptMemAlloc( len*width)))
200 {
201 return FALSE;
202 }
203
204 memcpy(*data,&(ptr[*index]),len*width);
205 if (stored)
206 {
207 *stored = len;
208 }
209 *index+=len*width;
210
211 return TRUE;
212 }
213
214 static
215 BOOL serialize(struct protect_data_t * pInfo, DATA_BLOB * pSerial)
216 {
217 BYTE * ptr;
218 DWORD dwStrLen;
219 DWORD dwStruct;
220
221 TRACE("called\n");
222
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)
227 {
228 return FALSE;
229 }
230
231 if (pInfo->info0.cbData!=16)
232 {
233 ERR("protect_data_t info0 not 16 bytes long\n");
234 }
235
236 if (pInfo->info1.cbData!=16)
237 {
238 ERR("protect_data_t info1 not 16 bytes long\n");
239 }
240
241 dwStrLen=lstrlenW(pInfo->szDataDescr);
242
243 pSerial->cbData=0;
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;
253
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;*/
258
259 pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
260 if (!pSerial->pbData) return FALSE;
261
262 ptr=pSerial->pbData;
263
264 /* count0 */
265 serialize_dword(pInfo->count0,&ptr);
266 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
267
268 /* info0 */
269 serialize_string(pInfo->info0.pbData,&ptr,
270 pInfo->info0.cbData,sizeof(BYTE),FALSE);
271 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
272
273 /* count1 */
274 serialize_dword(pInfo->count1,&ptr);
275 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
276
277 /* info1 */
278 serialize_string(pInfo->info1.pbData,&ptr,
279 pInfo->info1.cbData,sizeof(BYTE),FALSE);
280 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
281
282 /* null0 */
283 serialize_dword(pInfo->null0,&ptr);
284 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
285
286 /* szDataDescr */
287 serialize_string((BYTE*)pInfo->szDataDescr,&ptr,
288 (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE);
289 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
290
291 /* unknown0 */
292 serialize_dword(pInfo->unknown0,&ptr);
293 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
294 /* unknown1 */
295 serialize_dword(pInfo->unknown1,&ptr);
296 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
297
298 /* data0 */
299 serialize_string(pInfo->data0.pbData,&ptr,
300 pInfo->data0.cbData,sizeof(BYTE),TRUE);
301 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
302
303 /* null1 */
304 serialize_dword(pInfo->null1,&ptr);
305 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
306
307 /* unknown2 */
308 serialize_dword(pInfo->unknown2,&ptr);
309 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
310 /* unknown3 */
311 serialize_dword(pInfo->unknown3,&ptr);
312 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
313
314 /* salt */
315 serialize_string(pInfo->salt.pbData,&ptr,
316 pInfo->salt.cbData,sizeof(BYTE),TRUE);
317 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
318
319 /* cipher */
320 serialize_string(pInfo->cipher.pbData,&ptr,
321 pInfo->cipher.cbData,sizeof(BYTE),TRUE);
322 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
323
324 /* fingerprint */
325 serialize_string(pInfo->fingerprint.pbData,&ptr,
326 pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
327 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
328
329 if (ptr - pSerial->pbData != dwStruct)
330 {
331 ERR("struct size changed!? %u != expected %u\n",
332 ptr - pSerial->pbData, (unsigned int)dwStruct);
333 LocalFree(pSerial->pbData);
334 pSerial->pbData=NULL;
335 pSerial->cbData=0;
336 return FALSE;
337 }
338
339 return TRUE;
340 }
341
342 static
343 BOOL unserialize(DATA_BLOB * pSerial, struct protect_data_t * pInfo)
344 {
345 BYTE * ptr;
346 DWORD index;
347 DWORD size;
348 BOOL status=TRUE;
349
350 TRACE("called\n");
351
352 if (!pInfo || !pSerial || !pSerial->pbData)
353 return FALSE;
354
355 index=0;
356 ptr=pSerial->pbData;
357 size=pSerial->cbData;
358
359 /* count0 */
360 if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
361 {
362 ERR("reading count0 failed!\n");
363 return FALSE;
364 }
365
366 /* info0 */
367 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
368 &pInfo->info0.pbData, &pInfo->info0.cbData))
369 {
370 ERR("reading info0 failed!\n");
371 return FALSE;
372 }
373
374 /* count1 */
375 if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
376 {
377 ERR("reading count1 failed!\n");
378 return FALSE;
379 }
380
381 /* info1 */
382 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
383 &pInfo->info1.pbData, &pInfo->info1.cbData))
384 {
385 ERR("reading info1 failed!\n");
386 return FALSE;
387 }
388
389 /* null0 */
390 if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
391 {
392 ERR("reading null0 failed!\n");
393 return FALSE;
394 }
395
396 /* szDataDescr */
397 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
398 (BYTE**)&pInfo->szDataDescr, NULL))
399 {
400 ERR("reading szDataDescr failed!\n");
401 return FALSE;
402 }
403
404 /* unknown0 */
405 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0))
406 {
407 ERR("reading unknown0 failed!\n");
408 return FALSE;
409 }
410
411 /* unknown1 */
412 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1))
413 {
414 ERR("reading unknown1 failed!\n");
415 return FALSE;
416 }
417
418 /* data0 */
419 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
420 &pInfo->data0.pbData, &pInfo->data0.cbData))
421 {
422 ERR("reading data0 failed!\n");
423 return FALSE;
424 }
425
426 /* null1 */
427 if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
428 {
429 ERR("reading null1 failed!\n");
430 return FALSE;
431 }
432
433 /* unknown2 */
434 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2))
435 {
436 ERR("reading unknown2 failed!\n");
437 return FALSE;
438 }
439
440 /* unknown3 */
441 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3))
442 {
443 ERR("reading unknown3 failed!\n");
444 return FALSE;
445 }
446
447 /* salt */
448 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
449 &pInfo->salt.pbData, &pInfo->salt.cbData))
450 {
451 ERR("reading salt failed!\n");
452 return FALSE;
453 }
454
455 /* cipher */
456 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
457 &pInfo->cipher.pbData, &pInfo->cipher.cbData))
458 {
459 ERR("reading cipher failed!\n");
460 return FALSE;
461 }
462
463 /* fingerprint */
464 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
465 &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
466 {
467 ERR("reading fingerprint failed!\n");
468 return FALSE;
469 }
470
471 /* allow structure size to be too big (since some applications
472 * will pad this up to 256 bytes, it seems) */
473 if (index>size)
474 {
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);
479 status=FALSE;
480 }
481
482 return status;
483 }
484
485 /* perform sanity checks */
486 static
487 BOOL valid_protect_data(struct protect_data_t * pInfo)
488 {
489 BOOL status=TRUE;
490
491 TRACE("called\n");
492
493 if (pInfo->count0 != 0x0001)
494 {
495 ERR("count0 != 0x0001 !\n");
496 status=FALSE;
497 }
498 if (pInfo->count1 != 0x0001)
499 {
500 ERR("count0 != 0x0001 !\n");
501 status=FALSE;
502 }
503 if (pInfo->null0 != 0x0000)
504 {
505 ERR("null0 != 0x0000 !\n");
506 status=FALSE;
507 }
508 if (pInfo->null1 != 0x0000)
509 {
510 ERR("null1 != 0x0000 !\n");
511 status=FALSE;
512 }
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.
517 */
518 if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
519 strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
520 {
521 ERR("info0 magic value not matched !\n");
522 status=FALSE;
523 }
524
525 if (!status)
526 {
527 ERR("unrecognized CryptProtectData block\n");
528 }
529
530 return status;
531 }
532
533 static
534 void free_protect_data(struct protect_data_t * pInfo)
535 {
536 TRACE("called\n");
537
538 if (!pInfo) return;
539
540 if (pInfo->info0.pbData)
541 CryptMemFree(pInfo->info0.pbData);
542 if (pInfo->info1.pbData)
543 CryptMemFree(pInfo->info1.pbData);
544 if (pInfo->szDataDescr)
545 CryptMemFree(pInfo->szDataDescr);
546 if (pInfo->data0.pbData)
547 CryptMemFree(pInfo->data0.pbData);
548 if (pInfo->salt.pbData)
549 CryptMemFree(pInfo->salt.pbData);
550 if (pInfo->cipher.pbData)
551 CryptMemFree(pInfo->cipher.pbData);
552 if (pInfo->fingerprint.pbData)
553 CryptMemFree(pInfo->fingerprint.pbData);
554 }
555
556 /* copies a string into a data blob */
557 static
558 BYTE * convert_str_to_blob(char* str, DATA_BLOB* blob)
559 {
560 if (!str || !blob) return NULL;
561
562 blob->cbData=strlen(str)+1;
563 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
564 {
565 blob->cbData=0;
566 }
567 else {
568 strcpy((LPSTR)blob->pbData, str);
569 }
570
571 return blob->pbData;
572 }
573
574 /*
575 * Populates everything except "cipher" and "fingerprint".
576 */
577 static
578 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
579 HCRYPTPROV hProv)
580 {
581 DWORD dwStrLen;
582
583 TRACE("called\n");
584
585 if (!pInfo) return FALSE;
586
587 dwStrLen=lstrlenW(szDataDescr);
588
589 memset(pInfo,0,sizeof(*pInfo));
590
591 pInfo->count0=0x0001;
592
593 convert_str_to_blob((char*)crypt_magic_str,&pInfo->info0);
594
595 pInfo->count1=0x0001;
596
597 convert_str_to_blob((char*)crypt_magic_str,&pInfo->info1);
598
599 pInfo->null0=0x0000;
600
601 if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
602 {
603 memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
604 }
605
606 pInfo->unknown0=0x0000;
607 pInfo->unknown1=0x0000;
608
609 convert_str_to_blob((char*)crypt_magic_str,&pInfo->data0);
610
611 pInfo->null1=0x0000;
612 pInfo->unknown2=0x0000;
613 pInfo->unknown3=0x0000;
614
615 /* allocate memory to hold a salt */
616 pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
617 if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
618 {
619 /* generate random salt */
620 if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
621 {
622 ERR("CryptGenRandom\n");
623 free_protect_data(pInfo);
624 return FALSE;
625 }
626 }
627
628 /* debug: show our salt */
629 TRACE_DATA_BLOB(&pInfo->salt);
630
631 pInfo->cipher.cbData=0;
632 pInfo->cipher.pbData=NULL;
633
634 pInfo->fingerprint.cbData=0;
635 pInfo->fingerprint.pbData=NULL;
636
637 /* check all the allocations at once */
638 if (!pInfo->info0.pbData ||
639 !pInfo->info1.pbData ||
640 !pInfo->szDataDescr ||
641 !pInfo->data0.pbData ||
642 !pInfo->salt.pbData
643 )
644 {
645 ERR("could not allocate protect_data structures\n");
646 free_protect_data(pInfo);
647 return FALSE;
648 }
649
650 return TRUE;
651 }
652
653 static
654 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
655 {
656 DWORD dwSize;
657
658 TRACE("called\n");
659
660 if (!blob) return FALSE;
661
662 dwSize=sizeof(DWORD);
663 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
664 &dwSize, 0))
665 {
666 ERR("failed to get hash size\n");
667 return FALSE;
668 }
669
670 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
671 {
672 ERR("failed to allocate blob memory\n");
673 return FALSE;
674 }
675
676 dwSize=blob->cbData;
677 if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
678 {
679 ERR("failed to get hash value\n");
680 CryptMemFree(blob->pbData);
681 blob->pbData=NULL;
682 blob->cbData=0;
683 return FALSE;
684 }
685
686 return TRUE;
687 }
688
689 /* test that a given hash matches an exported-to-blob hash value */
690 static
691 BOOL hash_matches_blob(HCRYPTHASH hHash, DATA_BLOB * two)
692 {
693 BOOL rc = FALSE;
694 DATA_BLOB one;
695
696 if (!two || !two->pbData) return FALSE;
697
698 if (!convert_hash_to_blob(hHash,&one)) {
699 return FALSE;
700 }
701
702 if ( one.cbData == two->cbData &&
703 memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
704 {
705 rc = TRUE;
706 }
707
708 CryptMemFree(one.pbData);
709 return rc;
710 }
711
712 /* create an encryption key from a given salt and optional entropy */
713 static
714 BOOL load_encryption_key(HCRYPTPROV hProv, DATA_BLOB * salt,
715 DATA_BLOB * pOptionalEntropy, HCRYPTKEY * phKey)
716 {
717 BOOL rc = TRUE;
718 HCRYPTHASH hSaltHash;
719 char * szUsername = NULL;
720 DWORD dwUsernameLen;
721 DWORD dwError;
722
723 /* create hash for salt */
724 if (!salt || !phKey ||
725 !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
726 {
727 ERR("CryptCreateHash\n");
728 return FALSE;
729 }
730
731 /* This should be the "logon credentials" instead of username */
732 dwError=GetLastError();
733 dwUsernameLen = 0;
734 if (!GetUserNameA(NULL,&dwUsernameLen) &&
735 GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
736 (szUsername = CryptMemAlloc(dwUsernameLen)))
737 {
738 szUsername[0]='\0';
739 GetUserNameA( szUsername, &dwUsernameLen );
740 }
741 SetLastError(dwError);
742
743 /* salt the hash with:
744 * - the user id
745 * - an "internal secret"
746 * - randomness (from the salt)
747 * - user-supplied entropy
748 */
749 if ((szUsername && !CryptHashData(hSaltHash,(LPBYTE)szUsername,dwUsernameLen,0)) ||
750 !CryptHashData(hSaltHash,crypt32_protectdata_secret,
751 sizeof(crypt32_protectdata_secret)-1,0) ||
752 !CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
753 (pOptionalEntropy && !CryptHashData(hSaltHash,
754 pOptionalEntropy->pbData,
755 pOptionalEntropy->cbData,0)))
756 {
757 ERR("CryptHashData\n");
758 rc = FALSE;
759 }
760
761 /* produce a symmetric key */
762 if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
763 hSaltHash,CRYPT_EXPORTABLE,phKey))
764 {
765 ERR("CryptDeriveKey\n");
766 rc = FALSE;
767 }
768
769 /* clean up */
770 CryptDestroyHash(hSaltHash);
771 if (szUsername) CryptMemFree(szUsername);
772
773 return rc;
774 }
775
776 /* debugging tool to print the structures of a ProtectData call */
777 static void
778 report(DATA_BLOB* pDataIn, DATA_BLOB* pOptionalEntropy,
779 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags)
780 {
781 TRACE("pPromptStruct: %p\n", pPromptStruct);
782 if (pPromptStruct)
783 {
784 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize);
785 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags);
786 TRACE(" hwndApp: %p\n", pPromptStruct->hwndApp);
787 TRACE(" szPrompt: %p %s\n",
788 pPromptStruct->szPrompt,
789 pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
790 : "");
791 }
792 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags);
793 TRACE_DATA_BLOB(pDataIn);
794 if (pOptionalEntropy)
795 {
796 TRACE_DATA_BLOB(pOptionalEntropy);
797 TRACE(" %s\n",debugstr_an((LPCSTR)pOptionalEntropy->pbData,pOptionalEntropy->cbData));
798 }
799
800 }
801
802
803 /***************************************************************************
804 * CryptProtectData [CRYPT32.@]
805 *
806 * Generate Cipher data from given Plain and Entropy data.
807 *
808 * PARAMS
809 * pDataIn [I] Plain data to be enciphered
810 * szDataDescr [I] Optional Unicode string describing the Plain data
811 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
812 * pvReserved [I] Reserved, must be NULL
813 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
814 * dwFlags [I] Flags describing options to the ciphering
815 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
816 *
817 * RETURNS
818 * TRUE If a Cipher was generated.
819 * FALSE If something failed and no Cipher is available.
820 *
821 * FIXME
822 * The true Windows encryption and keying mechanisms are unknown.
823 *
824 * dwFlags and pPromptStruct are currently ignored.
825 *
826 * NOTES
827 * Memory allocated in pDataOut must be freed with LocalFree.
828 *
829 */
830 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
831 LPCWSTR szDataDescr,
832 DATA_BLOB* pOptionalEntropy,
833 PVOID pvReserved,
834 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
835 DWORD dwFlags,
836 DATA_BLOB* pDataOut)
837 {
838 BOOL rc = FALSE;
839
840 HCRYPTPROV hProv;
841 struct protect_data_t protect_data;
842 HCRYPTHASH hHash;
843 HCRYPTKEY hKey;
844 DWORD dwLength;
845
846 TRACE("called\n");
847
848 SetLastError(ERROR_SUCCESS);
849
850 if (!pDataIn || !pDataOut)
851 {
852 SetLastError(ERROR_INVALID_PARAMETER);
853 goto finished;
854 }
855
856 /* debug: show our arguments */
857 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
858 TRACE("\tszDataDescr: %p %s\n", szDataDescr,
859 szDataDescr ? debugstr_w(szDataDescr) : "");
860
861 /* Windows appears to create an empty szDataDescr instead of maintaining
862 * a NULL */
863 if (!szDataDescr)
864 szDataDescr=(WCHAR[]){'\0'};
865
866 /* get crypt context */
867 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
868 {
869 ERR("CryptAcquireContextW failed\n");
870 goto finished;
871 }
872
873 /* populate our structure */
874 if (!fill_protect_data(&protect_data,szDataDescr,hProv))
875 {
876 ERR("fill_protect_data\n");
877 goto free_context;
878 }
879
880 /* load key */
881 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
882 {
883 goto free_protect_data;
884 }
885
886 /* create a hash for the encryption validation */
887 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
888 {
889 ERR("CryptCreateHash\n");
890 goto free_key;
891 }
892
893 /* calculate storage required */
894 dwLength=pDataIn->cbData;
895 if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
896 GetLastError()!=ERROR_MORE_DATA)
897 {
898 ERR("CryptEncrypt\n");
899 goto free_hash;
900 }
901 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
902
903 /* copy plain text into cipher area for CryptEncrypt call */
904 protect_data.cipher.cbData=dwLength;
905 if (!(protect_data.cipher.pbData=CryptMemAlloc(
906 protect_data.cipher.cbData)))
907 {
908 ERR("CryptMemAlloc\n");
909 goto free_hash;
910 }
911 memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
912
913 /* encrypt! */
914 dwLength=pDataIn->cbData;
915 if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
916 &dwLength, protect_data.cipher.cbData))
917 {
918 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
919 goto free_hash;
920 }
921 protect_data.cipher.cbData=dwLength;
922
923 /* debug: show the cipher */
924 TRACE_DATA_BLOB(&protect_data.cipher);
925
926 /* attach our fingerprint */
927 if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
928 {
929 ERR("convert_hash_to_blob\n");
930 goto free_hash;
931 }
932
933 /* serialize into an opaque blob */
934 if (!serialize(&protect_data, pDataOut))
935 {
936 ERR("serialize\n");
937 goto free_hash;
938 }
939
940 /* success! */
941 rc=TRUE;
942
943 free_hash:
944 CryptDestroyHash(hHash);
945 free_key:
946 CryptDestroyKey(hKey);
947 free_protect_data:
948 free_protect_data(&protect_data);
949 free_context:
950 CryptReleaseContext(hProv,0);
951 finished:
952 /* If some error occurred, and no error code was set, force one. */
953 if (!rc && GetLastError()==ERROR_SUCCESS)
954 {
955 SetLastError(ERROR_INVALID_DATA);
956 }
957
958 if (rc)
959 {
960 SetLastError(ERROR_SUCCESS);
961
962 TRACE_DATA_BLOB(pDataOut);
963 }
964
965 TRACE("returning %s\n", rc ? "ok" : "FAIL");
966
967 return rc;
968 }
969
970
971 /***************************************************************************
972 * CryptUnprotectData [CRYPT32.@]
973 *
974 * Generate Plain data and Description from given Cipher and Entropy data.
975 *
976 * PARAMS
977 * pDataIn [I] Cipher data to be decoded
978 * ppszDataDescr [O] Optional Unicode string describing the Plain data
979 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
980 * pvReserved [I] Reserved, must be NULL
981 * pPromptStruct [I] Structure describing if/how to prompt during decoding
982 * dwFlags [I] Flags describing options to the decoding
983 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
984 *
985 * RETURNS
986 * TRUE If a Plain was generated.
987 * FALSE If something failed and no Plain is available.
988 *
989 * FIXME
990 * The true Windows encryption and keying mechanisms are unknown.
991 *
992 * dwFlags and pPromptStruct are currently ignored.
993 *
994 * NOTES
995 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
996 * with LocalFree.
997 *
998 */
999 BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
1000 LPWSTR * ppszDataDescr,
1001 DATA_BLOB* pOptionalEntropy,
1002 PVOID pvReserved,
1003 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
1004 DWORD dwFlags,
1005 DATA_BLOB* pDataOut)
1006 {
1007 BOOL rc = FALSE;
1008
1009 HCRYPTPROV hProv;
1010 struct protect_data_t protect_data;
1011 HCRYPTHASH hHash;
1012 HCRYPTKEY hKey;
1013 DWORD dwLength;
1014
1015 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.";
1016
1017 TRACE("called\n");
1018
1019 SetLastError(ERROR_SUCCESS);
1020
1021 if (!pDataIn || !pDataOut)
1022 {
1023 SetLastError(ERROR_INVALID_PARAMETER);
1024 goto finished;
1025 }
1026
1027 /* debug: show our arguments */
1028 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1029 TRACE("\tppszDataDescr: %p\n", ppszDataDescr);
1030
1031 /* take apart the opaque blob */
1032 if (!unserialize(pDataIn, &protect_data))
1033 {
1034 SetLastError(ERROR_INVALID_DATA);
1035 FIXME("%s\n",announce_bad_opaque_data);
1036 goto finished;
1037 }
1038
1039 /* perform basic validation on the resulting structure */
1040 if (!valid_protect_data(&protect_data))
1041 {
1042 SetLastError(ERROR_INVALID_DATA);
1043 FIXME("%s\n",announce_bad_opaque_data);
1044 goto free_protect_data;
1045 }
1046
1047 /* get a crypt context */
1048 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1049 {
1050 ERR("CryptAcquireContextW failed\n");
1051 goto free_protect_data;
1052 }
1053
1054 /* load key */
1055 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
1056 {
1057 goto free_context;
1058 }
1059
1060 /* create a hash for the decryption validation */
1061 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1062 {
1063 ERR("CryptCreateHash\n");
1064 goto free_key;
1065 }
1066
1067 /* prepare for plaintext */
1068 pDataOut->cbData=protect_data.cipher.cbData;
1069 if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1070 {
1071 ERR("CryptMemAlloc\n");
1072 goto free_hash;
1073 }
1074 memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1075
1076 /* decrypt! */
1077 if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
1078 &pDataOut->cbData) ||
1079 /* check the hash fingerprint */
1080 pDataOut->cbData > protect_data.cipher.cbData ||
1081 !hash_matches_blob(hHash, &protect_data.fingerprint))
1082 {
1083 SetLastError(ERROR_INVALID_DATA);
1084
1085 LocalFree( pDataOut->pbData );
1086 pDataOut->pbData = NULL;
1087 pDataOut->cbData = 0;
1088
1089 goto free_hash;
1090 }
1091
1092 /* Copy out the description */
1093 dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1094 if (ppszDataDescr)
1095 {
1096 if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1097 {
1098 ERR("LocalAlloc (ppszDataDescr)\n");
1099 goto free_hash;
1100 }
1101 else {
1102 memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1103 }
1104 }
1105
1106 /* success! */
1107 rc = TRUE;
1108
1109 free_hash:
1110 CryptDestroyHash(hHash);
1111 free_key:
1112 CryptDestroyKey(hKey);
1113 free_context:
1114 CryptReleaseContext(hProv,0);
1115 free_protect_data:
1116 free_protect_data(&protect_data);
1117 finished:
1118 /* If some error occurred, and no error code was set, force one. */
1119 if (!rc && GetLastError()==ERROR_SUCCESS)
1120 {
1121 SetLastError(ERROR_INVALID_DATA);
1122 }
1123
1124 if (rc) {
1125 SetLastError(ERROR_SUCCESS);
1126
1127 if (ppszDataDescr)
1128 {
1129 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1130 }
1131 TRACE_DATA_BLOB(pDataOut);
1132 }
1133
1134 TRACE("returning %s\n", rc ? "ok" : "FAIL");
1135
1136 return rc;
1137 }