crypt32: Use 3DES to encrypt data.
[wine/gsoc_dplay.git] / dlls / crypt32 / protectdata.c
blobd5ec287c10cd87a02e291d68cf7fb0a7dcd89f8f
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "wine/debug.h"
47 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
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
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
62 * The data format returned by the real Windows CryptProtectData seems
63 * to be something like this:
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?
89 * The data structures used in Wine are modelled after this guess.
92 struct protect_data_t
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;
111 /* this is used to check if an incoming structure was built by Wine */
112 static const char crypt_magic_str[] = "Wine Crypt32 ok";
114 /* debugging tool to print strings of hex chars */
115 static const char *
116 hex_str(const unsigned char *p, int n)
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)
125 if (r++ % 20 == 19)
127 ptr = wine_dbg_sprintf("%s%s",ptr,report);
128 report[0]='\0';
130 sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++);
132 return wine_dbg_sprintf("%s%s",ptr,report);
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)
141 static
142 void serialize_dword(DWORD value,BYTE ** ptr)
144 /*TRACE("called\n");*/
146 memcpy(*ptr,&value,sizeof(DWORD));
147 *ptr+=sizeof(DWORD);
150 static
151 void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width,
152 BOOL prepend_len)
154 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
156 if (prepend_len)
158 serialize_dword(len,ptr);
160 memcpy(*ptr,str,len*width);
161 *ptr+=len*width;
164 static
165 BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value)
167 /*TRACE("called\n");*/
169 if (!ptr || !index || !value) return FALSE;
171 if (*index+sizeof(DWORD)>size)
173 return FALSE;
176 memcpy(value,&(ptr[*index]),sizeof(DWORD));
177 *index+=sizeof(DWORD);
179 return TRUE;
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)
187 /*TRACE("called\n");*/
189 if (!ptr || !data) return FALSE;
191 if (inline_len) {
192 if (!unserialize_dword(ptr,index,size,&len))
193 return FALSE;
196 if (*index+len*width>size)
198 return FALSE;
201 if (!(*data = CryptMemAlloc( len*width)))
203 return FALSE;
206 memcpy(*data,&(ptr[*index]),len*width);
207 if (stored)
209 *stored = len;
211 *index+=len*width;
213 return TRUE;
216 static
217 BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial)
219 BYTE * ptr;
220 DWORD dwStrLen;
221 DWORD dwStruct;
223 TRACE("called\n");
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)
230 return FALSE;
233 if (pInfo->info0.cbData!=16)
235 ERR("protect_data_t info0 not 16 bytes long\n");
238 if (pInfo->info1.cbData!=16)
240 ERR("protect_data_t info1 not 16 bytes long\n");
243 dwStrLen=lstrlenW(pInfo->szDataDescr);
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;
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;*/
261 pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData);
262 if (!pSerial->pbData) return FALSE;
264 ptr=pSerial->pbData;
266 /* count0 */
267 serialize_dword(pInfo->count0,&ptr);
268 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
270 /* info0 */
271 serialize_string(pInfo->info0.pbData,&ptr,
272 pInfo->info0.cbData,sizeof(BYTE),FALSE);
273 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
275 /* count1 */
276 serialize_dword(pInfo->count1,&ptr);
277 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
279 /* info1 */
280 serialize_string(pInfo->info1.pbData,&ptr,
281 pInfo->info1.cbData,sizeof(BYTE),FALSE);
282 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
284 /* null0 */
285 serialize_dword(pInfo->null0,&ptr);
286 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
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);*/
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);*/
300 /* data0 */
301 serialize_string(pInfo->data0.pbData,&ptr,
302 pInfo->data0.cbData,sizeof(BYTE),TRUE);
303 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
305 /* null1 */
306 serialize_dword(pInfo->null1,&ptr);
307 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
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);*/
316 /* salt */
317 serialize_string(pInfo->salt.pbData,&ptr,
318 pInfo->salt.cbData,sizeof(BYTE),TRUE);
319 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
321 /* cipher */
322 serialize_string(pInfo->cipher.pbData,&ptr,
323 pInfo->cipher.cbData,sizeof(BYTE),TRUE);
324 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
326 /* fingerprint */
327 serialize_string(pInfo->fingerprint.pbData,&ptr,
328 pInfo->fingerprint.cbData,sizeof(BYTE),TRUE);
329 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
331 if (ptr - pSerial->pbData != dwStruct)
333 ERR("struct size changed!? %u != expected %u\n",
334 ptr - pSerial->pbData, (unsigned int)dwStruct);
335 LocalFree(pSerial->pbData);
336 pSerial->pbData=NULL;
337 pSerial->cbData=0;
338 return FALSE;
341 return TRUE;
344 static
345 BOOL unserialize(const DATA_BLOB *pSerial, struct protect_data_t *pInfo)
347 BYTE * ptr;
348 DWORD index;
349 DWORD size;
350 BOOL status=TRUE;
352 TRACE("called\n");
354 if (!pInfo || !pSerial || !pSerial->pbData)
355 return FALSE;
357 index=0;
358 ptr=pSerial->pbData;
359 size=pSerial->cbData;
361 /* count0 */
362 if (!unserialize_dword(ptr,&index,size,&pInfo->count0))
364 ERR("reading count0 failed!\n");
365 return FALSE;
368 /* info0 */
369 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
370 &pInfo->info0.pbData, &pInfo->info0.cbData))
372 ERR("reading info0 failed!\n");
373 return FALSE;
376 /* count1 */
377 if (!unserialize_dword(ptr,&index,size,&pInfo->count1))
379 ERR("reading count1 failed!\n");
380 return FALSE;
383 /* info1 */
384 if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
385 &pInfo->info1.pbData, &pInfo->info1.cbData))
387 ERR("reading info1 failed!\n");
388 return FALSE;
391 /* null0 */
392 if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
394 ERR("reading null0 failed!\n");
395 return FALSE;
398 /* szDataDescr */
399 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
400 (BYTE**)&pInfo->szDataDescr, NULL))
402 ERR("reading szDataDescr failed!\n");
403 return FALSE;
406 /* cipher_alg */
407 if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_alg))
409 ERR("reading cipher_alg failed!\n");
410 return FALSE;
413 /* cipher_key_len */
414 if (!unserialize_dword(ptr,&index,size,&pInfo->cipher_key_len))
416 ERR("reading cipher_key_len failed!\n");
417 return FALSE;
420 /* data0 */
421 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
422 &pInfo->data0.pbData, &pInfo->data0.cbData))
424 ERR("reading data0 failed!\n");
425 return FALSE;
428 /* null1 */
429 if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
431 ERR("reading null1 failed!\n");
432 return FALSE;
435 /* hash_alg */
436 if (!unserialize_dword(ptr,&index,size,&pInfo->hash_alg))
438 ERR("reading hash_alg failed!\n");
439 return FALSE;
442 /* hash_len */
443 if (!unserialize_dword(ptr,&index,size,&pInfo->hash_len))
445 ERR("reading hash_len failed!\n");
446 return FALSE;
449 /* salt */
450 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
451 &pInfo->salt.pbData, &pInfo->salt.cbData))
453 ERR("reading salt failed!\n");
454 return FALSE;
457 /* cipher */
458 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
459 &pInfo->cipher.pbData, &pInfo->cipher.cbData))
461 ERR("reading cipher failed!\n");
462 return FALSE;
465 /* fingerprint */
466 if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
467 &pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
469 ERR("reading fingerprint failed!\n");
470 return FALSE;
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)
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",
480 (unsigned int)index, (unsigned int)size);
481 status=FALSE;
484 return status;
487 /* perform sanity checks */
488 static
489 BOOL valid_protect_data(const struct protect_data_t *pInfo)
491 BOOL status=TRUE;
493 TRACE("called\n");
495 if (pInfo->count0 != 0x0001)
497 ERR("count0 != 0x0001 !\n");
498 status=FALSE;
500 if (pInfo->count1 != 0x0001)
502 ERR("count0 != 0x0001 !\n");
503 status=FALSE;
505 if (pInfo->null0 != 0x0000)
507 ERR("null0 != 0x0000 !\n");
508 status=FALSE;
510 if (pInfo->null1 != 0x0000)
512 ERR("null1 != 0x0000 !\n");
513 status=FALSE;
515 /* since we have no idea what info0 is used for, and it seems
516 * rather constant, we can test for a Wine-specific magic string
517 * there to be reasonably sure we're using data created by the Wine
518 * implementation of CryptProtectData.
520 if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
521 strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
523 ERR("info0 magic value not matched !\n");
524 status=FALSE;
527 if (!status)
529 ERR("unrecognized CryptProtectData block\n");
532 return status;
535 static
536 void free_protect_data(struct protect_data_t * pInfo)
538 TRACE("called\n");
540 if (!pInfo) return;
542 CryptMemFree(pInfo->info0.pbData);
543 CryptMemFree(pInfo->info1.pbData);
544 CryptMemFree(pInfo->szDataDescr);
545 CryptMemFree(pInfo->data0.pbData);
546 CryptMemFree(pInfo->salt.pbData);
547 CryptMemFree(pInfo->cipher.pbData);
548 CryptMemFree(pInfo->fingerprint.pbData);
551 /* copies a string into a data blob */
552 static
553 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
555 if (!str || !blob) return NULL;
557 blob->cbData=strlen(str)+1;
558 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
560 blob->cbData=0;
562 else {
563 strcpy((LPSTR)blob->pbData, str);
566 return blob->pbData;
570 * Populates everything except "cipher" and "fingerprint".
572 static
573 BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
574 HCRYPTPROV hProv)
576 DWORD dwStrLen;
578 TRACE("called\n");
580 if (!pInfo) return FALSE;
582 dwStrLen=lstrlenW(szDataDescr);
584 memset(pInfo,0,sizeof(*pInfo));
586 pInfo->count0=0x0001;
588 convert_str_to_blob(crypt_magic_str, &pInfo->info0);
590 pInfo->count1=0x0001;
592 convert_str_to_blob(crypt_magic_str, &pInfo->info1);
594 pInfo->null0=0x0000;
596 if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
598 memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
601 pInfo->cipher_alg=CRYPT32_PROTECTDATA_KEY_CALG;
602 pInfo->cipher_key_len=CRYPT32_PROTECTDATA_KEY_LEN;
604 convert_str_to_blob(crypt_magic_str, &pInfo->data0);
606 pInfo->null1=0x0000;
607 pInfo->hash_alg=CRYPT32_PROTECTDATA_HASH_CALG;
608 pInfo->hash_len=CRYPT32_PROTECTDATA_HASH_LEN;
610 /* allocate memory to hold a salt */
611 pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
612 if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
614 /* generate random salt */
615 if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
617 ERR("CryptGenRandom\n");
618 free_protect_data(pInfo);
619 return FALSE;
623 /* debug: show our salt */
624 TRACE_DATA_BLOB(&pInfo->salt);
626 pInfo->cipher.cbData=0;
627 pInfo->cipher.pbData=NULL;
629 pInfo->fingerprint.cbData=0;
630 pInfo->fingerprint.pbData=NULL;
632 /* check all the allocations at once */
633 if (!pInfo->info0.pbData ||
634 !pInfo->info1.pbData ||
635 !pInfo->szDataDescr ||
636 !pInfo->data0.pbData ||
637 !pInfo->salt.pbData
640 ERR("could not allocate protect_data structures\n");
641 free_protect_data(pInfo);
642 return FALSE;
645 return TRUE;
648 static
649 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
651 DWORD dwSize;
653 TRACE("called\n");
655 if (!blob) return FALSE;
657 dwSize=sizeof(DWORD);
658 if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
659 &dwSize, 0))
661 ERR("failed to get hash size\n");
662 return FALSE;
665 if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
667 ERR("failed to allocate blob memory\n");
668 return FALSE;
671 dwSize=blob->cbData;
672 if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
674 ERR("failed to get hash value\n");
675 CryptMemFree(blob->pbData);
676 blob->pbData=NULL;
677 blob->cbData=0;
678 return FALSE;
681 return TRUE;
684 /* test that a given hash matches an exported-to-blob hash value */
685 static
686 BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two)
688 BOOL rc = FALSE;
689 DATA_BLOB one;
691 if (!two || !two->pbData) return FALSE;
693 if (!convert_hash_to_blob(hHash,&one)) {
694 return FALSE;
697 if ( one.cbData == two->cbData &&
698 memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
700 rc = TRUE;
703 CryptMemFree(one.pbData);
704 return rc;
707 /* create an encryption key from a given salt and optional entropy */
708 static
709 BOOL load_encryption_key(HCRYPTPROV hProv, DWORD key_len, const DATA_BLOB *salt,
710 const DATA_BLOB *pOptionalEntropy, HCRYPTKEY *phKey)
712 BOOL rc = TRUE;
713 HCRYPTHASH hSaltHash;
714 char * szUsername = NULL;
715 DWORD dwUsernameLen;
716 DWORD dwError;
718 /* create hash for salt */
719 if (!salt || !phKey ||
720 !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
722 ERR("CryptCreateHash\n");
723 return FALSE;
726 /* This should be the "logon credentials" instead of username */
727 dwError=GetLastError();
728 dwUsernameLen = 0;
729 if (!GetUserNameA(NULL,&dwUsernameLen) &&
730 GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
731 (szUsername = CryptMemAlloc(dwUsernameLen)))
733 szUsername[0]='\0';
734 GetUserNameA( szUsername, &dwUsernameLen );
736 SetLastError(dwError);
738 /* salt the hash with:
739 * - the user id
740 * - an "internal secret"
741 * - randomness (from the salt)
742 * - user-supplied entropy
744 if ((szUsername && !CryptHashData(hSaltHash,(LPBYTE)szUsername,dwUsernameLen,0)) ||
745 !CryptHashData(hSaltHash,crypt32_protectdata_secret,
746 sizeof(crypt32_protectdata_secret)-1,0) ||
747 !CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
748 (pOptionalEntropy && !CryptHashData(hSaltHash,
749 pOptionalEntropy->pbData,
750 pOptionalEntropy->cbData,0)))
752 ERR("CryptHashData\n");
753 rc = FALSE;
756 /* produce a symmetric key */
757 if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG,
758 hSaltHash,key_len << 16 | CRYPT_EXPORTABLE,phKey))
760 ERR("CryptDeriveKey\n");
761 rc = FALSE;
764 /* clean up */
765 CryptDestroyHash(hSaltHash);
766 CryptMemFree(szUsername);
768 return rc;
771 /* debugging tool to print the structures of a ProtectData call */
772 static void
773 report(const DATA_BLOB* pDataIn, const DATA_BLOB* pOptionalEntropy,
774 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags)
776 TRACE("pPromptStruct: %p\n", pPromptStruct);
777 if (pPromptStruct)
779 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct->cbSize);
780 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct->dwPromptFlags);
781 TRACE(" hwndApp: %p\n", pPromptStruct->hwndApp);
782 TRACE(" szPrompt: %p %s\n",
783 pPromptStruct->szPrompt,
784 pPromptStruct->szPrompt ? debugstr_w(pPromptStruct->szPrompt)
785 : "");
787 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags);
788 TRACE_DATA_BLOB(pDataIn);
789 if (pOptionalEntropy)
791 TRACE_DATA_BLOB(pOptionalEntropy);
792 TRACE(" %s\n",debugstr_an((LPCSTR)pOptionalEntropy->pbData,pOptionalEntropy->cbData));
798 /***************************************************************************
799 * CryptProtectData [CRYPT32.@]
801 * Generate Cipher data from given Plain and Entropy data.
803 * PARAMS
804 * pDataIn [I] Plain data to be enciphered
805 * szDataDescr [I] Optional Unicode string describing the Plain data
806 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
807 * pvReserved [I] Reserved, must be NULL
808 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
809 * dwFlags [I] Flags describing options to the ciphering
810 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
812 * RETURNS
813 * TRUE If a Cipher was generated.
814 * FALSE If something failed and no Cipher is available.
816 * FIXME
817 * The true Windows encryption and keying mechanisms are unknown.
819 * dwFlags and pPromptStruct are currently ignored.
821 * NOTES
822 * Memory allocated in pDataOut must be freed with LocalFree.
825 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn,
826 LPCWSTR szDataDescr,
827 DATA_BLOB* pOptionalEntropy,
828 PVOID pvReserved,
829 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
830 DWORD dwFlags,
831 DATA_BLOB* pDataOut)
833 static const WCHAR empty_str[1];
834 BOOL rc = FALSE;
835 HCRYPTPROV hProv;
836 struct protect_data_t protect_data;
837 HCRYPTHASH hHash;
838 HCRYPTKEY hKey;
839 DWORD dwLength;
841 TRACE("called\n");
843 SetLastError(ERROR_SUCCESS);
845 if (!pDataIn || !pDataOut)
847 SetLastError(ERROR_INVALID_PARAMETER);
848 goto finished;
851 /* debug: show our arguments */
852 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
853 TRACE("\tszDataDescr: %p %s\n", szDataDescr,
854 szDataDescr ? debugstr_w(szDataDescr) : "");
856 /* Windows appears to create an empty szDataDescr instead of maintaining
857 * a NULL */
858 if (!szDataDescr)
859 szDataDescr = empty_str;
861 /* get crypt context */
862 if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
864 ERR("CryptAcquireContextW failed\n");
865 goto finished;
868 /* populate our structure */
869 if (!fill_protect_data(&protect_data,szDataDescr,hProv))
871 ERR("fill_protect_data\n");
872 goto free_context;
875 /* load key */
876 if (!load_encryption_key(hProv,protect_data.cipher_key_len,&protect_data.salt,pOptionalEntropy,&hKey))
878 goto free_protect_data;
881 /* create a hash for the encryption validation */
882 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
884 ERR("CryptCreateHash\n");
885 goto free_key;
888 /* calculate storage required */
889 dwLength=pDataIn->cbData;
890 if (CryptEncrypt(hKey, 0, TRUE, 0, pDataIn->pbData, &dwLength, 0) ||
891 GetLastError()!=ERROR_MORE_DATA)
893 ERR("CryptEncrypt\n");
894 goto free_hash;
896 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength);
898 /* copy plain text into cipher area for CryptEncrypt call */
899 protect_data.cipher.cbData=dwLength;
900 if (!(protect_data.cipher.pbData=CryptMemAlloc(
901 protect_data.cipher.cbData)))
903 ERR("CryptMemAlloc\n");
904 goto free_hash;
906 memcpy(protect_data.cipher.pbData,pDataIn->pbData,pDataIn->cbData);
908 /* encrypt! */
909 dwLength=pDataIn->cbData;
910 if (!CryptEncrypt(hKey, hHash, TRUE, 0, protect_data.cipher.pbData,
911 &dwLength, protect_data.cipher.cbData))
913 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
914 goto free_hash;
916 protect_data.cipher.cbData=dwLength;
918 /* debug: show the cipher */
919 TRACE_DATA_BLOB(&protect_data.cipher);
921 /* attach our fingerprint */
922 if (!convert_hash_to_blob(hHash, &protect_data.fingerprint))
924 ERR("convert_hash_to_blob\n");
925 goto free_hash;
928 /* serialize into an opaque blob */
929 if (!serialize(&protect_data, pDataOut))
931 ERR("serialize\n");
932 goto free_hash;
935 /* success! */
936 rc=TRUE;
938 free_hash:
939 CryptDestroyHash(hHash);
940 free_key:
941 CryptDestroyKey(hKey);
942 free_protect_data:
943 free_protect_data(&protect_data);
944 free_context:
945 CryptReleaseContext(hProv,0);
946 finished:
947 /* If some error occurred, and no error code was set, force one. */
948 if (!rc && GetLastError()==ERROR_SUCCESS)
950 SetLastError(ERROR_INVALID_DATA);
953 if (rc)
955 SetLastError(ERROR_SUCCESS);
957 TRACE_DATA_BLOB(pDataOut);
960 TRACE("returning %s\n", rc ? "ok" : "FAIL");
962 return rc;
966 /***************************************************************************
967 * CryptUnprotectData [CRYPT32.@]
969 * Generate Plain data and Description from given Cipher and Entropy data.
971 * PARAMS
972 * pDataIn [I] Cipher data to be decoded
973 * ppszDataDescr [O] Optional Unicode string describing the Plain data
974 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
975 * pvReserved [I] Reserved, must be NULL
976 * pPromptStruct [I] Structure describing if/how to prompt during decoding
977 * dwFlags [I] Flags describing options to the decoding
978 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
980 * RETURNS
981 * TRUE If a Plain was generated.
982 * FALSE If something failed and no Plain is available.
984 * FIXME
985 * The true Windows encryption and keying mechanisms are unknown.
987 * dwFlags and pPromptStruct are currently ignored.
989 * NOTES
990 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
991 * with LocalFree.
994 BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn,
995 LPWSTR * ppszDataDescr,
996 DATA_BLOB* pOptionalEntropy,
997 PVOID pvReserved,
998 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
999 DWORD dwFlags,
1000 DATA_BLOB* pDataOut)
1002 BOOL rc = FALSE;
1004 HCRYPTPROV hProv;
1005 struct protect_data_t protect_data;
1006 HCRYPTHASH hHash;
1007 HCRYPTKEY hKey;
1008 DWORD dwLength;
1010 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.";
1012 TRACE("called\n");
1014 SetLastError(ERROR_SUCCESS);
1016 if (!pDataIn || !pDataOut)
1018 SetLastError(ERROR_INVALID_PARAMETER);
1019 goto finished;
1021 if (!pDataIn->cbData)
1023 SetLastError(ERROR_INVALID_DATA);
1024 goto finished;
1027 /* debug: show our arguments */
1028 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags);
1029 TRACE("\tppszDataDescr: %p\n", ppszDataDescr);
1031 /* take apart the opaque blob */
1032 if (!unserialize(pDataIn, &protect_data))
1034 SetLastError(ERROR_INVALID_DATA);
1035 FIXME("%s\n",announce_bad_opaque_data);
1036 goto finished;
1039 /* perform basic validation on the resulting structure */
1040 if (!valid_protect_data(&protect_data))
1042 SetLastError(ERROR_INVALID_DATA);
1043 FIXME("%s\n",announce_bad_opaque_data);
1044 goto free_protect_data;
1047 /* get a crypt context */
1048 if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT))
1050 ERR("CryptAcquireContextW failed\n");
1051 goto free_protect_data;
1054 /* load key */
1055 if (!load_encryption_key(hProv,protect_data.cipher_key_len,&protect_data.salt,pOptionalEntropy,&hKey))
1057 goto free_context;
1060 /* create a hash for the decryption validation */
1061 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash))
1063 ERR("CryptCreateHash\n");
1064 goto free_key;
1067 /* prepare for plaintext */
1068 pDataOut->cbData=protect_data.cipher.cbData;
1069 if (!(pDataOut->pbData=LocalAlloc( LPTR, pDataOut->cbData)))
1071 ERR("CryptMemAlloc\n");
1072 goto free_hash;
1074 memcpy(pDataOut->pbData,protect_data.cipher.pbData,protect_data.cipher.cbData);
1076 /* decrypt! */
1077 if (!CryptDecrypt(hKey, hHash, TRUE, 0, pDataOut->pbData,
1078 &pDataOut->cbData) ||
1079 /* check the hash fingerprint */
1080 pDataOut->cbData > protect_data.cipher.cbData ||
1081 !hash_matches_blob(hHash, &protect_data.fingerprint))
1083 SetLastError(ERROR_INVALID_DATA);
1085 LocalFree( pDataOut->pbData );
1086 pDataOut->pbData = NULL;
1087 pDataOut->cbData = 0;
1089 goto free_hash;
1092 /* Copy out the description */
1093 dwLength = (lstrlenW(protect_data.szDataDescr)+1) * sizeof(WCHAR);
1094 if (ppszDataDescr)
1096 if (!(*ppszDataDescr = LocalAlloc(LPTR,dwLength)))
1098 ERR("LocalAlloc (ppszDataDescr)\n");
1099 goto free_hash;
1101 else {
1102 memcpy(*ppszDataDescr,protect_data.szDataDescr,dwLength);
1106 /* success! */
1107 rc = TRUE;
1109 free_hash:
1110 CryptDestroyHash(hHash);
1111 free_key:
1112 CryptDestroyKey(hKey);
1113 free_context:
1114 CryptReleaseContext(hProv,0);
1115 free_protect_data:
1116 free_protect_data(&protect_data);
1117 finished:
1118 /* If some error occurred, and no error code was set, force one. */
1119 if (!rc && GetLastError()==ERROR_SUCCESS)
1121 SetLastError(ERROR_INVALID_DATA);
1124 if (rc) {
1125 SetLastError(ERROR_SUCCESS);
1127 if (ppszDataDescr)
1129 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr));
1131 TRACE_DATA_BLOB(pDataOut);
1134 TRACE("returning %s\n", rc ? "ok" : "FAIL");
1136 return rc;