Fix some DPA functions so they pass the new tests.
[wine/multimedia.git] / dlls / crypt32 / protectdata.c
blobf11f978bf720b90856e083d66363d38597caa625
1 /*
2 * Copyright 2005 Kees Cook <kees@outflux.net>
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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.
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.
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <stdlib.h>
42 #include "windef.h"
43 #include "winbase.h"
44 #include "wincrypt.h"
45 #include "winreg.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
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
55 #define CRYPT32_PROTECTDATA_SECRET "I'm hunting wabbits"
58 * The data format returned by the real Windows CryptProtectData seems
59 * to be something like this:
61 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1)
62 BYTE info0_0[16]; - unknown information
63 ...
64 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1)
65 BYTE info1_0[16]; - unknown information
66 ...
67 DWORD null0; - NULL "end of records"?
68 DWORD str_len; - length of WCHAR string including term
69 WCHAR str[str_len]; - The "dataDescription" value
70 DWORD unknown0; - unknown value (seems large, but only WORD large)
71 DWORD unknown1; - unknown value (seems small, less than a BYTE)
72 DWORD data_len; - length of data (was 16 in samples)
73 BYTE data[data_len]; - unknown data (fingerprint?)
74 DWORD null1; - NULL ?
75 DWORD unknown2; - unknown value (seems large, but only WORD large)
76 DWORD unknown3; - unknown value (seems small, less than a BYTE)
77 DWORD salt_len; - length of salt(?) data
78 BYTE salt[salt_len]; - salt(?) for symmetric encryption
79 DWORD cipher_len; - length of cipher(?) data - was close to plain len
80 BYTE cipher[cipher_len]; - cipher text?
81 DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1
82 BYTE crc[crc_len]; - fingerprint of record?
84 * The data structures used in Wine are modelled after this guess.
87 struct protect_data_t
89 DWORD count0;
90 DATA_BLOB info0; /* using this to hold crypt_magic_str */
91 DWORD count1;
92 DATA_BLOB info1;
93 DWORD null0;
94 WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */
95 DWORD unknown0; /* perhaps the HASH alg const should go here? */
96 DWORD unknown1;
97 DATA_BLOB data0;
98 DWORD null1;
99 DWORD unknown2; /* perhaps the KEY alg const should go here? */
100 DWORD unknown3;
101 DATA_BLOB salt;
102 DATA_BLOB cipher;
103 DATA_BLOB fingerprint;
106 /* this is used to check if an incoming structure was built by Wine */
107 static const char * crypt_magic_str = "Wine Crypt32 ok";
109 /* debugging tool to print strings of hex chars */
110 static const char *
111 hex_str(unsigned char *p, int n)
113 const char * ptr;
114 char report[80];
115 int r=-1;
116 report[0]='\0';
117 ptr = wine_dbg_sprintf("%s","");
118 while (--n >= 0)
120 if (r++ % 20 == 19)
122 ptr = wine_dbg_sprintf("%s%s",ptr,report);
123 report[0]='\0';
125 sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
127 return wine_dbg_sprintf("%s%s",ptr,report);
130 #define TRACE_DATA_BLOB(blob) do { \
131 TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
132 TRACE("%s pbData @ 0x%x:%s\n", #blob ,(unsigned int)((blob)->pbData), \
133 hex_str((blob)->pbData, (blob)->cbData)); \
134 } while (0)
136 static
137 void serialize_dword(DWORD value,BYTE ** ptr)
139 /*TRACE("called\n");*/
141 memcpy(*ptr,&value,sizeof(DWORD));
142 *ptr+=sizeof(DWORD);
145 static
146 void serialize_string(BYTE * str,BYTE ** ptr,DWORD len, DWORD width,
147 BOOL prepend_len)
149 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
151 if (prepend_len)
153 serialize_dword(len,ptr);
155 memcpy(*ptr,str,len*width);
156 *ptr+=len*width;
159 static
160 BOOL unserialize_dword(BYTE * ptr, DWORD *index, DWORD size, DWORD * value)
162 /*TRACE("called\n");*/
164 if (!ptr || !index || !value) return FALSE;
166 if (*index+sizeof(DWORD)>size)
168 return FALSE;
171 memcpy(value,&(ptr[*index]),sizeof(DWORD));
172 *index+=sizeof(DWORD);
174 return TRUE;
177 static
178 BOOL unserialize_string(BYTE * ptr, DWORD *index, DWORD size,
179 DWORD len, DWORD width, BOOL inline_len,
180 BYTE ** data, DWORD * stored)
182 /*TRACE("called\n");*/
184 if (!ptr || !data) return FALSE;
186 if (inline_len) {
187 if (!unserialize_dword(ptr,index,size,&len))
188 return FALSE;
191 if (*index+len*width>size)
193 return FALSE;
196 if (!(*data = HeapAlloc( GetProcessHeap(), 0, len*width)))
198 return FALSE;
201 memcpy(*data,&(ptr[*index]),len*width);
202 if (stored)
204 *stored = len;
206 *index+=len*width;
208 return TRUE;
211 static
212 BOOL serialize(struct protect_data_t * pInfo, DATA_BLOB * pSerial)
214 BYTE * ptr;
215 DWORD dwStrLen;
216 DWORD dwStruct;
218 TRACE("called\n");
220 if (!pInfo || !pInfo->szDataDescr || !pSerial ||
221 !pInfo->info0.pbData || !pInfo->info1.pbData ||
222 !pInfo->data0.pbData || !pInfo->salt.pbData ||
223 !pInfo->cipher.pbData || !pInfo->fingerprint.pbData)
225 return FALSE;
228 if (pInfo->info0.cbData!=16)
230 ERR("protect_data_t info0 not 16 bytes long\n");
233 if (pInfo->info1.cbData!=16)
235 ERR("protect_data_t info1 not 16 bytes long\n");
238 dwStrLen=lstrlenW(pInfo->szDataDescr);
240 pSerial->cbData=0;
241 pSerial->cbData+=sizeof(DWORD)*8; /* 8 raw DWORDs */
242 pSerial->cbData+=sizeof(DWORD)*4; /* 4 BLOBs with size */
243 pSerial->cbData+=pInfo->info0.cbData;
244 pSerial->cbData+=pInfo->info1.cbData;
245 pSerial->cbData+=(dwStrLen+1)*sizeof(WCHAR) + 4; /* str, null, size */
246 pSerial->cbData+=pInfo->data0.cbData;
247 pSerial->cbData+=pInfo->salt.cbData;
248 pSerial->cbData+=pInfo->cipher.cbData;
249 pSerial->cbData+=pInfo->fingerprint.cbData;
251 /* save the actual structure size */
252 dwStruct = pSerial->cbData;
253 /* There may be a 256 byte minimum, but I can't prove it. */
254 /*if (pSerial->cbData<256) pSerial->cbData=256;*/
256 pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
257 if (!pSerial->pbData) return FALSE;
259 ptr=pSerial->pbData;
261 /* count0 */
262 serialize_dword(pInfo->count0,&ptr);
263 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
265 /* info0 */
266 serialize_string(pInfo->info0.pbData,&ptr,
267 pInfo->info0.cbData,sizeof(BYTE),FALSE);
268 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
270 /* count1 */
271 serialize_dword(pInfo->count1,&ptr);
272 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
274 /* info1 */
275 serialize_string(pInfo->info1.pbData,&ptr,
276 pInfo->info1.cbData,sizeof(BYTE),FALSE);
277 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
279 /* null0 */
280 serialize_dword(pInfo->null0,&ptr);
281 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
283 /* szDataDescr */
284 serialize_string((BYTE*)pInfo->szDataDescr,&ptr,
285 (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE);
286 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
288 /* unknown0 */
289 serialize_dword(pInfo->unknown0,&ptr);
290 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
291 /* unknown1 */
292 serialize_dword(pInfo->unknown1,&ptr);
293 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
295 /* data0 */
296 serialize_string(pInfo->data0.pbData,&ptr,
297 pInfo->data0.cbData,sizeof(BYTE),TRUE);
298 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
300 /* null1 */
301 serialize_dword(pInfo->null1,&ptr);
302 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
304 /* unknown2 */
305 serialize_dword(pInfo->unknown2,&ptr);
306 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
307 /* unknown3 */
308 serialize_dword(pInfo->unknown3,&ptr);
309 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
311 /* salt */
312 serialize_string(pInfo->salt.pbData,&ptr,
313 pInfo->salt.cbData,sizeof(BYTE),TRUE);
314 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
316 /* cipher */
317 serialize_string(pInfo->cipher.pbData,&ptr,
318 pInfo->cipher.cbData,sizeof(BYTE),TRUE);
319 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
321 /* fingerprint */
322 serialize_string(pInfo->fingerprint.pbData,&ptr,
323 pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
324 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
326 if (ptr - pSerial->pbData != dwStruct)
328 ERR("struct size changed!? %u != expected %u\n",
329 ptr - pSerial->pbData, (unsigned int)dwStruct);
330 LocalFree(pSerial->pbData);
331 pSerial->pbData=NULL;
332 pSerial->cbData=0;
333 return FALSE;
336 return TRUE;
339 static
340 BOOL unserialize(DATA_BLOB * pSerial, struct protect_data_t * pInfo)
342 BYTE * ptr;
343 DWORD index;
344 DWORD size;
345 BOOL status=TRUE;
347 TRACE("called\n");
349 if (!pInfo || !pSerial || !pSerial->pbData)
350 return FALSE;
352 index=0;
353 ptr=pSerial->pbData;
354 size=pSerial->cbData;
356 /* count0 */
357 if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
359 ERR("reading count0 failed!\n");
360 return FALSE;
363 /* info0 */
364 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
365 &pInfo->info0.pbData, &pInfo->info0.cbData))
367 ERR("reading info0 failed!\n");
368 return FALSE;
371 /* count1 */
372 if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
374 ERR("reading count1 failed!\n");
375 return FALSE;
378 /* info1 */
379 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
380 &pInfo->info1.pbData, &pInfo->info1.cbData))
382 ERR("reading info1 failed!\n");
383 return FALSE;
386 /* null0 */
387 if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
389 ERR("reading null0 failed!\n");
390 return FALSE;
393 /* szDataDescr */
394 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
395 (BYTE**)&pInfo->szDataDescr, NULL))
397 ERR("reading szDataDescr failed!\n");
398 return FALSE;
401 /* unknown0 */
402 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0))
404 ERR("reading unknown0 failed!\n");
405 return FALSE;
408 /* unknown1 */
409 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1))
411 ERR("reading unknown1 failed!\n");
412 return FALSE;
415 /* data0 */
416 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
417 &pInfo->data0.pbData, &pInfo->data0.cbData))
419 ERR("reading data0 failed!\n");
420 return FALSE;
423 /* null1 */
424 if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
426 ERR("reading null1 failed!\n");
427 return FALSE;
430 /* unknown2 */
431 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2))
433 ERR("reading unknown2 failed!\n");
434 return FALSE;
437 /* unknown3 */
438 if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3))
440 ERR("reading unknown3 failed!\n");
441 return FALSE;
444 /* salt */
445 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
446 &pInfo->salt.pbData, &pInfo->salt.cbData))
448 ERR("reading salt failed!\n");
449 return FALSE;
452 /* cipher */
453 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
454 &pInfo->cipher.pbData, &pInfo->cipher.cbData))
456 ERR("reading cipher failed!\n");
457 return FALSE;
460 /* fingerprint */
461 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
462 &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
464 ERR("reading fingerprint failed!\n");
465 return FALSE;
468 /* allow structure size to be too big (since some applications
469 * will pad this up to 256 bytes, it seems) */
470 if (index>size)
472 /* this is an impossible-to-reach test, but if the padding
473 * issue is ever understood, this may become more useful */
474 ERR("loaded corrupt structure! (used %u expected %u)\n",
475 (unsigned int)index, (unsigned int)size);
476 status=FALSE;
479 return status;
482 /* perform sanity checks */
483 static
484 BOOL valid_protect_data(struct protect_data_t * pInfo)
486 BOOL status=TRUE;
488 TRACE("called\n");
490 if (pInfo->count0 != 0x0001)
492 ERR("count0 != 0x0001 !\n");
493 status=FALSE;
495 if (pInfo->count1 != 0x0001)
497 ERR("count0 != 0x0001 !\n");
498 status=FALSE;
500 if (pInfo->null0 != 0x0000)
502 ERR("null0 != 0x0000 !\n");
503 status=FALSE;
505 if (pInfo->null1 != 0x0000)
507 ERR("null1 != 0x0000 !\n");
508 status=FALSE;
510 /* since we have no idea what info0 is used for, and it seems
511 * rather constant, we can test for a Wine-specific magic string
512 * there to be reasonably sure we're using data created by the Wine
513 * implementation of CryptProtectData.
515 if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
516 strcmp(pInfo->info0.pbData,crypt_magic_str) != 0)
518 ERR("info0 magic value not matched !\n");
519 status=FALSE;
522 if (!status)
524 ERR("unrecognized CryptProtectData block\n");
527 return status;
530 static
531 void free_protect_data(struct protect_data_t * pInfo)
533 TRACE("called\n");
535 if (!pInfo) return;
537 if (pInfo->info0.pbData)
538 HeapFree( GetProcessHeap(), 0, pInfo->info0.pbData);
539 if (pInfo->info1.pbData)
540 HeapFree( GetProcessHeap(), 0, pInfo->info1.pbData);
541 if (pInfo->szDataDescr)
542 HeapFree( GetProcessHeap(), 0, pInfo->szDataDescr);
543 if (pInfo->data0.pbData)
544 HeapFree( GetProcessHeap(), 0, pInfo->data0.pbData);
545 if (pInfo->salt.pbData)
546 HeapFree( GetProcessHeap(), 0, pInfo->salt.pbData);
547 if (pInfo->cipher.pbData)
548 HeapFree( GetProcessHeap(), 0, pInfo->cipher.pbData);
549 if (pInfo->fingerprint.pbData)
550 HeapFree( GetProcessHeap(), 0, pInfo->fingerprint.pbData);
553 /* copies a string into a data blob */
554 static
555 BYTE * convert_str_to_blob(char* str, DATA_BLOB* blob)
557 if (!str || !blob) return NULL;
559 blob->cbData=strlen(str)+1;
560 if (!(blob->pbData=HeapAlloc(GetProcessHeap(),0,blob->cbData)))
562 blob->cbData=0;
564 else {
565 strcpy(blob->pbData, str);
568 return blob->pbData;
572 * Populates everything except "cipher" and "fingerprint".
574 static
575 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
576 HCRYPTPROV hProv)
578 DWORD dwStrLen;
580 TRACE("called\n");
582 if (!pInfo) return FALSE;
584 dwStrLen=lstrlenW(szDataDescr);
586 memset(pInfo,0,sizeof(*pInfo));
588 pInfo->count0=0x0001;
590 convert_str_to_blob((char*)crypt_magic_str,&pInfo->info0);
592 pInfo->count1=0x0001;
594 convert_str_to_blob((char*)crypt_magic_str,&pInfo->info1);
596 pInfo->null0=0x0000;
598 if ((pInfo->szDataDescr=HeapAlloc( GetProcessHeap(), 0, (dwStrLen+1)*sizeof(WCHAR))))
600 memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
603 pInfo->unknown0=0x0000;
604 pInfo->unknown1=0x0000;
606 convert_str_to_blob((char*)crypt_magic_str,&pInfo->data0);
608 pInfo->null1=0x0000;
609 pInfo->unknown2=0x0000;
610 pInfo->unknown3=0x0000;
612 /* allocate memory to hold a salt */
613 pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
614 if ((pInfo->salt.pbData=HeapAlloc( GetProcessHeap(),0,pInfo->salt.cbData)))
616 /* generate random salt */
617 if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
619 ERR("CryptGenRandom\n");
620 free_protect_data(pInfo);
621 return FALSE;
625 /* debug: show our salt */
626 TRACE_DATA_BLOB(&pInfo->salt);
628 pInfo->cipher.cbData=0;
629 pInfo->cipher.pbData=NULL;
631 pInfo->fingerprint.cbData=0;
632 pInfo->fingerprint.pbData=NULL;
634 /* check all the allocations at once */
635 if (!pInfo->info0.pbData ||
636 !pInfo->info1.pbData ||
637 !pInfo->szDataDescr ||
638 !pInfo->data0.pbData ||
639 !pInfo->salt.pbData
642 ERR("could not allocate protect_data structures\n");
643 free_protect_data(pInfo);
644 return FALSE;
647 return TRUE;
650 static
651 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
653 DWORD dwSize;
655 TRACE("called\n");
657 if (!blob) return FALSE;
659 dwSize=sizeof(DWORD);
660 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
661 &dwSize, 0))
663 ERR("failed to get hash size\n");
664 return FALSE;
667 if (!(blob->pbData=HeapAlloc( GetProcessHeap(), 0, blob->cbData)))
669 ERR("failed to allocate blob memory\n");
670 return FALSE;
673 dwSize=blob->cbData;
674 if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
676 ERR("failed to get hash value\n");
677 HeapFree( GetProcessHeap(), 0, blob->pbData);
678 blob->pbData=NULL;
679 blob->cbData=0;
680 return FALSE;
683 return TRUE;
686 /* test that a given hash matches an exported-to-blob hash value */
687 static
688 BOOL hash_matches_blob(HCRYPTHASH hHash, DATA_BLOB * two)
690 BOOL rc = FALSE;
691 DATA_BLOB one;
693 if (!two || !two->pbData) return FALSE;
695 if (!convert_hash_to_blob(hHash,&one)) {
696 return FALSE;
699 if ( one.cbData == two->cbData &&
700 memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
702 rc = TRUE;
705 HeapFree( GetProcessHeap(), 0, one.pbData );
706 return rc;
709 /* create an encryption key from a given salt and optional entropy */
710 static
711 BOOL load_encryption_key(HCRYPTPROV hProv, DATA_BLOB * salt,
712 DATA_BLOB * pOptionalEntropy, HCRYPTKEY * phKey)
714 BOOL rc = TRUE;
715 HCRYPTHASH hSaltHash;
716 char * szUsername = NULL;
717 DWORD dwUsernameLen;
718 DWORD dwError;
720 /* create hash for salt */
721 if (!salt || !phKey ||
722 !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
724 ERR("CryptCreateHash\n");
725 return FALSE;
728 /* This should be the "logon credentials" instead of username */
729 dwError=GetLastError();
730 dwUsernameLen = 0;
731 if (!GetUserNameA(NULL,&dwUsernameLen) &&
732 GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
733 (szUsername = HeapAlloc( GetProcessHeap(), 0, dwUsernameLen)))
735 szUsername[0]='\0';
736 GetUserNameA( szUsername, &dwUsernameLen );
738 SetLastError(dwError);
740 /* salt the hash with:
741 * - the user id
742 * - an "internal secret"
743 * - randomness (from the salt)
744 * - user-supplied entropy
746 if ((szUsername && !CryptHashData(hSaltHash,szUsername,dwUsernameLen,0)) ||
747 !CryptHashData(hSaltHash,CRYPT32_PROTECTDATA_SECRET,
748 strlen(CRYPT32_PROTECTDATA_SECRET),0) ||
749 !CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
750 (pOptionalEntropy && !CryptHashData(hSaltHash,
751 pOptionalEntropy->pbData,
752 pOptionalEntropy->cbData,0)))
754 ERR("CryptHashData\n");
755 rc = FALSE;
758 /* produce a symmetric key */
759 if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
760 hSaltHash,CRYPT_EXPORTABLE,phKey))
762 ERR("CryptDeriveKey\n");
763 rc = FALSE;
766 /* clean up */
767 CryptDestroyHash(hSaltHash);
768 if (szUsername) HeapFree( GetProcessHeap(), 0, szUsername );
770 return rc;
773 /* debugging tool to print the structures of a ProtectData call */
774 static void
775 report(DATA_BLOB* pDataIn, DATA_BLOB* pOptionalEntropy,
776 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags)
778 TRACE("pPromptStruct: 0x%x\n",(unsigned int)pPromptStruct);
779 if (pPromptStruct)
781 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize);
782 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags);
783 TRACE(" hwndApp: 0x%x\n",(unsigned int)pPromptStruct->hwndApp);
784 TRACE(" szPrompt: 0x%x %s\n",
785 (unsigned int)pPromptStruct->szPrompt,
786 pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
787 : "");
789 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags);
790 TRACE_DATA_BLOB(pDataIn);
791 if (pOptionalEntropy)
793 TRACE_DATA_BLOB(pOptionalEntropy);
794 TRACE(" %s\n",debugstr_an(pOptionalEntropy->pbData,pOptionalEntropy->cbData));
800 /***************************************************************************
801 * CryptProtectData [CRYPT32.@]
803 * Generate Cipher data from given Plain and Entropy data.
805 * PARAMS
806 * pDataIn [I] Plain data to be enciphered
807 * szDataDescr [I] Optional Unicode string describing the Plain data
808 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
809 * pvReserved [I] Reserved, must be NULL
810 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
811 * dwFlags [I] Flags describing options to the ciphering
812 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
814 * RETURNS
815 * TRUE If a Cipher was generated.
816 * FALSE If something failed and no Cipher is available.
818 * FIXME
819 * The true Windows encryption and keying mechanisms are unknown.
821 * dwFlags and pPromptStruct are currently ignored.
823 * NOTES
824 * Memory allocated in pDataOut must be freed with LocalFree.
827 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
828 LPCWSTR szDataDescr,
829 DATA_BLOB* pOptionalEntropy,
830 PVOID pvReserved,
831 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
832 DWORD dwFlags,
833 DATA_BLOB* pDataOut)
835 BOOL rc = FALSE;
837 HCRYPTPROV hProv;
838 struct protect_data_t protect_data;
839 HCRYPTHASH hHash;
840 HCRYPTKEY hKey;
841 DWORD dwLength;
843 TRACE("called\n");
845 SetLastError(ERROR_SUCCESS);
847 if (!pDataIn || !pDataOut)
849 SetLastError(ERROR_INVALID_PARAMETER);
850 goto finished;
853 /* debug: show our arguments */
854 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
855 TRACE("\tszDataDescr: 0x%x %s\n",(unsigned int)szDataDescr,
856 szDataDescr ? debugstr_w(szDataDescr) : "");
858 /* Windows appears to create an empty szDataDescr instead of maintaining
859 * a NULL */
860 if (!szDataDescr)
861 szDataDescr=(WCHAR[]){'\0'};
863 /* get crypt context */
864 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
866 ERR("CryptAcquireContextW failed\n");
867 goto finished;
870 /* populate our structure */
871 if (!fill_protect_data(&protect_data,szDataDescr,hProv))
873 ERR("fill_protect_data\n");
874 goto free_context;
877 /* load key */
878 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
880 goto free_protect_data;
883 /* create a hash for the encryption validation */
884 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
886 ERR("CryptCreateHash\n");
887 goto free_key;
890 /* calculate storage required */
891 dwLength=pDataIn->cbData;
892 if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
893 GetLastError()!=ERROR_MORE_DATA)
895 ERR("CryptEncrypt\n");
896 goto free_hash;
898 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
900 /* copy plain text into cipher area for CryptEncrypt call */
901 protect_data.cipher.cbData=dwLength;
902 if (!(protect_data.cipher.pbData=HeapAlloc( GetProcessHeap(), 0,
903 protect_data.cipher.cbData)))
905 ERR("HeapAlloc\n");
906 goto free_hash;
908 memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
910 /* encrypt! */
911 dwLength=pDataIn->cbData;
912 if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
913 &dwLength, protect_data.cipher.cbData))
915 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
916 goto free_hash;
918 protect_data.cipher.cbData=dwLength;
920 /* debug: show the cipher */
921 TRACE_DATA_BLOB(&protect_data.cipher);
923 /* attach our fingerprint */
924 if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
926 ERR("convert_hash_to_blob\n");
927 goto free_hash;
930 /* serialize into an opaque blob */
931 if (!serialize(&protect_data, pDataOut))
933 ERR("serialize\n");
934 goto free_hash;
937 /* success! */
938 rc=TRUE;
940 free_hash:
941 CryptDestroyHash(hHash);
942 free_key:
943 CryptDestroyKey(hKey);
944 free_protect_data:
945 free_protect_data(&protect_data);
946 free_context:
947 CryptReleaseContext(hProv,0);
948 finished:
949 /* If some error occurred, and no error code was set, force one. */
950 if (!rc && GetLastError()==ERROR_SUCCESS)
952 SetLastError(ERROR_INVALID_DATA);
955 if (rc)
957 SetLastError(ERROR_SUCCESS);
959 TRACE_DATA_BLOB(pDataOut);
962 TRACE("returning %s\n", rc ? "ok" : "FAIL");
964 return rc;
968 /***************************************************************************
969 * CryptUnprotectData [CRYPT32.@]
971 * Generate Plain data and Description from given Cipher and Entropy data.
973 * PARAMS
974 * pDataIn [I] Cipher data to be decoded
975 * ppszDataDescr [O] Optional Unicode string describing the Plain data
976 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
977 * pvReserved [I] Reserved, must be NULL
978 * pPromptStruct [I] Structure describing if/how to prompt during decoding
979 * dwFlags [I] Flags describing options to the decoding
980 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
982 * RETURNS
983 * TRUE If a Plain was generated.
984 * FALSE If something failed and no Plain is available.
986 * FIXME
987 * The true Windows encryption and keying mechanisms are unknown.
989 * dwFlags and pPromptStruct are currently ignored.
991 * NOTES
992 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
993 * with LocalFree.
996 BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
997 LPWSTR * ppszDataDescr,
998 DATA_BLOB* pOptionalEntropy,
999 PVOID pvReserved,
1000 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
1001 DWORD dwFlags,
1002 DATA_BLOB* pDataOut)
1004 BOOL rc = FALSE;
1006 HCRYPTPROV hProv;
1007 struct protect_data_t protect_data;
1008 HCRYPTHASH hHash;
1009 HCRYPTKEY hKey;
1010 DWORD dwLength;
1012 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.";
1014 TRACE("called\n");
1016 SetLastError(ERROR_SUCCESS);
1018 if (!pDataIn || !pDataOut)
1020 SetLastError(ERROR_INVALID_PARAMETER);
1021 goto finished;
1024 /* debug: show our arguments */
1025 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1026 TRACE("\tppszDataDescr: 0x%x\n",(unsigned int)ppszDataDescr);
1028 /* take apart the opaque blob */
1029 if (!unserialize(pDataIn, &protect_data))
1031 SetLastError(ERROR_INVALID_DATA);
1032 FIXME("%s\n",announce_bad_opaque_data);
1033 goto finished;
1036 /* perform basic validation on the resulting structure */
1037 if (!valid_protect_data(&protect_data))
1039 SetLastError(ERROR_INVALID_DATA);
1040 FIXME("%s\n",announce_bad_opaque_data);
1041 goto free_protect_data;
1044 /* get a crypt context */
1045 if (!CryptAcquireContextW(&hProv,NULL,NULL,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1047 ERR("CryptAcquireContextW failed\n");
1048 goto free_protect_data;
1051 /* load key */
1052 if (!load_encryption_key(hProv,&protect_data.salt,pOptionalEntropy,&hKey))
1054 goto free_context;
1057 /* create a hash for the decryption validation */
1058 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1060 ERR("CryptCreateHash\n");
1061 goto free_key;
1064 /* prepare for plaintext */
1065 pDataOut->cbData=protect_data.cipher.cbData;
1066 if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1068 ERR("HeapAlloc\n");
1069 goto free_hash;
1071 memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1073 /* decrypt! */
1074 if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
1075 &pDataOut->cbData) ||
1076 /* check the hash fingerprint */
1077 pDataOut->cbData > protect_data.cipher.cbData ||
1078 !hash_matches_blob(hHash, &protect_data.fingerprint))
1080 SetLastError(ERROR_INVALID_DATA);
1082 LocalFree( pDataOut->pbData );
1083 pDataOut->pbData = NULL;
1084 pDataOut->cbData = 0;
1086 goto free_hash;
1089 /* Copy out the description */
1090 dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1091 if (ppszDataDescr)
1093 if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1095 ERR("LocalAlloc (ppszDataDescr)\n");
1096 goto free_hash;
1098 else {
1099 memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1103 /* success! */
1104 rc = TRUE;
1106 free_hash:
1107 CryptDestroyHash(hHash);
1108 free_key:
1109 CryptDestroyKey(hKey);
1110 free_context:
1111 CryptReleaseContext(hProv,0);
1112 free_protect_data:
1113 free_protect_data(&protect_data);
1114 finished:
1115 /* If some error occurred, and no error code was set, force one. */
1116 if (!rc && GetLastError()==ERROR_SUCCESS)
1118 SetLastError(ERROR_INVALID_DATA);
1121 if (rc) {
1122 SetLastError(ERROR_SUCCESS);
1124 if (ppszDataDescr)
1126 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1128 TRACE_DATA_BLOB(pDataOut);
1131 TRACE("returning %s\n", rc ? "ok" : "FAIL");
1133 return rc;