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