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