crypt32: Test and fix getting a certificate context's key identifier property.
[wine] / dlls / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "wine/debug.h"
46
47 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
48
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
53
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
57 };
58
59 /*
60  * The data format returned by the real Windows CryptProtectData seems
61  * to be something like this:
62
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?
85
86  * The data structures used in Wine are modelled after this guess.
87  */
88
89 struct protect_data_t
90 {
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;
106 };
107
108 /* this is used to check if an incoming structure was built by Wine */
109 static const char crypt_magic_str[] = "Wine Crypt32 ok";
110
111 /* debugging tool to print strings of hex chars */
112 static const char *
113 hex_str(const unsigned char *p, int n)
114 {
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)
121     {
122         if (r++ % 20 == 19)
123         {
124             ptr = wine_dbg_sprintf("%s%s",ptr,report);
125             report[0]='\0';
126         }
127         sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
128     }
129     return wine_dbg_sprintf("%s%s",ptr,report);
130 }
131
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)
137
138 static
139 void serialize_dword(DWORD value,BYTE ** ptr)
140 {
141     /*TRACE("called\n");*/
142
143     memcpy(*ptr,&value,sizeof(DWORD));
144     *ptr+=sizeof(DWORD);
145 }
146
147 static
148 void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width,
149                       BOOL prepend_len)
150 {
151     /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
152
153     if (prepend_len)
154     {
155         serialize_dword(len,ptr);
156     }
157     memcpy(*ptr,str,len*width);
158     *ptr+=len*width;
159 }
160
161 static
162 BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value)
163 {
164     /*TRACE("called\n");*/
165
166     if (!ptr || !index || !value) return FALSE;
167
168     if (*index+sizeof(DWORD)>size)
169     {
170         return FALSE;
171     }
172
173     memcpy(value,&(ptr[*index]),sizeof(DWORD));
174     *index+=sizeof(DWORD);
175
176     return TRUE;
177 }
178
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)
183 {
184     /*TRACE("called\n");*/
185
186     if (!ptr || !data) return FALSE;
187
188     if (inline_len) {
189         if (!unserialize_dword(ptr,index,size,&len))
190             return FALSE;
191     }
192
193     if (*index+len*width>size)
194     {
195         return FALSE;
196     }
197
198     if (!(*data = CryptMemAlloc( len*width)))
199     {
200         return FALSE;
201     }
202
203     memcpy(*data,&(ptr[*index]),len*width);
204     if (stored)
205     {
206         *stored = len;
207     }
208     *index+=len*width;
209
210     return TRUE;
211 }
212
213 static
214 BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial)
215 {
216     BYTE * ptr;
217     DWORD dwStrLen;
218     DWORD dwStruct;
219
220     TRACE("called\n");
221
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)
226     {
227         return FALSE;
228     }
229
230     if (pInfo->info0.cbData!=16)
231     {
232         ERR("protect_data_t info0 not 16 bytes long\n");
233     }
234
235     if (pInfo->info1.cbData!=16)
236     {
237         ERR("protect_data_t info1 not 16 bytes long\n");
238     }
239
240     dwStrLen=lstrlenW(pInfo->szDataDescr);
241
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;
252
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;*/
257
258     pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
259     if (!pSerial->pbData) return FALSE;
260
261     ptr=pSerial->pbData;
262
263     /* count0 */
264     serialize_dword(pInfo->count0,&ptr);
265     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
266     
267     /* info0 */
268     serialize_string(pInfo->info0.pbData,&ptr,
269                      pInfo->info0.cbData,sizeof(BYTE),FALSE);
270     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
271
272     /* count1 */
273     serialize_dword(pInfo->count1,&ptr);
274     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
275
276     /* info1 */
277     serialize_string(pInfo->info1.pbData,&ptr,
278                      pInfo->info1.cbData,sizeof(BYTE),FALSE);
279     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
280
281     /* null0 */
282     serialize_dword(pInfo->null0,&ptr);
283     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
284     
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);*/
289
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);*/
296     
297     /* data0 */
298     serialize_string(pInfo->data0.pbData,&ptr,
299                      pInfo->data0.cbData,sizeof(BYTE),TRUE);
300     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
301
302     /* null1 */
303     serialize_dword(pInfo->null1,&ptr);
304     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
305     
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);*/
312     
313     /* salt */
314     serialize_string(pInfo->salt.pbData,&ptr,
315                      pInfo->salt.cbData,sizeof(BYTE),TRUE);
316     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
317
318     /* cipher */
319     serialize_string(pInfo->cipher.pbData,&ptr,
320                      pInfo->cipher.cbData,sizeof(BYTE),TRUE);
321     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
322
323     /* fingerprint */
324     serialize_string(pInfo->fingerprint.pbData,&ptr,
325                      pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
326     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
327
328     if (ptr - pSerial->pbData != dwStruct)
329     {
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;
336     }
337
338     return TRUE;
339 }
340
341 static
342 BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
343 {
344     BYTE * ptr;
345     DWORD index;
346     DWORD size;
347     BOOL status=TRUE;
348
349     TRACE("called\n");
350
351     if (!pInfo || !pSerial || !pSerial->pbData)
352         return FALSE;
353
354     index=0;
355     ptr=pSerial->pbData;
356     size=pSerial->cbData;
357
358     /* count0 */
359     if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
360     {
361         ERR("reading count0 failed!\n");
362         return FALSE;
363     }
364     
365     /* info0 */
366     if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
367                             &pInfo->info0.pbData, &pInfo->info0.cbData))
368     {
369         ERR("reading info0 failed!\n");
370         return FALSE;
371     }
372
373     /* count1 */
374     if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
375     {
376         ERR("reading count1 failed!\n");
377         return FALSE;
378     }
379
380     /* info1 */
381     if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
382                             &pInfo->info1.pbData, &pInfo->info1.cbData))
383     {
384         ERR("reading info1 failed!\n");
385         return FALSE;
386     }
387
388     /* null0 */
389     if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
390     {
391         ERR("reading null0 failed!\n");
392         return FALSE;
393     }
394     
395     /* szDataDescr */
396     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
397                             (BYTE**)&pInfo->szDataDescr, NULL))
398     {
399         ERR("reading szDataDescr failed!\n");
400         return FALSE;
401     }
402
403     /* unknown0 */
404     if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0))
405     {
406         ERR("reading unknown0 failed!\n");
407         return FALSE;
408     }
409     
410     /* unknown1 */
411     if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1))
412     {
413         ERR("reading unknown1 failed!\n");
414         return FALSE;
415     }
416     
417     /* data0 */
418     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
419                             &pInfo->data0.pbData, &pInfo->data0.cbData))
420     {
421         ERR("reading data0 failed!\n");
422         return FALSE;
423     }
424
425     /* null1 */
426     if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
427     {
428         ERR("reading null1 failed!\n");
429         return FALSE;
430     }
431     
432     /* unknown2 */
433     if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2))
434     {
435         ERR("reading unknown2 failed!\n");
436         return FALSE;
437     }
438     
439     /* unknown3 */
440     if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3))
441     {
442         ERR("reading unknown3 failed!\n");
443         return FALSE;
444     }
445     
446     /* salt */
447     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
448                             &pInfo->salt.pbData, &pInfo->salt.cbData))
449     {
450         ERR("reading salt failed!\n");
451         return FALSE;
452     }
453
454     /* cipher */
455     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
456                             &pInfo->cipher.pbData, &pInfo->cipher.cbData))
457     {
458         ERR("reading cipher failed!\n");
459         return FALSE;
460     }
461
462     /* fingerprint */
463     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
464                             &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
465     {
466         ERR("reading fingerprint failed!\n");
467         return FALSE;
468     }
469
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)
473     {
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;
479     }
480
481     return status;
482 }
483
484 /* perform sanity checks */
485 static
486 BOOL valid_protect_data(const struct protect_data_t *pInfo)
487 {
488     BOOL status=TRUE;
489
490     TRACE("called\n");
491
492     if (pInfo->count0 != 0x0001)
493     {
494         ERR("count0 != 0x0001 !\n");
495         status=FALSE;
496     }
497     if (pInfo->count1 != 0x0001)
498     {
499         ERR("count0 != 0x0001 !\n");
500         status=FALSE;
501     }
502     if (pInfo->null0 != 0x0000)
503     {
504         ERR("null0 != 0x0000 !\n");
505         status=FALSE;
506     }
507     if (pInfo->null1 != 0x0000)
508     {
509         ERR("null1 != 0x0000 !\n");
510         status=FALSE;
511     }
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.
516      */
517     if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
518         strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
519     {
520         ERR("info0 magic value not matched !\n");
521         status=FALSE;
522     }
523
524     if (!status)
525     {
526         ERR("unrecognized CryptProtectData block\n");
527     }
528
529     return status;
530 }
531
532 static
533 void free_protect_data(struct protect_data_t * pInfo)
534 {
535     TRACE("called\n");
536
537     if (!pInfo) return;
538
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);
546 }
547
548 /* copies a string into a data blob */
549 static
550 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
551 {
552     if (!str || !blob) return NULL;
553
554     blob->cbData=strlen(str)+1;
555     if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
556     {
557         blob->cbData=0;
558     }
559     else {
560         strcpy((LPSTR)blob->pbData, str);
561     }
562
563     return blob->pbData;
564 }
565
566 /*
567  * Populates everything except "cipher" and "fingerprint".
568  */
569 static
570 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
571                        HCRYPTPROV hProv)
572 {
573     DWORD dwStrLen;
574
575     TRACE("called\n");
576
577     if (!pInfo) return FALSE;
578
579     dwStrLen=lstrlenW(szDataDescr);
580
581     memset(pInfo,0,sizeof(*pInfo));
582
583     pInfo->count0=0x0001;
584
585     convert_str_to_blob(crypt_magic_str, &pInfo->info0);
586
587     pInfo->count1=0x0001;
588
589     convert_str_to_blob(crypt_magic_str, &pInfo->info1);
590
591     pInfo->null0=0x0000;
592
593     if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
594     {
595         memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
596     }
597
598     pInfo->unknown0=0x0000;
599     pInfo->unknown1=0x0000;
600
601     convert_str_to_blob(crypt_magic_str, &pInfo->data0);
602
603     pInfo->null1=0x0000;
604     pInfo->unknown2=0x0000;
605     pInfo->unknown3=0x0000;
606
607     /* allocate memory to hold a salt */
608     pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
609     if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
610     {
611         /* generate random salt */
612         if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
613         {
614             ERR("CryptGenRandom\n");
615             free_protect_data(pInfo);
616             return FALSE;
617         }
618     }
619
620     /* debug: show our salt */
621     TRACE_DATA_BLOB(&pInfo->salt);
622
623     pInfo->cipher.cbData=0;
624     pInfo->cipher.pbData=NULL;
625
626     pInfo->fingerprint.cbData=0;
627     pInfo->fingerprint.pbData=NULL;
628
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
635         )
636     {
637         ERR("could not allocate protect_data structures\n");
638         free_protect_data(pInfo);
639         return FALSE;
640     }
641
642     return TRUE;
643 }
644
645 static
646 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
647 {
648     DWORD dwSize;
649
650     TRACE("called\n");
651
652     if (!blob) return FALSE;
653
654     dwSize=sizeof(DWORD);
655     if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
656                            &dwSize, 0))
657     {
658         ERR("failed to get hash size\n");
659         return FALSE;
660     }
661
662     if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
663     {
664         ERR("failed to allocate blob memory\n");
665         return FALSE;
666     }
667
668     dwSize=blob->cbData;
669     if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
670     {
671         ERR("failed to get hash value\n");
672         CryptMemFree(blob->pbData);
673         blob->pbData=NULL;
674         blob->cbData=0;
675         return FALSE;
676     }
677
678     return TRUE;
679 }
680
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)
684 {
685     BOOL rc = FALSE;
686     DATA_BLOB one;
687
688     if (!two || !two->pbData) return FALSE;
689
690     if (!convert_hash_to_blob(hHash,&one)) {
691         return FALSE;
692     }
693
694     if ( one.cbData == two->cbData &&
695          memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
696     {
697         rc = TRUE;
698     }
699
700     CryptMemFree(one.pbData);
701     return rc;
702 }
703
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)
708 {
709     BOOL rc = TRUE;
710     HCRYPTHASH hSaltHash;
711     char * szUsername = NULL;
712     DWORD dwUsernameLen;
713     DWORD dwError;
714
715     /* create hash for salt */
716     if (!salt || !phKey ||
717         !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
718     {
719         ERR("CryptCreateHash\n");
720         return FALSE;
721     }
722
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)))
729     {
730         szUsername[0]='\0';
731         GetUserNameA( szUsername, &dwUsernameLen );
732     }
733     SetLastError(dwError);
734
735     /* salt the hash with:
736      * - the user id
737      * - an "internal secret"
738      * - randomness (from the salt)
739      * - user-supplied entropy
740      */
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)))
748     {
749         ERR("CryptHashData\n");
750         rc = FALSE;
751     }
752
753     /* produce a symmetric key */
754     if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
755                               hSaltHash,CRYPT_EXPORTABLE,phKey))
756     {
757         ERR("CryptDeriveKey\n");
758         rc = FALSE;
759     }
760
761     /* clean up */
762     CryptDestroyHash(hSaltHash);
763     CryptMemFree(szUsername);
764
765     return rc;
766 }
767
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)
772 {
773     TRACE("pPromptStruct: %p\n", pPromptStruct);
774     if (pPromptStruct)
775     {
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               : "");
783     }
784     TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags);
785     TRACE_DATA_BLOB(pDataIn);
786     if (pOptionalEntropy)
787     {
788         TRACE_DATA_BLOB(pOptionalEntropy);
789         TRACE("  %s\n",debugstr_an((LPCSTR)pOptionalEntropy->pbData,pOptionalEntropy->cbData));
790     }
791
792 }
793
794
795 /***************************************************************************
796  * CryptProtectData     [CRYPT32.@]
797  *
798  * Generate Cipher data from given Plain and Entropy data.
799  *
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
808  *
809  * RETURNS
810  *  TRUE  If a Cipher was generated.
811  *  FALSE If something failed and no Cipher is available.
812  *
813  * FIXME
814  *  The true Windows encryption and keying mechanisms are unknown.
815  *
816  *  dwFlags and pPromptStruct are currently ignored.
817  *
818  * NOTES
819  *  Memory allocated in pDataOut must be freed with LocalFree.
820  *
821  */
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)
829 {
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;
837
838     TRACE("called\n");
839
840     SetLastError(ERROR_SUCCESS);
841
842     if (!pDataIn || !pDataOut)
843     {
844         SetLastError(ERROR_INVALID_PARAMETER);
845         goto finished;
846     }
847
848     /* debug: show our arguments */
849     report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
850     TRACE("\tszDataDescr: %p %s\n", szDataDescr,
851           szDataDescr ? debugstr_w(szDataDescr) : "");
852
853     /* Windows appears to create an empty szDataDescr instead of maintaining
854      * a NULL */
855     if (!szDataDescr)
856         szDataDescr = empty_str;
857
858     /* get crypt context */
859     if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
860     {
861         ERR("CryptAcquireContextW failed\n");
862         goto finished;
863     }
864
865     /* populate our structure */
866     if (!fill_protect_data(&protect_data,szDataDescr,hProv))
867     {
868         ERR("fill_protect_data\n");
869         goto free_context;
870     }
871
872     /* load key */
873     if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
874     {
875         goto free_protect_data;
876     }
877
878     /* create a hash for the encryption validation */
879     if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
880     {
881         ERR("CryptCreateHash\n");
882         goto free_key;
883     }
884
885     /* calculate storage required */
886     dwLength=pDataIn->cbData;
887     if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
888         GetLastError()!=ERROR_MORE_DATA)
889     {
890         ERR("CryptEncrypt\n");
891         goto free_hash;
892     }
893     TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
894
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)))
899     {
900         ERR("CryptMemAlloc\n");
901         goto free_hash;
902     }
903     memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
904
905     /* encrypt! */
906     dwLength=pDataIn->cbData;
907     if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
908                       &dwLength, protect_data.cipher.cbData))
909     {
910         ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
911         goto free_hash;
912     }
913     protect_data.cipher.cbData=dwLength;
914
915     /* debug: show the cipher */
916     TRACE_DATA_BLOB(&protect_data.cipher);
917
918     /* attach our fingerprint */
919     if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
920     {
921         ERR("convert_hash_to_blob\n");
922         goto free_hash;
923     }
924
925     /* serialize into an opaque blob */
926     if (!serialize(&protect_data, pDataOut))
927     {
928         ERR("serialize\n");
929         goto free_hash;
930     }
931
932     /* success! */
933     rc=TRUE;
934
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)
946     {
947         SetLastError(ERROR_INVALID_DATA);
948     }
949
950     if (rc)
951     {
952         SetLastError(ERROR_SUCCESS);
953
954         TRACE_DATA_BLOB(pDataOut);
955     }
956
957     TRACE("returning %s\n", rc ? "ok" : "FAIL");
958
959     return rc;
960 }
961
962
963 /***************************************************************************
964  * CryptUnprotectData   [CRYPT32.@]
965  *
966  * Generate Plain data and Description from given Cipher and Entropy data.
967  *
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
976  *
977  * RETURNS
978  *  TRUE  If a Plain was generated.
979  *  FALSE If something failed and no Plain is available.
980  *
981  * FIXME
982  *  The true Windows encryption and keying mechanisms are unknown.
983  *
984  *  dwFlags and pPromptStruct are currently ignored.
985  *
986  * NOTES
987  *  Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
988  *  with LocalFree.
989  *
990  */
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)
998 {
999     BOOL rc = FALSE;
1000
1001     HCRYPTPROV hProv;
1002     struct protect_data_t protect_data;
1003     HCRYPTHASH hHash;
1004     HCRYPTKEY hKey;
1005     DWORD dwLength;
1006
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.";
1008
1009     TRACE("called\n");
1010
1011     SetLastError(ERROR_SUCCESS);
1012
1013     if (!pDataIn || !pDataOut)
1014     {
1015         SetLastError(ERROR_INVALID_PARAMETER);
1016         goto finished;
1017     }
1018
1019     /* debug: show our arguments */
1020     report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1021     TRACE("\tppszDataDescr: %p\n", ppszDataDescr);
1022
1023     /* take apart the opaque blob */
1024     if (!unserialize(pDataIn, &protect_data))
1025     {
1026         SetLastError(ERROR_INVALID_DATA);
1027         FIXME("%s\n",announce_bad_opaque_data);
1028         goto finished;
1029     }
1030
1031     /* perform basic validation on the resulting structure */
1032     if (!valid_protect_data(&protect_data))
1033     {
1034         SetLastError(ERROR_INVALID_DATA);
1035         FIXME("%s\n",announce_bad_opaque_data);
1036         goto free_protect_data;
1037     }
1038
1039     /* get a crypt context */
1040     if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1041     {
1042         ERR("CryptAcquireContextW failed\n");
1043         goto free_protect_data;
1044     }
1045
1046     /* load key */
1047     if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
1048     {
1049         goto free_context;
1050     }
1051
1052     /* create a hash for the decryption validation */
1053     if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1054     {
1055         ERR("CryptCreateHash\n");
1056         goto free_key;
1057     }
1058
1059     /* prepare for plaintext */
1060     pDataOut->cbData=protect_data.cipher.cbData;
1061     if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1062     {
1063         ERR("CryptMemAlloc\n");
1064         goto free_hash;
1065     }
1066     memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1067
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))
1074     {
1075         SetLastError(ERROR_INVALID_DATA);
1076
1077         LocalFree( pDataOut->pbData );
1078         pDataOut->pbData = NULL;
1079         pDataOut->cbData = 0;
1080
1081         goto free_hash;
1082     }
1083
1084     /* Copy out the description */
1085     dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1086     if (ppszDataDescr)
1087     {
1088         if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1089         {
1090             ERR("LocalAlloc (ppszDataDescr)\n");
1091             goto free_hash;
1092         }
1093         else {
1094             memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1095         }
1096     }
1097
1098     /* success! */
1099     rc = TRUE;
1100
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)
1112     {
1113         SetLastError(ERROR_INVALID_DATA);
1114     }
1115
1116     if (rc) {
1117         SetLastError(ERROR_SUCCESS);
1118
1119         if (ppszDataDescr)
1120         {
1121             TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1122         }
1123         TRACE_DATA_BLOB(pDataOut);
1124     }
1125
1126     TRACE("returning %s\n", rc ? "ok" : "FAIL");
1127
1128     return rc;
1129 }