~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/protectdata.c

Version: ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  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!? %u != expected %u\n",
334             ptr - pSerial->pbData, dwStruct);
335         LocalFree(pSerial->pbData);
336         pSerial->pbData=NULL;
337         pSerial->cbData=0;
338         return FALSE;
339     }
340 
341     return TRUE;
342 }
343 
344 static
345 BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
346 {
347     BYTE * ptr;
348     DWORD index;
349     DWORD size;
350     BOOL status=TRUE;
351 
352     TRACE("called\n");
353 
354     if (!pInfo || !pSerial || !pSerial->pbData)
355         return FALSE;
356 
357     index=0;
358     ptr=pSerial->pbData;
359     size=pSerial->cbData;
360 
361     /* count0 */
362     if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
363     {
364         ERR("reading count0 failed!\n");
365         return FALSE;
366     }
367     
368     /* info0 */
369     if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
370                             &pInfo->info0.pbData, &pInfo->info0.cbData))
371     {
372         ERR("reading info0 failed!\n");
373         return FALSE;
374     }
375 
376     /* count1 */
377     if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
378     {
379         ERR("reading count1 failed!\n");
380         return FALSE;
381     }
382 
383     /* info1 */
384     if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
385                             &pInfo->info1.pbData, &pInfo->info1.cbData))
386     {
387         ERR("reading info1 failed!\n");
388         return FALSE;
389     }
390 
391     /* null0 */
392     if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
393     {
394         ERR("reading null0 failed!\n");
395         return FALSE;
396     }
397     
398     /* szDataDescr */
399     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
400                             (BYTE**)&pInfo->szDataDescr, NULL))
401     {
402         ERR("reading szDataDescr failed!\n");
403         return FALSE;
404     }
405 
406     /* cipher_alg */
407     if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_alg))
408     {
409         ERR("reading cipher_alg failed!\n");
410         return FALSE;
411     }
412     
413     /* cipher_key_len */
414     if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_key_len))
415     {
416         ERR("reading cipher_key_len failed!\n");
417         return FALSE;
418     }
419     
420     /* data0 */
421     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
422                             &pInfo->data0.pbData, &pInfo->data0.cbData))
423     {
424         ERR("reading data0 failed!\n");
425         return FALSE;
426     }
427 
428     /* null1 */
429     if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
430     {
431         ERR("reading null1 failed!\n");
432         return FALSE;
433     }
434     
435     /* hash_alg */
436     if (!unserialize_dword(ptr,&index,size,&pInfo->hash_alg))
437     {
438         ERR("reading hash_alg failed!\n");
439         return FALSE;
440     }
441     
442     /* hash_len */
443     if (!unserialize_dword(ptr,&index,size,&pInfo->hash_len))
444     {
445         ERR("reading hash_len failed!\n");
446         return FALSE;
447     }
448     
449     /* salt */
450     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
451                             &pInfo->salt.pbData, &pInfo->salt.cbData))
452     {
453         ERR("reading salt failed!\n");
454         return FALSE;
455     }
456 
457     /* cipher */
458     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
459                             &pInfo->cipher.pbData, &pInfo->cipher.cbData))
460     {
461         ERR("reading cipher failed!\n");
462         return FALSE;
463     }
464 
465     /* fingerprint */
466     if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
467                             &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
468     {
469         ERR("reading fingerprint failed!\n");
470         return FALSE;
471     }
472 
473     /* allow structure size to be too big (since some applications
474      * will pad this up to 256 bytes, it seems) */
475     if (index>size)
476     {
477         /* this is an impossible-to-reach test, but if the padding
478          * issue is ever understood, this may become more useful */
479         ERR("loaded corrupt structure! (used %u expected %u)\n", index, size);
480         status=FALSE;
481     }
482 
483     return status;
484 }
485 
486 /* perform sanity checks */
487 static
488 BOOL valid_protect_data(const struct protect_data_t *pInfo)
489 {
490     BOOL status=TRUE;
491 
492     TRACE("called\n");
493 
494     if (pInfo->count0 != 0x0001)
495     {
496         ERR("count0 != 0x0001 !\n");
497         status=FALSE;
498     }
499     if (pInfo->count1 != 0x0001)
500     {
501         ERR("count0 != 0x0001 !\n");
502         status=FALSE;
503     }
504     if (pInfo->null0 != 0x0000)
505     {
506         ERR("null0 != 0x0000 !\n");
507         status=FALSE;
508     }
509     if (pInfo->null1 != 0x0000)
510     {
511         ERR("null1 != 0x0000 !\n");
512         status=FALSE;
513     }
514     /* since we have no idea what info0 is used for, and it seems
515      * rather constant, we can test for a Wine-specific magic string
516      * there to be reasonably sure we're using data created by the Wine
517      * implementation of CryptProtectData.
518      */
519     if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
520         strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
521     {
522         ERR("info0 magic value not matched !\n");
523         status=FALSE;
524     }
525 
526     if (!status)
527     {
528         ERR("unrecognized CryptProtectData block\n");
529     }
530 
531     return status;
532 }
533 
534 static
535 void free_protect_data(struct protect_data_t * pInfo)
536 {
537     TRACE("called\n");
538 
539     if (!pInfo) return;
540 
541     CryptMemFree(pInfo->info0.pbData);
542     CryptMemFree(pInfo->info1.pbData);
543     CryptMemFree(pInfo->szDataDescr);
544     CryptMemFree(pInfo->data0.pbData);
545     CryptMemFree(pInfo->salt.pbData);
546     CryptMemFree(pInfo->cipher.pbData);
547     CryptMemFree(pInfo->fingerprint.pbData);
548 }
549 
550 /* copies a string into a data blob */
551 static
552 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
553 {
554     if (!str || !blob) return NULL;
555 
556     blob->cbData=strlen(str)+1;
557     if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
558     {
559         blob->cbData=0;
560     }
561     else {
562         strcpy((LPSTR)blob->pbData, str);
563     }
564 
565     return blob->pbData;
566 }
567 
568 /*
569  * Populates everything except "cipher" and "fingerprint".
570  */
571 static
572 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
573                        HCRYPTPROV hProv)
574 {
575     DWORD dwStrLen;
576 
577     TRACE("called\n");
578 
579     if (!pInfo) return FALSE;
580 
581     dwStrLen=lstrlenW(szDataDescr);
582 
583     memset(pInfo,0,sizeof(*pInfo));
584 
585     pInfo->count0=0x0001;
586 
587     convert_str_to_blob(crypt_magic_str, &pInfo->info0);
588 
589     pInfo->count1=0x0001;
590 
591     convert_str_to_blob(crypt_magic_str, &pInfo->info1);
592 
593     pInfo->null0=0x0000;
594 
595     if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
596     {
597         memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
598     }
599 
600     pInfo->cipher_alg=CRYPT32_PROTECTDATA_KEY_CALG;
601     pInfo->cipher_key_len=CRYPT32_PROTECTDATA_KEY_LEN;
602 
603     convert_str_to_blob(crypt_magic_str, &pInfo->data0);
604 
605     pInfo->null1=0x0000;
606     pInfo->hash_alg=CRYPT32_PROTECTDATA_HASH_CALG;
607     pInfo->hash_len=CRYPT32_PROTECTDATA_HASH_LEN;
608 
609     /* allocate memory to hold a salt */
610     pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
611     if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
612     {
613         /* generate random salt */
614         if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
615         {
616             ERR("CryptGenRandom\n");
617             free_protect_data(pInfo);
618             return FALSE;
619         }
620     }
621 
622     /* debug: show our salt */
623     TRACE_DATA_BLOB(&pInfo->salt);
624 
625     pInfo->cipher.cbData=0;
626     pInfo->cipher.pbData=NULL;
627 
628     pInfo->fingerprint.cbData=0;
629     pInfo->fingerprint.pbData=NULL;
630 
631     /* check all the allocations at once */
632     if (!pInfo->info0.pbData ||
633         !pInfo->info1.pbData ||
634         !pInfo->szDataDescr  ||
635         !pInfo->data0.pbData ||
636         !pInfo->salt.pbData
637         )
638     {
639         ERR("could not allocate protect_data structures\n");
640         free_protect_data(pInfo);
641         return FALSE;
642     }
643 
644     return TRUE;
645 }
646 
647 static
648 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
649 {
650     DWORD dwSize;
651 
652     TRACE("called\n");
653 
654     if (!blob) return FALSE;
655 
656     dwSize=sizeof(DWORD);
657     if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
658                            &dwSize, 0))
659     {
660         ERR("failed to get hash size\n");
661         return FALSE;
662     }
663 
664     if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
665     {
666         ERR("failed to allocate blob memory\n");
667         return FALSE;
668     }
669 
670     dwSize=blob->cbData;
671     if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
672     {
673         ERR("failed to get hash value\n");
674         CryptMemFree(blob->pbData);
675         blob->pbData=NULL;
676         blob->cbData=0;
677         return FALSE;
678     }
679 
680     return TRUE;
681 }
682 
683 /* test that a given hash matches an exported-to-blob hash value */
684 static
685 BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two)
686 {
687     BOOL rc = FALSE;
688     DATA_BLOB one;
689 
690     if (!two || !two->pbData) return FALSE;
691 
692     if (!convert_hash_to_blob(hHash,&one)) {
693         return FALSE;
694     }
695 
696     if ( one.cbData == two->cbData &&
697          memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
698     {
699         rc = TRUE;
700     }
701 
702     CryptMemFree(one.pbData);
703     return rc;
704 }
705 
706 /* create an encryption key from a given salt and optional entropy */
707 static
708 BOOL load_encryption_key(HCRYPTPROV hProv, DWORD key_len, const DATA_BLOB *salt,
709                          const DATA_BLOB *pOptionalEntropy, HCRYPTKEY *phKey)
710 {
711     BOOL rc = TRUE;
712     HCRYPTHASH hSaltHash;
713     char * szUsername = NULL;
714     DWORD dwUsernameLen;
715     DWORD dwError;
716 
717     /* create hash for salt */
718     if (!salt || !phKey ||
719         !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
720     {
721         ERR("CryptCreateHash\n");
722         return FALSE;
723     }
724 
725     /* This should be the "logon credentials" instead of username */
726     dwError=GetLastError();
727     dwUsernameLen = 0;
728     if (!GetUserNameA(NULL,&dwUsernameLen) &&
729         GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
730         (szUsername = CryptMemAlloc(dwUsernameLen)))
731     {
732         szUsername[0]='\0';
733         GetUserNameA( szUsername, &dwUsernameLen );
734     }
735     SetLastError(dwError);
736 
737     /* salt the hash with:
738      * - the user id
739      * - an "internal secret"
740      * - randomness (from the salt)
741      * - user-supplied entropy
742      */
743     if ((szUsername && !CryptHashData(hSaltHash,(LPBYTE)szUsername,dwUsernameLen,0)) ||
744         !CryptHashData(hSaltHash,crypt32_protectdata_secret,
745                                  sizeof(crypt32_protectdata_secret)-1,0) ||
746         !CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
747         (pOptionalEntropy && !CryptHashData(hSaltHash,
748                                             pOptionalEntropy->pbData,
749                                             pOptionalEntropy->cbData,0)))
750     {
751         ERR("CryptHashData\n");
752         rc = FALSE;
753     }
754 
755     /* produce a symmetric key */
756     if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
757                               hSaltHash,key_len << 16 | CRYPT_EXPORTABLE,phKey))
758     {
759         ERR("CryptDeriveKey\n");
760         rc = FALSE;
761     }
762 
763     /* clean up */
764     CryptDestroyHash(hSaltHash);
765     CryptMemFree(szUsername);
766 
767     return rc;
768 }
769 
770 /* debugging tool to print the structures of a ProtectData call */
771 static void
772 report(const DATA_BLOB* pDataIn, const DATA_BLOB* pOptionalEntropy,
773        CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags)
774 {
775     TRACE("pPromptStruct: %p\n", pPromptStruct);
776     if (pPromptStruct)
777     {
778         TRACE("  cbSize: 0x%x\n", pPromptStruct->cbSize);
779         TRACE("  dwPromptFlags: 0x%x\n", pPromptStruct->dwPromptFlags);
780         TRACE("  hwndApp: %p\n", pPromptStruct->hwndApp);
781         TRACE("  szPrompt: %p %s\n",
782               pPromptStruct->szPrompt,
783               pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
784               : "");
785     }
786     TRACE("dwFlags: 0x%04x\n", dwFlags);
787     TRACE_DATA_BLOB(pDataIn);
788     if (pOptionalEntropy)
789     {
790         TRACE_DATA_BLOB(pOptionalEntropy);
791         TRACE("  %s\n",debugstr_an((LPCSTR)pOptionalEntropy->pbData,pOptionalEntropy->cbData));
792     }
793 
794 }
795 
796 
797 /***************************************************************************
798  * CryptProtectData     [CRYPT32.@]
799  *
800  * Generate Cipher data from given Plain and Entropy data.
801  *
802  * PARAMS
803  *  pDataIn          [I] Plain data to be enciphered
804  *  szDataDescr      [I] Optional Unicode string describing the Plain data
805  *  pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
806  *  pvReserved       [I] Reserved, must be NULL
807  *  pPromptStruct    [I] Structure describing if/how to prompt during ciphering
808  *  dwFlags          [I] Flags describing options to the ciphering
809  *  pDataOut         [O] Resulting Cipher data, for calls to CryptUnprotectData
810  *
811  * RETURNS
812  *  TRUE  If a Cipher was generated.
813  *  FALSE If something failed and no Cipher is available.
814  *
815  * FIXME
816  *  The true Windows encryption and keying mechanisms are unknown.
817  *
818  *  dwFlags and pPromptStruct are currently ignored.
819  *
820  * NOTES
821  *  Memory allocated in pDataOut must be freed with LocalFree.
822  *
823  */
824 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
825                              LPCWSTR szDataDescr,
826                              DATA_BLOB* pOptionalEntropy,
827                              PVOID pvReserved,
828                              CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
829                              DWORD dwFlags,
830                              DATA_BLOB* pDataOut)
831 {
832     static const WCHAR empty_str[1];
833     BOOL rc = FALSE;
834     HCRYPTPROV hProv;
835     struct protect_data_t protect_data;
836     HCRYPTHASH hHash;
837     HCRYPTKEY hKey;
838     DWORD dwLength;
839 
840     TRACE("called\n");
841 
842     SetLastError(ERROR_SUCCESS);
843 
844     if (!pDataIn || !pDataOut)
845     {
846         SetLastError(ERROR_INVALID_PARAMETER);
847         goto finished;
848     }
849 
850     /* debug: show our arguments */
851     report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
852     TRACE("\tszDataDescr: %p %s\n", szDataDescr,
853           szDataDescr ? debugstr_w(szDataDescr) : "");
854 
855     /* Windows appears to create an empty szDataDescr instead of maintaining
856      * a NULL */
857     if (!szDataDescr)
858         szDataDescr = empty_str;
859 
860     /* get crypt context */
861     if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
862     {
863         ERR("CryptAcquireContextW failed\n");
864         goto finished;
865     }
866 
867     /* populate our structure */
868     if (!fill_protect_data(&protect_data,szDataDescr,hProv))
869     {
870         ERR("fill_protect_data\n");
871         goto free_context;
872     }
873 
874     /* load key */
875     if (!load_encryption_key(hProv,protect_data.cipher_key_len,&protect_data.salt,pOptionalEntropy,&hKey))
876     {
877         goto free_protect_data;
878     }
879 
880     /* create a hash for the encryption validation */
881     if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
882     {
883         ERR("CryptCreateHash\n");
884         goto free_key;
885     }
886 
887     /* calculate storage required */
888     dwLength=pDataIn->cbData;
889     if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
890         GetLastError()!=ERROR_MORE_DATA)
891     {
892         ERR("CryptEncrypt\n");
893         goto free_hash;
894     }
895     TRACE("required encrypted storage: %u\n", dwLength);
896 
897     /* copy plain text into cipher area for CryptEncrypt call */
898     protect_data.cipher.cbData=dwLength;
899     if (!(protect_data.cipher.pbData=CryptMemAlloc(
900                                                 protect_data.cipher.cbData)))
901     {
902         ERR("CryptMemAlloc\n");
903         goto free_hash;
904     }
905     memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
906 
907     /* encrypt! */
908     dwLength=pDataIn->cbData;
909     if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
910                       &dwLength, protect_data.cipher.cbData))
911     {
912         ERR("CryptEncrypt %u\n", GetLastError());
913         goto free_hash;
914     }
915     protect_data.cipher.cbData=dwLength;
916 
917     /* debug: show the cipher */
918     TRACE_DATA_BLOB(&protect_data.cipher);
919 
920     /* attach our fingerprint */
921     if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
922     {
923         ERR("convert_hash_to_blob\n");
924         goto free_hash;
925     }
926 
927     /* serialize into an opaque blob */
928     if (!serialize(&protect_data, pDataOut))
929     {
930         ERR("serialize\n");
931         goto free_hash;
932     }
933 
934     /* success! */
935     rc=TRUE;
936 
937 free_hash:
938     CryptDestroyHash(hHash);
939 free_key:
940     CryptDestroyKey(hKey);
941 free_protect_data:
942     free_protect_data(&protect_data);
943 free_context:
944     CryptReleaseContext(hProv,0);
945 finished:
946     /* If some error occurred, and no error code was set, force one. */
947     if (!rc && GetLastError()==ERROR_SUCCESS)
948     {
949         SetLastError(ERROR_INVALID_DATA);
950     }
951 
952     if (rc)
953     {
954         SetLastError(ERROR_SUCCESS);
955 
956         TRACE_DATA_BLOB(pDataOut);
957     }
958 
959     TRACE("returning %s\n", rc ? "ok" : "FAIL");
960 
961     return rc;
962 }
963 
964 
965 /***************************************************************************
966  * CryptUnprotectData   [CRYPT32.@]
967  *
968  * Generate Plain data and Description from given Cipher and Entropy data.
969  *
970  * PARAMS
971  *  pDataIn          [I] Cipher data to be decoded
972  *  ppszDataDescr    [O] Optional Unicode string describing the Plain data
973  *  pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
974  *  pvReserved       [I] Reserved, must be NULL
975  *  pPromptStruct    [I] Structure describing if/how to prompt during decoding
976  *  dwFlags          [I] Flags describing options to the decoding
977  *  pDataOut         [O] Resulting Plain data, from calls to CryptProtectData
978  *
979  * RETURNS
980  *  TRUE  If a Plain was generated.
981  *  FALSE If something failed and no Plain is available.
982  *
983  * FIXME
984  *  The true Windows encryption and keying mechanisms are unknown.
985  *
986  *  dwFlags and pPromptStruct are currently ignored.
987  *
988  * NOTES
989  *  Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
990  *  with LocalFree.
991  *
992  */