1 /* 2 * Copyright 2005 Kees Cook <kees@outflux.net> 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19 20 /* 21 * The Win32 CryptProtectData and CryptUnprotectData functions are meant 22 * to provide a mechanism for encrypting data on a machine where other users 23 * of the system can't be trusted. It is used in many examples as a way 24 * to store username and password information to the registry, but store 25 * it not in the clear. 26 * 27 * The encryption is symmetric, but the method is unknown. However, since 28 * it is keyed to the machine and the user, it is unlikely that the values 29 * would be portable. Since programs must first call CryptProtectData to 30 * get a cipher text, the underlying system doesn't have to exactly 31 * match the real Windows version. However, attempts have been made to 32 * at least try to look like the Windows version, including guesses at the 33 * purpose of various portions of the "opaque data blob" that is used. 34 * 35 */ 36 37 #include <stdarg.h> 38 #include <stdio.h> 39 #include <string.h> 40 #include <stdlib.h> 41 42 #include "windef.h" 43 #include "winbase.h" 44 #include "wincrypt.h" 45 #include "wine/debug.h" 46 47 WINE_DEFAULT_DEBUG_CHANNEL(crypt); 48 49 #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL 50 #define CRYPT32_PROTECTDATA_HASH_CALG CALG_SHA1 51 #define CRYPT32_PROTECTDATA_HASH_LEN 160 52 #define CRYPT32_PROTECTDATA_KEY_CALG CALG_3DES 53 #define CRYPT32_PROTECTDATA_KEY_LEN 168 54 #define CRYPT32_PROTECTDATA_SALT_LEN 16 55 56 static const BYTE crypt32_protectdata_secret[] = { 57 'I','\'','m',' ','h','u','n','t','i','n','g',' ', 58 'w','a','b','b','i','t','s',0 59 }; 60 61 /* 62 * The data format returned by the real Windows CryptProtectData seems 63 * to be something like this: 64 65 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1) 66 BYTE info0_0[16]; - unknown information - persistent across invocations, 67 ... reboots, password changes, and users 68 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1) 69 BYTE info1_0[16]; - unknown information - unique to each user, but 70 ... persistent across reboots and password changes 71 DWORD null0; - NULL "end of records"? 72 DWORD str_len; - byte length of WCHAR string including term 73 BYTE str[str_len]; - The "dataDescription" value as a NULL-terminated 74 little-endian WCHAR string 75 ALG_ID cipher_alg; - cipher algo - was CALG_3DES 76 DWORD cipher_key_len; - cipher key bit length - was 0xa8==168 77 DWORD data_len; - length of data (was 16 in samples) 78 BYTE data[data_len]; - unknown data (fingerprint?) 79 DWORD null1; - NULL ? 80 ALG_ID hash_alg; - hash algo - was CALG_SHA1 81 DWORD hash_len; - bit length of hash - was 0xa0==160 82 DWORD salt_len; - length of salt(?) data 83 BYTE salt[salt_len]; - salt(?) for symmetric encryption 84 DWORD cipher_len; - length of cipher(?) data - was close to plain len 85 BYTE cipher[cipher_len]; - cipher text? 86 DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1 87 BYTE crc[crc_len]; - fingerprint of record? 88 89 * The data structures used in Wine are modelled after this guess. 90 */ 91 92 struct protect_data_t 93 { 94 DWORD count0; 95 DATA_BLOB info0; /* using this to hold crypt_magic_str */ 96 DWORD count1; 97 DATA_BLOB info1; 98 DWORD null0; 99 WCHAR * szDataDescr; /* serialized differently than the DATA_BLOBs */ 100 ALG_ID cipher_alg; 101 DWORD cipher_key_len; 102 DATA_BLOB data0; 103 DWORD null1; 104 ALG_ID hash_alg; 105 DWORD hash_len; 106 DATA_BLOB salt; 107 DATA_BLOB cipher; 108 DATA_BLOB fingerprint; 109 }; 110 111 /* this is used to check if an incoming structure was built by Wine */ 112 static const char crypt_magic_str[] = "Wine Crypt32 ok"; 113 114 /* debugging tool to print strings of hex chars */ 115 static const char * 116 hex_str(const unsigned char *p, int n) 117 { 118 const char * ptr; 119 char report[80]; 120 int r=-1; 121 report[0]='\0'; 122 ptr = wine_dbg_sprintf("%s",""); 123 while (--n >= 0) 124 { 125 if (r++ % 20 == 19) 126 { 127 ptr = wine_dbg_sprintf("%s%s",ptr,report); 128 report[0]='\0'; 129 } 130 sprintf(report+strlen(report),"%s%02x", r ? "," : "", *p++); 131 } 132 return wine_dbg_sprintf("%s%s",ptr,report); 133 } 134 135 #define TRACE_DATA_BLOB(blob) do { \ 136 TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \ 137 TRACE("%s pbData @ %p:%s\n", #blob ,(blob)->pbData, \ 138 hex_str((blob)->pbData, (blob)->cbData)); \ 139 } while (0) 140 141 static 142 void serialize_dword(DWORD value,BYTE ** ptr) 143 { 144 /*TRACE("called\n");*/ 145 146 memcpy(*ptr,&value,sizeof(DWORD)); 147 *ptr+=sizeof(DWORD); 148 } 149 150 static 151 void serialize_string(const BYTE *str, BYTE **ptr, DWORD len, DWORD width, 152 BOOL prepend_len) 153 { 154 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/ 155 156 if (prepend_len) 157 { 158 serialize_dword(len,ptr); 159 } 160 memcpy(*ptr,str,len*width); 161 *ptr+=len*width; 162 } 163 164 static 165 BOOL unserialize_dword(const BYTE *ptr, DWORD *index, DWORD size, DWORD *value) 166 { 167 /*TRACE("called\n");*/ 168 169 if (!ptr || !index || !value) return FALSE; 170 171 if (*index+sizeof(DWORD)>size) 172 { 173 return FALSE; 174 } 175 176 memcpy(value,&(ptr[*index]),sizeof(DWORD)); 177 *index+=sizeof(DWORD); 178 179 return TRUE; 180 } 181 182 static 183 BOOL unserialize_string(const BYTE *ptr, DWORD *index, DWORD size, 184 DWORD len, DWORD width, BOOL inline_len, 185 BYTE ** data, DWORD * stored) 186 { 187 /*TRACE("called\n");*/ 188 189 if (!ptr || !data) return FALSE; 190 191 if (inline_len) { 192 if (!unserialize_dword(ptr,index,size,&len)) 193 return FALSE; 194 } 195 196 if (*index+len*width>size) 197 { 198 return FALSE; 199 } 200 201 if (!(*data = CryptMemAlloc( len*width))) 202 { 203 return FALSE; 204 } 205 206 memcpy(*data,&(ptr[*index]),len*width); 207 if (stored) 208 { 209 *stored = len; 210 } 211 *index+=len*width; 212 213 return TRUE; 214 } 215 216 static 217 BOOL serialize(const struct protect_data_t *pInfo, DATA_BLOB *pSerial) 218 { 219 BYTE * ptr; 220 DWORD dwStrLen; 221 DWORD dwStruct; 222 223 TRACE("called\n"); 224 225 if (!pInfo || !pInfo->szDataDescr || !pSerial || 226 !pInfo->info0.pbData || !pInfo->info1.pbData || 227 !pInfo->data0.pbData || !pInfo->salt.pbData || 228 !pInfo->cipher.pbData || !pInfo->fingerprint.pbData) 229 { 230 return FALSE; 231 } 232 233 if (pInfo->info0.cbData!=16) 234 { 235 ERR("protect_data_t info0 not 16 bytes long\n"); 236 } 237 238 if (pInfo->info1.cbData!=16) 239 { 240 ERR("protect_data_t info1 not 16 bytes long\n"); 241 } 242 243 dwStrLen=lstrlenW(pInfo->szDataDescr); 244 245 pSerial->cbData=0; 246 pSerial->cbData+=sizeof(DWORD)*8; /* 8 raw DWORDs */ 247 pSerial->cbData+=sizeof(DWORD)*4; /* 4 BLOBs with size */ 248 pSerial->cbData+=pInfo->info0.cbData; 249 pSerial->cbData+=pInfo->info1.cbData; 250 pSerial->cbData+=(dwStrLen+1)*sizeof(WCHAR) + 4; /* str, null, size */ 251 pSerial->cbData+=pInfo->data0.cbData; 252 pSerial->cbData+=pInfo->salt.cbData; 253 pSerial->cbData+=pInfo->cipher.cbData; 254 pSerial->cbData+=pInfo->fingerprint.cbData; 255 256 /* save the actual structure size */ 257 dwStruct = pSerial->cbData; 258 /* There may be a 256 byte minimum, but I can't prove it. */ 259 /*if (pSerial->cbData<256) pSerial->cbData=256;*/ 260 261 pSerial->pbData=LocalAlloc(LPTR,pSerial->cbData); 262 if (!pSerial->pbData) return FALSE; 263 264 ptr=pSerial->pbData; 265 266 /* count0 */ 267 serialize_dword(pInfo->count0,&ptr); 268 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 269 270 /* info0 */ 271 serialize_string(pInfo->info0.pbData,&ptr, 272 pInfo->info0.cbData,sizeof(BYTE),FALSE); 273 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 274 275 /* count1 */ 276 serialize_dword(pInfo->count1,&ptr); 277 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 278 279 /* info1 */ 280 serialize_string(pInfo->info1.pbData,&ptr, 281 pInfo->info1.cbData,sizeof(BYTE),FALSE); 282 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 283 284 /* null0 */ 285 serialize_dword(pInfo->null0,&ptr); 286 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 287 288 /* szDataDescr */ 289 serialize_string((BYTE*)pInfo->szDataDescr,&ptr, 290 (dwStrLen+1)*sizeof(WCHAR),sizeof(BYTE),TRUE); 291 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 292 293 /* cipher_alg */ 294 serialize_dword(pInfo->cipher_alg,&ptr); 295 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 296 /* cipher_key_len */ 297 serialize_dword(pInfo->cipher_key_len,&ptr); 298 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 299 300 /* data0 */ 301 serialize_string(pInfo->data0.pbData,&ptr, 302 pInfo->data0.cbData,sizeof(BYTE),TRUE); 303 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 304 305 /* null1 */ 306 serialize_dword(pInfo->null1,&ptr); 307 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 308 309 /* hash_alg */ 310 serialize_dword(pInfo->hash_alg,&ptr); 311 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 312 /* hash_len */ 313 serialize_dword(pInfo->hash_len,&ptr); 314 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 315 316 /* salt */ 317 serialize_string(pInfo->salt.pbData,&ptr, 318 pInfo->salt.cbData,sizeof(BYTE),TRUE); 319 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 320 321 /* cipher */ 322 serialize_string(pInfo->cipher.pbData,&ptr, 323 pInfo->cipher.cbData,sizeof(BYTE),TRUE); 324 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 325 326 /* fingerprint */ 327 serialize_string(pInfo->fingerprint.pbData,&ptr, 328 pInfo->fingerprint.cbData,sizeof(BYTE),TRUE); 329 /*TRACE("used %u\n",ptr-pSerial->pbData);*/ 330 331 if (ptr - pSerial->pbData != dwStruct) 332 { 333 ERR("struct size changed!? 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 */ 413 if (!unserialize_dword(ptr,&index,size,&pInfo->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 487 BOOL valid_protect_data(const struct protect_data_t *pInfo) 488 { 489 BOOL status=TRUE; 490 491 TRACE("called\n"); 492 493 if (pInfo->count0 != 0x0001) 494 { 495 ERR("count0 != 0x0001 !\n"); 496 status=FALSE; 497 } 498 if (pInfo->count1 != 0x0001) 499 { 500 ERR("count0 != 0x0001 !\n"); 501 status=FALSE; 502 } 503 if (pInfo->null0 != 0x0000) 504 { 505 ERR("null0 != 0x0000 !\n"); 506 status=FALSE; 507 } 508 if (pInfo->null1 != 0x0000) 509 { 510 ERR("null1 != 0x0000 !\n"); 511 status=FALSE; 512 } 513 /* since we have no idea what info0 is used for, and it seems 514 * rather constant, we can test for a Wine-specific magic string 515 * there to be reasonably sure we're using data created by the Wine 516 * implementation of CryptProtectData. 517 */ 518 if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 || 519 strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0) 520 { 521 ERR("info0 magic value not matched !\n"); 522 status=FALSE; 523 } 524 525 if (!status) 526 { 527 ERR("unrecognized CryptProtectData block\n"); 528 } 529 530 return status; 531 } 532 533 static 534 void free_protect_data(struct protect_data_t * pInfo) 535 { 536 TRACE("called\n"); 537 538 if (!pInfo) return; 539 540 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); 546 CryptMemFree(pInfo->fingerprint.pbData); 547 } 548 549 /* copies a string into a data blob */ 550 static 551 BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob) 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, 572 HCRYPTPROV hProv) 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 586 convert_str_to_blob(crypt_magic_str, &pInfo->info0); 587 588 pInfo->count1=0x0001; 589 590 convert_str_to_blob(crypt_magic_str, &pInfo->info1); 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 599 pInfo->cipher_alg=CRYPT32_PROTECTDATA_KEY_CALG; 600 pInfo->cipher_key_len=CRYPT32_PROTECTDATA_KEY_LEN; 601 602 convert_str_to_blob(crypt_magic_str, &pInfo->data0); 603 604 pInfo->null1=0x0000; 605 pInfo->hash_alg=CRYPT32_PROTECTDATA_HASH_CALG; 606 pInfo->hash_len=CRYPT32_PROTECTDATA_HASH_LEN; 607 608 /* allocate memory to hold a salt */ 609 if ((pInfo->salt.pbData=CryptMemAlloc(CRYPT32_PROTECTDATA_SALT_LEN))) 610 { 611 /* generate random salt */ 612 if (!CryptGenRandom(hProv, CRYPT32_PROTECTDATA_SALT_LEN, pInfo->salt.pbData)) 613 { 614 ERR("CryptGenRandom\n"); 615 free_protect_data(pInfo); 616 return FALSE; 617 } 618 pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN; 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 645 BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob) 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 682 BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two) 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 705 BOOL load_encryption_key(HCRYPTPROV hProv, DWORD key_len, const DATA_BLOB *salt, 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 || 716 !CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash)) 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)) || 741 !CryptHashData(hSaltHash,crypt32_protectdata_secret, 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 */ 753 if (rc && !CryptDeriveKey(hProv,CRYPT32_PROTECTDATA_KEY_CALG, 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 */ 821 BOOL WINAPI CryptProtectData(DATA_BLOB* pDataIn, 822 LPCWSTR szDataDescr, 823 DATA_BLOB* pOptionalEntropy, 824 PVOID pvReserved, 825 CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, 826 DWORD dwFlags, 827 DATA_BLOB* pDataOut) 828 { 829 static const WCHAR empty_str[1]; 830 BOOL rc = FALSE; 831 HCRYPTPROV hProv; 832 struct protect_data_t protect_data; 833 HCRYPTHASH hHash; 834 HCRYPTKEY hKey; 835 DWORD dwLength; 836 837 TRACE("called\n"); 838 839 SetLastError(ERROR_SUCCESS); 840 841 if (!pDataIn || !pDataOut) 842 { 843 SetLastError(ERROR_INVALID_PARAMETER); 844 goto finished; 845 } 846 847 /* debug: show our arguments */ 848 report(pDataIn,pOptionalEntropy,pPromptStruct,dwFlags); 849 TRACE("\tszDataDescr: %p %s\n", szDataDescr, 850 szDataDescr ? debugstr_w(szDataDescr) : ""); 851 852 /* Windows appears to create an empty szDataDescr instead of maintaining 853 * a NULL */ 854 if (!szDataDescr) 855 szDataDescr = empty_str; 856 857 /* get crypt context */ 858 if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) 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 */ 878 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash)) 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) || 887 GetLastError()!=ERROR_MORE_DATA) 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: 935 CryptDestroyHash(hHash); 936 free_key: 937 CryptDestroyKey(hKey); 938 free_protect_data: 939 free_protect_data(&protect_data); 940 free_context: 941 CryptReleaseContext(hProv,0); 942 finished: 943 /* If some error occurred, and no error code was set, force one. */ 944 if (!rc && GetLastError()==ERROR_SUCCESS) 945 { 946 SetLastError(ERROR_INVALID_DATA); 947 } 948 949 if (rc) 950 { 951 SetLastError(ERROR_SUCCESS); 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 */ 990 BOOL WINAPI CryptUnprotectData(DATA_BLOB* pDataIn, 991 LPWSTR * ppszDataDescr, 992 DATA_BLOB* pOptionalEntropy, 993 PVOID pvReserved, 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 1010 SetLastError(ERROR_SUCCESS); 1011 1012 if (!pDataIn || !pDataOut) 1013 { 1014 SetLastError(ERROR_INVALID_PARAMETER); 1015 goto finished; 1016 } 1017 if (!pDataIn->cbData) 1018 { 1019 SetLastError(ERROR_INVALID_DATA); 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 { 1030 SetLastError(ERROR_INVALID_DATA); 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 { 1038 SetLastError(ERROR_INVALID_DATA); 1039 FIXME("%s\n",announce_bad_opaque_data); 1040 goto free_protect_data; 1041 } 1042 1043 /* get a crypt context */ 1044 if (!CryptAcquireContextW(&hProv,NULL,MS_ENHANCED_PROV_W,CRYPT32_PROTECTDATA_PROV,CRYPT_VERIFYCONTEXT)) 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 */ 1057 if (!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hHash)) 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 { 1079 SetLastError(ERROR_INVALID_DATA); 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: 1106 CryptDestroyHash(hHash); 1107 free_key: 1108 CryptDestroyKey(hKey); 1109 free_context: 1110 CryptReleaseContext(hProv,0); 1111 free_protect_data: 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 { 1117 SetLastError(ERROR_INVALID_DATA); 1118 } 1119 1120 if (rc) { 1121 SetLastError(ERROR_SUCCESS); 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 } 1134