ReactOS  0.4.14-dev-614-gbfd8a84
protectdata.c
Go to the documentation of this file.
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 
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 
93 {
95  DATA_BLOB info0; /* using this to hold crypt_magic_str */
99  WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */
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
143 {
144  /*TRACE("called\n");*/
145 
146  memcpy(*ptr,&value,sizeof(DWORD));
147  *ptr+=sizeof(DWORD);
148 }
149 
150 static
152  BOOL prepend_len)
153 {
154  /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
155 
156  if (prepend_len)
157  {
159  }
160  memcpy(*ptr,str,len*width);
161  *ptr+=len*width;
162 }
163 
164 static
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
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) {
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 */
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 */
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 */
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 */
298  /*TRACE("used %u\n",ptr-pSerial->pbData);*/
299 
300  /* data0 */
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 */
318  pInfo->salt.cbData,sizeof(BYTE),TRUE);
319  /*TRACE("used %u\n",ptr-pSerial->pbData);*/
320 
321  /* cipher */
323  pInfo->cipher.cbData,sizeof(BYTE),TRUE);
324  /*TRACE("used %u\n",ptr-pSerial->pbData);*/
325 
326  /* fingerprint */
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 */
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
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);
547 }
548 
549 /* copies a string into a data blob */
550 static
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,
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 
587 
588  pInfo->count1=0x0001;
589 
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 
601 
603 
604  pInfo->null1=0x0000;
607 
608  /* allocate memory to hold a salt */
610  {
611  /* generate random salt */
613  {
614  ERR("CryptGenRandom\n");
615  free_protect_data(pInfo);
616  return FALSE;
617  }
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
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
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
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 ||
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)) ||
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 */
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  */
822  LPCWSTR szDataDescr,
823  DATA_BLOB* pOptionalEntropy,
825  CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
826  DWORD dwFlags,
827  DATA_BLOB* pDataOut)
828 {
829  static const WCHAR empty_str[1];
830  BOOL rc = FALSE;
832  struct protect_data_t protect_data;
834  HCRYPTKEY hKey;
835  DWORD dwLength;
836 
837  TRACE("called\n");
838 
840 
841  if (!pDataIn || !pDataOut)
842  {
844  goto finished;
845  }
846 
847  /* debug: show our arguments */
848  report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
849  TRACE("\tszDataDescr: %p %s\n", szDataDescr,
851 
852  /* Windows appears to create an empty szDataDescr instead of maintaining
853  * a NULL */
854  if (!szDataDescr)
856 
857  /* get crypt context */
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 */
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) ||
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:
936 free_key:
937  CryptDestroyKey(hKey);
939  free_protect_data(&protect_data);
940 free_context:
942 finished:
943  /* If some error occurred, and no error code was set, force one. */
944  if (!rc && GetLastError()==ERROR_SUCCESS)
945  {
947  }
948 
949  if (rc)
950  {
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  */
991  LPWSTR * ppszDataDescr,
992  DATA_BLOB* pOptionalEntropy,
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 
1011 
1012  if (!pDataIn || !pDataOut)
1013  {
1015  goto finished;
1016  }
1017  if (!pDataIn->cbData)
1018  {
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  {
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  {
1039  FIXME("%s\n",announce_bad_opaque_data);
1040  goto free_protect_data;
1041  }
1042 
1043  /* get a crypt context */
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 */
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  {
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:
1107 free_key:
1108  CryptDestroyKey(hKey);
1109 free_context:
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  {
1118  }
1119 
1120  if (rc) {
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 }
#define ERROR_INVALID_PARAMETER
Definition: compat.h:91
static BYTE * convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
Definition: protectdata.c:551
GLint GLint GLsizei width
Definition: gl.h:1546
static const char * hex_str(const unsigned char *p, int n)
Definition: protectdata.c:116
#define TRUE
Definition: types.h:120
WINE_DEFAULT_DEBUG_CHANNEL(crypt)
static const TCHAR empty_str[]
Definition: dialog.c:32
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
static BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB *blob)
Definition: protectdata.c:645
#define ERROR_SUCCESS
Definition: deptool.c:10
unsigned int ALG_ID
Definition: wincrypt.h:45
_In_ HCRYPTHASH hHash
Definition: wincrypt.h:4198
static void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width, BOOL prepend_len)
Definition: protectdata.c:151
#define CRYPT32_PROTECTDATA_PROV
Definition: protectdata.c:49
const WCHAR * LPCWSTR
Definition: xmlstorage.h:185
Definition: image.c:133
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
DATA_BLOB cipher
Definition: protectdata.c:107
static BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
Definition: protectdata.c:344
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
static const char crypt_magic_str[]
Definition: protectdata.c:112
#define CRYPT32_PROTECTDATA_KEY_CALG
Definition: protectdata.c:52
GLdouble n
Definition: glext.h:7729
static BOOL fill_protect_data(struct protect_data_t *pInfo, LPCWSTR szDataDescr, HCRYPTPROV hProv)
Definition: protectdata.c:571
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define CRYPT32_PROTECTDATA_KEY_LEN
Definition: protectdata.c:53
BOOL WINAPI CryptUnprotectData(DATA_BLOB *pDataIn, LPWSTR *ppszDataDescr, DATA_BLOB *pOptionalEntropy, PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, DWORD dwFlags, DATA_BLOB *pDataOut)
Definition: protectdata.c:990
char * LPSTR
Definition: xmlstorage.h:182
BOOL WINAPI CryptProtectData(DATA_BLOB *pDataIn, LPCWSTR szDataDescr, DATA_BLOB *pOptionalEntropy, PVOID pvReserved, CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, DWORD dwFlags, DATA_BLOB *pDataOut)
Definition: protectdata.c:821
#define lstrlenW
Definition: compat.h:415
static HCRYPTPROV hProv
Definition: rsaenh.c:32
WCHAR * szDataDescr
Definition: protectdata.c:99
#define HP_HASHSIZE
Definition: wincrypt.h:2184
BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer)
Definition: crypt.c:705
static double one
Definition: j0_y0.c:80
const char * wine_dbg_sprintf(const char *format,...)
Definition: compat.c:271
BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
Definition: crypt.c:358
#define sprintf(buf, format,...)
Definition: sprintf.c:55
LPVOID WINAPI CryptMemAlloc(ULONG cbSize)
Definition: main.c:131
unsigned char * LPBYTE
Definition: typedefs.h:52
DWORD cipher_key_len
Definition: protectdata.c:101
BOOL WINAPI CryptGetHashParam(HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags)
Definition: crypt.c:1615
unsigned int BOOL
Definition: ntddk_ex.h:94
static BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial)
Definition: protectdata.c:217
static double two
Definition: jn_yn.c:52
#define debugstr_w
Definition: kernel32.h:32
#define FIXME(fmt,...)
Definition: debug.h:110
static PVOID ptr
Definition: dispmode.c:27
const WCHAR * str
DATA_BLOB fingerprint
Definition: protectdata.c:108
smooth NULL
Definition: ftsmooth.c:416
static BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two)
Definition: protectdata.c:682
BOOL WINAPI CryptDestroyKey(HCRYPTKEY hKey)
Definition: crypt.c:935
BOOL WINAPI CryptDecrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen)
Definition: crypt.c:805
static void report(const DATA_BLOB *pDataIn, const DATA_BLOB *pOptionalEntropy, CRYPTPROTECT_PROMPTSTRUCT *pPromptStruct, DWORD dwFlags)
Definition: protectdata.c:769
static void serialize_dword(DWORD value, BYTE **ptr)
Definition: protectdata.c:142
static const BYTE crypt32_protectdata_secret[]
Definition: protectdata.c:56
DATA_BLOB info0
Definition: protectdata.c:95
GLuint index
Definition: glext.h:6031
const char * LPCSTR
Definition: xmlstorage.h:183
static BOOL unserialize_string(const BYTE *ptr, DWORD *index, DWORD size, DWORD len, DWORD width, BOOL inline_len, BYTE **data, DWORD *stored)
Definition: protectdata.c:183
DATA_BLOB salt
Definition: protectdata.c:106
DATA_BLOB info1
Definition: protectdata.c:97
BOOL WINAPI CryptEncrypt(HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen)
Definition: crypt.c:1098
#define TRACE(s)
Definition: solgame.cpp:4
GLsizeiptr size
Definition: glext.h:5919
BOOL WINAPI CryptDeriveKey(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey)
Definition: crypt.c:843
__wchar_t WCHAR
Definition: xmlstorage.h:180
static DWORD DWORD * dwLength
Definition: fusion.c:85
static LPCSTR DWORD void * pvReserved
Definition: str.c:196
#define WINAPI
Definition: msvc.h:6
#define CRYPT32_PROTECTDATA_HASH_CALG
Definition: protectdata.c:50
unsigned long DWORD
Definition: ntddk_ex.h:95
DATA_BLOB data0
Definition: protectdata.c:102
#define SetLastError(x)
Definition: compat.h:417
#define CRYPT32_PROTECTDATA_SALT_LEN
Definition: protectdata.c:54
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
BOOL WINAPI CryptDestroyHash(HCRYPTHASH hHash)
Definition: crypt.c:895
#define index(s, c)
Definition: various.h:29
BYTE * pbData
Definition: wincrypt.h:103
static __inline const char * debugstr_an(const char *s, int n)
Definition: compat.h:47
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
BOOL WINAPI GetUserNameA(LPSTR lpszName, LPDWORD lpSize)
Definition: misc.c:246
unsigned char BYTE
Definition: mem.h:68
BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash)
Definition: crypt.c:745
static BOOL load_encryption_key(HCRYPTPROV hProv, DWORD key_len, const DATA_BLOB *salt, const DATA_BLOB *pOptionalEntropy, HCRYPTKEY *phKey)
Definition: protectdata.c:705
#define ERROR_MORE_DATA
Definition: dderror.h:13
static BOOL valid_protect_data(const struct protect_data_t *pInfo)
Definition: protectdata.c:487
static const WCHAR MS_ENHANCED_PROV_W[]
Definition: wincrypt.h:1882
#define CRYPT_VERIFYCONTEXT
Definition: wincrypt.h:2069
#define ERROR_INVALID_DATA
Definition: winerror.h:116
ULONG_PTR HCRYPTHASH
Definition: wincrypt.h:50
#define ERR(fmt,...)
Definition: debug.h:109
static DATA_BLOB CRYPTPROTECT_PROMPTSTRUCT DWORD
Definition: protectdata.c:30
ULONG_PTR HCRYPTPROV
Definition: wincrypt.h:46
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
BOOL WINAPI CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags)
Definition: crypt.c:1776
static void free_protect_data(struct protect_data_t *pInfo)
Definition: protectdata.c:534
ULONG_PTR HCRYPTKEY
Definition: wincrypt.h:49
VOID WINAPI CryptMemFree(LPVOID pv)
Definition: main.c:141
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, ULONG_PTR dwFlags)
Definition: crypt.c:651
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define CRYPT_EXPORTABLE
Definition: wincrypt.h:2206
#define LPTR
Definition: winbase.h:362
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
static BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value)
Definition: protectdata.c:165
HLOCAL NTAPI LocalAlloc(UINT uFlags, SIZE_T dwBytes)
Definition: heapmem.c:1373
GLfloat GLfloat p
Definition: glext.h:8902
WCHAR * LPWSTR
Definition: xmlstorage.h:184
#define HP_HASHVAL
Definition: wincrypt.h:2183
#define CRYPT32_PROTECTDATA_HASH_LEN
Definition: protectdata.c:51
ALG_ID cipher_alg
Definition: protectdata.c:100
#define memset(x, y, z)
Definition: compat.h:39
static SERVICE_STATUS status
Definition: service.c:31
PSDBQUERYRESULT_VISTA PVOID DWORD * dwSize
Definition: env.c:54
#define TRACE_DATA_BLOB(blob)
Definition: protectdata.c:135
#define ERROR_INSUFFICIENT_BUFFER
Definition: dderror.h:10
Definition: ps.c:97