netstat: Initial implementation.
[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_SHA1
51 #define CRYPT32_PROTECTDATA_HASH_LEN  160
52 #define CRYPT32_PROTECTDATA_KEY_CALG  CALG_3DES
53 #define CRYPT32_PROTECTDATA_KEY_LEN   168
54 #define CRYPT32_PROTECTDATA_SALT_LEN  16
55
56 static const BYTE crypt32_protectdata_secret[] = {
57     'I','\'','m',' ','h','u','n','t','i','n','g',' ',
58     'w','a','b','b','i','t','s',0
59 };
60
61 /*
62  * The data format returned by the real Windows CryptProtectData seems
63  * to be something like this:
64
65  DWORD  count0;         - how many "info0_*[16]" blocks follow (was always 1)
66  BYTE   info0_0[16];    - unknown information - persistent across invocations,
67  ...                      reboots, password changes, and users
68  DWORD  count1;         - how many "info1_*[16]" blocks follow (was always 1)
69  BYTE   info1_0[16];    - unknown information - unique to each user, but
70  ...                      persistent across reboots and password changes
71  DWORD  null0;          - NULL "end of records"?
72  DWORD  str_len;        - byte length of WCHAR string including term
73  BYTE   str[str_len];   - The "dataDescription" value as a NULL-terminated
74                           little-endian WCHAR string
75  ALG_ID cipher_alg;     - cipher algo - was CALG_3DES
76  DWORD  cipher_key_len; - cipher key bit length - was 0xa8==168
77  DWORD  data_len;       - length of data (was 16 in samples)
78  BYTE   data[data_len]; - unknown data (fingerprint?)
79  DWORD  null1;          - NULL ?
80  ALG_ID hash_alg;       - hash algo - was CALG_SHA1
81  DWORD  hash_len;       - bit length of hash - was 0xa0==160
82  DWORD  salt_len;       - length of salt(?) data
83  BYTE   salt[salt_len]; - salt(?) for symmetric encryption
84  DWORD  cipher_len;     - length of cipher(?) data - was close to plain len
85  BYTE   cipher[cipher_len]; - cipher text?
86  DWORD  crc_len;        - length of fingerprint(?) data - was 20 byte==160b SHA1
87  BYTE   crc[crc_len];   - fingerprint of record?
88
89  * The data structures used in Wine are modelled after this guess.
90  */
91
92 struct protect_data_t
93 {
94     DWORD       count0;
95     DATA_BLOB   info0;        /* using this to hold crypt_magic_str */
96     DWORD       count1;
97     DATA_BLOB   info1;
98     DWORD       null0;
99     WCHAR *     szDataDescr;  /* serialized differently than the DATA_BLOBs */
100     ALG_ID      cipher_alg;
101     DWORD       cipher_key_len;
102     DATA_BLOB   data0;
103     DWORD       null1;
104     ALG_ID      hash_alg;
105     DWORD       hash_len;
106     DATA_BLOB   salt;
107     DATA_BLOB   cipher;
108     DATA_BLOB   fingerprint;
109 };
110
111 /* this is used to check if an incoming structure was built by Wine */
112 static const char crypt_magic_str[] = "Wine Crypt32 ok";
113
114 /* debugging tool to print strings of hex chars */
115 static const char *
116 hex_str(const unsigned char *p, int n)
117 {
118     const char * ptr;
119     char report[80];
120     int r=-1;
121     report[0]='\0';
122     ptr = wine_dbg_sprintf("%s","");
123     while (--n >= 0)
124     {
125         if (r++ % 20 == 19)
126         {
127             ptr = wine_dbg_sprintf("%s%s",ptr,report);
128             report[0]='\0';
129         }
130         sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
131     }
132     return wine_dbg_sprintf("%s%s",ptr,report);
133 }
134
135 #define TRACE_DATA_BLOB(blob) do { \
136     TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
137     TRACE("%s pbData @ %p:%s\n", #blob ,(blob)->pbData, \
138           hex_str((blob)->pbData, (blob)->cbData)); \
139 } while (0)
140
141 static
142 void serialize_dword(DWORD value,BYTE ** ptr)
143 {
144     /*TRACE("called\n");*/
145
146     memcpy(*ptr,&value,sizeof(DWORD));
147     *ptr+=sizeof(DWORD);
148 }
149
150 static
151 void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width,
152                       BOOL prepend_len)
153 {
154     /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
155
156     if (prepend_len)
157     {
158         serialize_dword(len,ptr);
159     }
160     memcpy(*ptr,str,len*width);
161     *ptr+=len*width;
162 }
163
164 static
165 BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value)
166 {
167     /*TRACE("called\n");*/
168
169     if (!ptr || !index || !value) return FALSE;
170
171     if (*index+sizeof(DWORD)>size)
172     {
173         return FALSE;
174     }
175
176     memcpy(value,&(ptr[*index]),sizeof(DWORD));
177     *index+=sizeof(DWORD);
178
179     return TRUE;
180 }
181
182 static
183 BOOL unserialize_string(const BYTE *ptr, DWORD *index, DWORD size,
184                         DWORD len, DWORD width, BOOL inline_len,
185                         BYTE ** data, DWORD * stored)
186 {
187     /*TRACE("called\n");*/
188
189     if (!ptr || !data) return FALSE;
190
191     if (inline_len) {
192         if (!unserialize_dword(ptr,index,size,&len))
193             return FALSE;
194     }
195
196     if (*index+len*width>size)
197     {
198         return FALSE;
199     }
200
201     if (!(*data = CryptMemAlloc( len*width)))
202     {
203         return FALSE;
204     }
205
206     memcpy(*data,&(ptr[*index]),len*width);
207     if (stored)
208     {
209         *stored = len;
210     }
211     *index+=len*width;
212
213     return TRUE;
214 }
215
216 static
217 BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial)
218 {
219     BYTE * ptr;
220     DWORD dwStrLen;
221     DWORD dwStruct;
222
223     TRACE("called\n");
224
225     if (!pInfo || !pInfo->szDataDescr || !pSerial ||
226         !pInfo->info0.pbData || !pInfo->info1.pbData ||
227         !pInfo->data0.pbData || !pInfo->salt.pbData ||
228         !pInfo->cipher.pbData || !pInfo->fingerprint.pbData)
229     {
230         return FALSE;
231     }
232
233     if (pInfo->info0.cbData!=16)
234     {
235         ERR("protect_data_t info0 not 16 bytes long\n");
236     }
237
238     if (pInfo->info1.cbData!=16)
239     {
240         ERR("protect_data_t info1 not 16 bytes long\n");
241     }
242
243     dwStrLen=lstrlenW(pInfo->szDataDescr);
244
245     pSerial->cbData=0;
246     pSerial->cbData+=sizeof(DWORD)*8; /* 8 raw DWORDs */
247     pSerial->cbData+=sizeof(DWORD)*4; /* 4 BLOBs with size */
248     pSerial->cbData+=pInfo->info0.cbData;
249     pSerial->cbData+=pInfo->info1.cbData;
250     pSerial->cbData+=(dwStrLen+1)*sizeof(WCHAR) + 4; /* str, null, size */
251     pSerial->cbData+=pInfo->data0.cbData;
252     pSerial->cbData+=pInfo->salt.cbData;
253     pSerial->cbData+=pInfo->cipher.cbData;
254     pSerial->cbData+=pInfo->fingerprint.cbData;
255
256     /* save the actual structure size */
257     dwStruct = pSerial->cbData;
258     /* There may be a 256 byte minimum, but I can't prove it. */
259     /*if (pSerial->cbData<256) pSerial->cbData=256;*/
260
261     pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
262     if (!pSerial->pbData) return FALSE;
263
264     ptr=pSerial->pbData;
265
266     /* count0 */
267     serialize_dword(pInfo->count0,&ptr);
268     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
269     
270     /* info0 */
271     serialize_string(pInfo->info0.pbData,&ptr,
272                      pInfo->info0.cbData,sizeof(BYTE),FALSE);
273     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
274
275     /* count1 */
276     serialize_dword(pInfo->count1,&ptr);
277     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
278
279     /* info1 */
280     serialize_string(pInfo->info1.pbData,&ptr,
281                      pInfo->info1.cbData,sizeof(BYTE),FALSE);
282     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
283
284     /* null0 */
285     serialize_dword(pInfo->null0,&ptr);
286     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
287     
288     /* szDataDescr */
289     serialize_string((BYTE*)pInfo->szDataDescr,&ptr,
290                      (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE);
291     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
292
293     /* cipher_alg */
294     serialize_dword(pInfo->cipher_alg,&ptr);
295     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
296     /* cipher_key_len */
297     serialize_dword(pInfo->cipher_key_len,&ptr);
298     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
299     
300     /* data0 */
301     serialize_string(pInfo->data0.pbData,&ptr,
302                      pInfo->data0.cbData,sizeof(BYTE),TRUE);
303     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
304
305     /* null1 */
306     serialize_dword(pInfo->null1,&ptr);
307     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
308     
309     /* hash_alg */
310     serialize_dword(pInfo->hash_alg,&ptr);
311     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
312     /* hash_len */
313     serialize_dword(pInfo->hash_len,&ptr);
314     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
315     
316     /* salt */
317     serialize_string(pInfo->salt.pbData,&ptr,
318                      pInfo->salt.cbData,sizeof(BYTE),TRUE);
319     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
320
321     /* cipher */
322     serialize_string(pInfo->cipher.pbData,&ptr,
323                      pInfo->cipher.cbData,sizeof(BYTE),TRUE);
324     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
325
326     /* fingerprint */
327     serialize_string(pInfo->fingerprint.pbData,&ptr,
328                      pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
329     /*TRACE("used %u\n",ptr-pSerial->pbData);*/
330
331     if (ptr - pSerial->pbData != dwStruct)
332     {
333         ERR("struct size changed!? expected %u\n", dwStruct);
334         LocalFree(pSerial->pbData);
335         pSerial->pbData=NULL;
336         pSerial->cbData=0;
337         return FALSE;
338     }
339
340     return TRUE;
341 }
342
343 static
344 BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
345 {
346     BYTE * ptr;
347     DWORD index;
348     DWORD size;
349     BOOL status=TRUE;
350
351     TRACE("called\n");
352
353     if (!pInfo || !pSerial || !pSerial->pbData)
354         return FALSE;
355
356     index=0;
357     ptr=pSerial->pbData;
358     size=pSerial->cbData;
359
360     /* count0 */
361     if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
362     {
363         ERR("reading count0 failed!\n");
364         return FALSE;
365     }
366     
367     /* info0 */
368     if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
369                             &pInfo->info0.pbData, &pInfo->info0.cbData))
370     {
371         ERR("reading info0 failed!\n");
372         return FALSE;
373     }
374
375     /* count1 */
376     if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
377     {
378         ERR("reading count1 failed!\n");
379         return FALSE;
380     }
381
382     /* info1 */
383     if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
384                             &pInfo->info1.pbData, &pInfo->info1.cbData))
385     {
386         ERR("reading info1 failed!\n");
387         return FALSE;
388     }
389
390     /* null0 */
391     if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
392     {
393         ERR("reading null0 failed!\n");
394         return FALSE;
395     }
396     
397     /* szDataDescr */
398     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
399                             (BYTE**)&pInfo->szDataDescr, NULL))
400     {
401         ERR("reading szDataDescr failed!\n");
402         return FALSE;
403     }
404
405     /* cipher_alg */
406     if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_alg))
407     {
408         ERR("reading cipher_alg failed!\n");
409         return FALSE;
410     }
411     
412     /* cipher_key_len */
413     if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_key_len))
414     {
415         ERR("reading cipher_key_len failed!\n");
416         return FALSE;
417     }
418     
419     /* data0 */
420     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
421                             &pInfo->data0.pbData, &pInfo->data0.cbData))
422     {
423         ERR("reading data0 failed!\n");
424         return FALSE;
425     }
426
427     /* null1 */
428     if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
429     {
430         ERR("reading null1 failed!\n");
431         return FALSE;
432     }
433     
434     /* hash_alg */
435     if (!unserialize_dword(ptr,&index,size,&pInfo->hash_alg))
436     {
437         ERR("reading hash_alg failed!\n");
438         return FALSE;
439     }
440     
441     /* hash_len */
442     if (!unserialize_dword(ptr,&index,size,&pInfo->hash_len))
443     {
444         ERR("reading hash_len failed!\n");
445         return FALSE;
446     }
447     
448     /* salt */
449     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
450                             &pInfo->salt.pbData, &pInfo->salt.cbData))
451     {
452         ERR("reading salt failed!\n");
453         return FALSE;
454     }
455
456     /* cipher */
457     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
458                             &pInfo->cipher.pbData, &pInfo->cipher.cbData))
459     {
460         ERR("reading cipher failed!\n");
461         return FALSE;
462     }
463
464     /* fingerprint */
465     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
466                             &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
467     {
468         ERR("reading fingerprint failed!\n");
469         return FALSE;
470     }
471
472     /* allow structure size to be too big (since some applications
473      * will pad this up to 256 bytes, it seems) */
474     if (index>size)
475     {
476         /* this is an impossible-to-reach test, but if the padding
477          * issue is ever understood, this may become more useful */
478         ERR("loaded corrupt structure! (used %u expected %u)\n", index, size);
479         status=FALSE;
480     }
481
482     return status;
483 }
484
485 /* perform sanity checks */
486 static
487 BOOL valid_protect_data(const 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     CryptMemFree(pInfo->info0.pbData);
541     CryptMemFree(pInfo->info1.pbData);
542     CryptMemFree(pInfo->szDataDescr);
543     CryptMemFree(pInfo->data0.pbData);
544     CryptMemFree(pInfo->salt.pbData);
545     CryptMemFree(pInfo->cipher.pbData);
546     CryptMemFree(pInfo->fingerprint.pbData);
547 }
548
549 /* copies a string into a data blob */
550 static
551 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
552 {
553     if (!str || !blob) return NULL;
554
555     blob->cbData=strlen(str)+1;
556     if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
557     {
558         blob->cbData=0;
559     }
560     else {
561         strcpy((LPSTR)blob->pbData, str);
562     }
563
564     return blob->pbData;
565 }
566
567 /*
568  * Populates everything except "cipher" and "fingerprint".
569  */
570 static
571 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
572                        HCRYPTPROV hProv)
573 {
574     DWORD dwStrLen;
575
576     TRACE("called\n");
577
578     if (!pInfo) return FALSE;
579
580     dwStrLen=lstrlenW(szDataDescr);
581
582     memset(pInfo,0,sizeof(*pInfo));
583
584     pInfo->count0=0x0001;
585
586     convert_str_to_blob(crypt_magic_str, &pInfo->info0);
587
588     pInfo->count1=0x0001;
589
590     convert_str_to_blob(crypt_magic_str, &pInfo->info1);
591
592     pInfo->null0=0x0000;
593
594     if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
595     {
596         memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
597     }
598
599     pInfo->cipher_alg=CRYPT32_PROTECTDATA_KEY_CALG;
600     pInfo->cipher_key_len=CRYPT32_PROTECTDATA_KEY_LEN;
601
602     convert_str_to_blob(crypt_magic_str, &pInfo->data0);
603
604     pInfo->null1=0x0000;
605     pInfo->hash_alg=CRYPT32_PROTECTDATA_HASH_CALG;
606     pInfo->hash_len=CRYPT32_PROTECTDATA_HASH_LEN;
607
608     /* allocate memory to hold a salt */
609     if ((pInfo->salt.pbData=CryptMemAlloc(CRYPT32_PROTECTDATA_SALT_LEN)))
610     {
611         /* generate random salt */
612         if (!CryptGenRandom(hProv, CRYPT32_PROTECTDATA_SALT_LEN, pInfo->salt.pbData))
613         {
614             ERR("CryptGenRandom\n");
615             free_protect_data(pInfo);
616             return FALSE;
617         }
618         pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
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, const 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, DWORD key_len, const DATA_BLOB *salt,
706                          const 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_INSUFFICIENT_BUFFER && 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,key_len << 16 | CRYPT_EXPORTABLE,phKey))
755     {
756         ERR("CryptDeriveKey\n");
757         rc = FALSE;
758     }
759
760     /* clean up */
761     CryptDestroyHash(hSaltHash);
762     CryptMemFree(szUsername);
763
764     return rc;
765 }
766
767 /* debugging tool to print the structures of a ProtectData call */
768 static void
769 report(const DATA_BLOB* pDataIn, const 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", pPromptStruct->cbSize);
776         TRACE("  dwPromptFlags: 0x%x\n", 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", 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     static const WCHAR empty_str[1];
830     BOOL rc = FALSE;
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 = empty_str;
856
857     /* get crypt context */
858     if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,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.cipher_key_len,&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", 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", 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     if (!pDataIn->cbData)
1018     {
1019         SetLastError(ERROR_INVALID_DATA);
1020         goto finished;
1021     }
1022
1023     /* debug: show our arguments */
1024     report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1025     TRACE("\tppszDataDescr: %p\n", ppszDataDescr);
1026
1027     /* take apart the opaque blob */
1028     if (!unserialize(pDataIn, &protect_data))
1029     {
1030         SetLastError(ERROR_INVALID_DATA);
1031         FIXME("%s\n",announce_bad_opaque_data);
1032         goto finished;
1033     }
1034
1035     /* perform basic validation on the resulting structure */
1036     if (!valid_protect_data(&protect_data))
1037     {
1038         SetLastError(ERROR_INVALID_DATA);
1039         FIXME("%s\n",announce_bad_opaque_data);
1040         goto free_protect_data;
1041     }
1042
1043     /* get a crypt context */
1044     if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1045     {
1046         ERR("CryptAcquireContextW failed\n");
1047         goto free_protect_data;
1048     }
1049
1050     /* load key */
1051     if (!load_encryption_key(hProv,protect_data.cipher_key_len,&protect_data.salt,pOptionalEntropy,&hKey))
1052     {
1053         goto free_context;
1054     }
1055
1056     /* create a hash for the decryption validation */
1057     if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1058     {
1059         ERR("CryptCreateHash\n");
1060         goto free_key;
1061     }
1062
1063     /* prepare for plaintext */
1064     pDataOut->cbData=protect_data.cipher.cbData;
1065     if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1066     {
1067         ERR("CryptMemAlloc\n");
1068         goto free_hash;
1069     }
1070     memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1071
1072     /* decrypt! */
1073     if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
1074                       &pDataOut->cbData) ||
1075         /* check the hash fingerprint */
1076         pDataOut->cbData > protect_data.cipher.cbData ||
1077         !hash_matches_blob(hHash, &protect_data.fingerprint))
1078     {
1079         SetLastError(ERROR_INVALID_DATA);
1080
1081         LocalFree( pDataOut->pbData );
1082         pDataOut->pbData = NULL;
1083         pDataOut->cbData = 0;
1084
1085         goto free_hash;
1086     }
1087
1088     /* Copy out the description */
1089     dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1090     if (ppszDataDescr)
1091     {
1092         if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1093         {
1094             ERR("LocalAlloc (ppszDataDescr)\n");
1095             goto free_hash;
1096         }
1097         else {
1098             memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1099         }
1100     }
1101
1102     /* success! */
1103     rc = TRUE;
1104
1105 free_hash:
1106     CryptDestroyHash(hHash);
1107 free_key:
1108     CryptDestroyKey(hKey);
1109 free_context:
1110     CryptReleaseContext(hProv,0);
1111 free_protect_data:
1112     free_protect_data(&protect_data);
1113 finished:
1114     /* If some error occurred, and no error code was set, force one. */
1115     if (!rc && GetLastError()==ERROR_SUCCESS)
1116     {
1117         SetLastError(ERROR_INVALID_DATA);
1118     }
1119
1120     if (rc) {
1121         SetLastError(ERROR_SUCCESS);
1122
1123         if (ppszDataDescr)
1124         {
1125             TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1126         }
1127         TRACE_DATA_BLOB(pDataOut);
1128     }
1129
1130     TRACE("returning %s\n", rc ? "ok" : "FAIL");
1131
1132     return rc;
1133 }