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.
39 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
41 #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL
42 #define CRYPT32_PROTECTDATA_HASH_CALG CALG_MD5
43 #define CRYPT32_PROTECTDATA_KEY_CALG CALG_RC2
44 #define CRYPT32_PROTECTDATA_SALT_LEN 16
46 static const BYTE crypt32_protectdata_secret
[] = {
47 'I','\'','m',' ','h','u','n','t','i','n','g',' ',
48 'w','a','b','b','i','t','s',0
52 * The data format returned by the real Windows CryptProtectData seems
53 * to be something like this:
55 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1)
56 BYTE info0_0[16]; - unknown information
58 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1)
59 BYTE info1_0[16]; - unknown information
61 DWORD null0; - NULL "end of records"?
62 DWORD str_len; - length of WCHAR string including term
63 WCHAR str[str_len]; - The "dataDescription" value
64 DWORD unknown0; - unknown value (seems large, but only WORD large)
65 DWORD unknown1; - unknown value (seems small, less than a BYTE)
66 DWORD data_len; - length of data (was 16 in samples)
67 BYTE data[data_len]; - unknown data (fingerprint?)
69 DWORD unknown2; - unknown value (seems large, but only WORD large)
70 DWORD unknown3; - unknown value (seems small, less than a BYTE)
71 DWORD salt_len; - length of salt(?) data
72 BYTE salt[salt_len]; - salt(?) for symmetric encryption
73 DWORD cipher_len; - length of cipher(?) data - was close to plain len
74 BYTE cipher[cipher_len]; - cipher text?
75 DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1
76 BYTE crc[crc_len]; - fingerprint of record?
78 * The data structures used in Wine are modelled after this guess.
84 DATA_BLOB info0
; /* using this to hold crypt_magic_str */
88 WCHAR
* szDataDescr
; /* serialized differently than the DATA_BLOBs */
89 DWORD unknown0
; /* perhaps the HASH alg const should go here? */
93 DWORD unknown2
; /* perhaps the KEY alg const should go here? */
97 DATA_BLOB fingerprint
;
100 /* this is used to check if an incoming structure was built by Wine */
101 static const char * crypt_magic_str
= "Wine Crypt32 ok";
103 /* debugging tool to print strings of hex chars */
105 hex_str(unsigned char *p
, int n
)
111 ptr
= wine_dbg_sprintf("%s","");
116 ptr
= wine_dbg_sprintf("%s%s",ptr
,report
);
119 sprintf(report
+strlen(report
),"%s%02x", r
? "," : "", *p
++);
121 return wine_dbg_sprintf("%s%s",ptr
,report
);
124 #define TRACE_DATA_BLOB(blob) do { \
125 TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
126 TRACE("%s pbData @ %p:%s\n", #blob ,(blob)->pbData, \
127 hex_str((blob)->pbData, (blob)->cbData)); \
131 void serialize_dword(DWORD value
,BYTE
** ptr
)
133 /*TRACE("called\n");*/
135 memcpy(*ptr
,&value
,sizeof(DWORD
));
140 void serialize_string(BYTE
* str
,BYTE
** ptr
,DWORD len
, DWORD width
,
143 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
147 serialize_dword(len
,ptr
);
149 memcpy(*ptr
,str
,len
*width
);
154 BOOL
unserialize_dword(BYTE
* ptr
, DWORD
*index
, DWORD size
, DWORD
* value
)
156 /*TRACE("called\n");*/
158 if (!ptr
|| !index
|| !value
) return FALSE
;
160 if (*index
+sizeof(DWORD
)>size
)
165 memcpy(value
,&(ptr
[*index
]),sizeof(DWORD
));
166 *index
+=sizeof(DWORD
);
172 BOOL
unserialize_string(BYTE
* ptr
, DWORD
*index
, DWORD size
,
173 DWORD len
, DWORD width
, BOOL inline_len
,
174 BYTE
** data
, DWORD
* stored
)
176 /*TRACE("called\n");*/
178 if (!ptr
|| !data
) return FALSE
;
181 if (!unserialize_dword(ptr
,index
,size
,&len
))
185 if (*index
+len
*width
>size
)
190 if (!(*data
= CryptMemAlloc( len
*width
)))
195 memcpy(*data
,&(ptr
[*index
]),len
*width
);
206 BOOL
serialize(struct protect_data_t
* pInfo
, DATA_BLOB
* pSerial
)
214 if (!pInfo
|| !pInfo
->szDataDescr
|| !pSerial
||
215 !pInfo
->info0
.pbData
|| !pInfo
->info1
.pbData
||
216 !pInfo
->data0
.pbData
|| !pInfo
->salt
.pbData
||
217 !pInfo
->cipher
.pbData
|| !pInfo
->fingerprint
.pbData
)
222 if (pInfo
->info0
.cbData
!=16)
224 ERR("protect_data_t info0 not 16 bytes long\n");
227 if (pInfo
->info1
.cbData
!=16)
229 ERR("protect_data_t info1 not 16 bytes long\n");
232 dwStrLen
=lstrlenW(pInfo
->szDataDescr
);
235 pSerial
->cbData
+=sizeof(DWORD
)*8; /* 8 raw DWORDs */
236 pSerial
->cbData
+=sizeof(DWORD
)*4; /* 4 BLOBs with size */
237 pSerial
->cbData
+=pInfo
->info0
.cbData
;
238 pSerial
->cbData
+=pInfo
->info1
.cbData
;
239 pSerial
->cbData
+=(dwStrLen
+1)*sizeof(WCHAR
) + 4; /* str, null, size */
240 pSerial
->cbData
+=pInfo
->data0
.cbData
;
241 pSerial
->cbData
+=pInfo
->salt
.cbData
;
242 pSerial
->cbData
+=pInfo
->cipher
.cbData
;
243 pSerial
->cbData
+=pInfo
->fingerprint
.cbData
;
245 /* save the actual structure size */
246 dwStruct
= pSerial
->cbData
;
247 /* There may be a 256 byte minimum, but I can't prove it. */
248 /*if (pSerial->cbData<256) pSerial->cbData=256;*/
250 pSerial
->pbData
=LocalAlloc(LPTR
,pSerial
->cbData
);
251 if (!pSerial
->pbData
) return FALSE
;
256 serialize_dword(pInfo
->count0
,&ptr
);
257 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
260 serialize_string(pInfo
->info0
.pbData
,&ptr
,
261 pInfo
->info0
.cbData
,sizeof(BYTE
),FALSE
);
262 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
265 serialize_dword(pInfo
->count1
,&ptr
);
266 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
269 serialize_string(pInfo
->info1
.pbData
,&ptr
,
270 pInfo
->info1
.cbData
,sizeof(BYTE
),FALSE
);
271 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
274 serialize_dword(pInfo
->null0
,&ptr
);
275 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
278 serialize_string((BYTE
*)pInfo
->szDataDescr
,&ptr
,
279 (dwStrLen
+1)*sizeof(WCHAR
),sizeof(BYTE
),TRUE
);
280 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
283 serialize_dword(pInfo
->unknown0
,&ptr
);
284 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
286 serialize_dword(pInfo
->unknown1
,&ptr
);
287 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
290 serialize_string(pInfo
->data0
.pbData
,&ptr
,
291 pInfo
->data0
.cbData
,sizeof(BYTE
),TRUE
);
292 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
295 serialize_dword(pInfo
->null1
,&ptr
);
296 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
299 serialize_dword(pInfo
->unknown2
,&ptr
);
300 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
302 serialize_dword(pInfo
->unknown3
,&ptr
);
303 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
306 serialize_string(pInfo
->salt
.pbData
,&ptr
,
307 pInfo
->salt
.cbData
,sizeof(BYTE
),TRUE
);
308 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
311 serialize_string(pInfo
->cipher
.pbData
,&ptr
,
312 pInfo
->cipher
.cbData
,sizeof(BYTE
),TRUE
);
313 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
316 serialize_string(pInfo
->fingerprint
.pbData
,&ptr
,
317 pInfo
->fingerprint
.cbData
,sizeof(BYTE
),TRUE
);
318 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
320 if (ptr
- pSerial
->pbData
!= dwStruct
)
322 ERR("struct size changed!? %u != expected %u\n",
323 ptr
- pSerial
->pbData
, (unsigned int)dwStruct
);
324 LocalFree(pSerial
->pbData
);
325 pSerial
->pbData
=NULL
;
334 BOOL
unserialize(DATA_BLOB
* pSerial
, struct protect_data_t
* pInfo
)
343 if (!pInfo
|| !pSerial
|| !pSerial
->pbData
)
348 size
=pSerial
->cbData
;
351 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->count0
))
353 ERR("reading count0 failed!\n");
358 if (!unserialize_string(ptr
,&index
,size
,16,sizeof(BYTE
),FALSE
,
359 &pInfo
->info0
.pbData
, &pInfo
->info0
.cbData
))
361 ERR("reading info0 failed!\n");
366 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->count1
))
368 ERR("reading count1 failed!\n");
373 if (!unserialize_string(ptr
,&index
,size
,16,sizeof(BYTE
),FALSE
,
374 &pInfo
->info1
.pbData
, &pInfo
->info1
.cbData
))
376 ERR("reading info1 failed!\n");
381 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->null0
))
383 ERR("reading null0 failed!\n");
388 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
389 (BYTE
**)&pInfo
->szDataDescr
, NULL
))
391 ERR("reading szDataDescr failed!\n");
396 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown0
))
398 ERR("reading unknown0 failed!\n");
403 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown1
))
405 ERR("reading unknown1 failed!\n");
410 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
411 &pInfo
->data0
.pbData
, &pInfo
->data0
.cbData
))
413 ERR("reading data0 failed!\n");
418 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->null1
))
420 ERR("reading null1 failed!\n");
425 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown2
))
427 ERR("reading unknown2 failed!\n");
432 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown3
))
434 ERR("reading unknown3 failed!\n");
439 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
440 &pInfo
->salt
.pbData
, &pInfo
->salt
.cbData
))
442 ERR("reading salt failed!\n");
447 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
448 &pInfo
->cipher
.pbData
, &pInfo
->cipher
.cbData
))
450 ERR("reading cipher failed!\n");
455 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
456 &pInfo
->fingerprint
.pbData
, &pInfo
->fingerprint
.cbData
))
458 ERR("reading fingerprint failed!\n");
462 /* allow structure size to be too big (since some applications
463 * will pad this up to 256 bytes, it seems) */
466 /* this is an impossible-to-reach test, but if the padding
467 * issue is ever understood, this may become more useful */
468 ERR("loaded corrupt structure! (used %u expected %u)\n",
469 (unsigned int)index
, (unsigned int)size
);
476 /* perform sanity checks */
478 BOOL
valid_protect_data(struct protect_data_t
* pInfo
)
484 if (pInfo
->count0
!= 0x0001)
486 ERR("count0 != 0x0001 !\n");
489 if (pInfo
->count1
!= 0x0001)
491 ERR("count0 != 0x0001 !\n");
494 if (pInfo
->null0
!= 0x0000)
496 ERR("null0 != 0x0000 !\n");
499 if (pInfo
->null1
!= 0x0000)
501 ERR("null1 != 0x0000 !\n");
504 /* since we have no idea what info0 is used for, and it seems
505 * rather constant, we can test for a Wine-specific magic string
506 * there to be reasonably sure we're using data created by the Wine
507 * implementation of CryptProtectData.
509 if (pInfo
->info0
.cbData
!=strlen(crypt_magic_str
)+1 ||
510 strcmp( (LPCSTR
)pInfo
->info0
.pbData
,crypt_magic_str
) != 0)
512 ERR("info0 magic value not matched !\n");
518 ERR("unrecognized CryptProtectData block\n");
525 void free_protect_data(struct protect_data_t
* pInfo
)
531 if (pInfo
->info0
.pbData
)
532 CryptMemFree(pInfo
->info0
.pbData
);
533 if (pInfo
->info1
.pbData
)
534 CryptMemFree(pInfo
->info1
.pbData
);
535 if (pInfo
->szDataDescr
)
536 CryptMemFree(pInfo
->szDataDescr
);
537 if (pInfo
->data0
.pbData
)
538 CryptMemFree(pInfo
->data0
.pbData
);
539 if (pInfo
->salt
.pbData
)
540 CryptMemFree(pInfo
->salt
.pbData
);
541 if (pInfo
->cipher
.pbData
)
542 CryptMemFree(pInfo
->cipher
.pbData
);
543 if (pInfo
->fingerprint
.pbData
)
544 CryptMemFree(pInfo
->fingerprint
.pbData
);
547 /* copies a string into a data blob */
549 BYTE
* convert_str_to_blob(char* str
, DATA_BLOB
* blob
)
551 if (!str
|| !blob
) return NULL
;
553 blob
->cbData
=strlen(str
)+1;
554 if (!(blob
->pbData
=CryptMemAlloc(blob
->cbData
)))
559 strcpy((LPSTR
)blob
->pbData
, str
);
566 * Populates everything except "cipher" and "fingerprint".
569 BOOL
fill_protect_data(struct protect_data_t
* pInfo
, LPCWSTR szDataDescr
,
576 if (!pInfo
) return FALSE
;
578 dwStrLen
=lstrlenW(szDataDescr
);
580 memset(pInfo
,0,sizeof(*pInfo
));
582 pInfo
->count0
=0x0001;
584 convert_str_to_blob((char*)crypt_magic_str
,&pInfo
->info0
);
586 pInfo
->count1
=0x0001;
588 convert_str_to_blob((char*)crypt_magic_str
,&pInfo
->info1
);
592 if ((pInfo
->szDataDescr
=CryptMemAlloc((dwStrLen
+1)*sizeof(WCHAR
))))
594 memcpy(pInfo
->szDataDescr
,szDataDescr
,(dwStrLen
+1)*sizeof(WCHAR
));
597 pInfo
->unknown0
=0x0000;
598 pInfo
->unknown1
=0x0000;
600 convert_str_to_blob((char*)crypt_magic_str
,&pInfo
->data0
);
603 pInfo
->unknown2
=0x0000;
604 pInfo
->unknown3
=0x0000;
606 /* allocate memory to hold a salt */
607 pInfo
->salt
.cbData
=CRYPT32_PROTECTDATA_SALT_LEN
;
608 if ((pInfo
->salt
.pbData
=CryptMemAlloc(pInfo
->salt
.cbData
)))
610 /* generate random salt */
611 if (!CryptGenRandom(hProv
, pInfo
->salt
.cbData
, pInfo
->salt
.pbData
))
613 ERR("CryptGenRandom\n");
614 free_protect_data(pInfo
);
619 /* debug: show our salt */
620 TRACE_DATA_BLOB(&pInfo
->salt
);
622 pInfo
->cipher
.cbData
=0;
623 pInfo
->cipher
.pbData
=NULL
;
625 pInfo
->fingerprint
.cbData
=0;
626 pInfo
->fingerprint
.pbData
=NULL
;
628 /* check all the allocations at once */
629 if (!pInfo
->info0
.pbData
||
630 !pInfo
->info1
.pbData
||
631 !pInfo
->szDataDescr
||
632 !pInfo
->data0
.pbData
||
636 ERR("could not allocate protect_data structures\n");
637 free_protect_data(pInfo
);
645 BOOL
convert_hash_to_blob(HCRYPTHASH hHash
, DATA_BLOB
* blob
)
651 if (!blob
) return FALSE
;
653 dwSize
=sizeof(DWORD
);
654 if (!CryptGetHashParam(hHash
, HP_HASHSIZE
, (BYTE
*)&blob
->cbData
,
657 ERR("failed to get hash size\n");
661 if (!(blob
->pbData
=CryptMemAlloc(blob
->cbData
)))
663 ERR("failed to allocate blob memory\n");
668 if (!CryptGetHashParam(hHash
, HP_HASHVAL
, blob
->pbData
, &dwSize
, 0))
670 ERR("failed to get hash value\n");
671 CryptMemFree(blob
->pbData
);
680 /* test that a given hash matches an exported-to-blob hash value */
682 BOOL
hash_matches_blob(HCRYPTHASH hHash
, DATA_BLOB
* two
)
687 if (!two
|| !two
->pbData
) return FALSE
;
689 if (!convert_hash_to_blob(hHash
,&one
)) {
693 if ( one
.cbData
== two
->cbData
&&
694 memcmp( one
.pbData
, two
->pbData
, one
.cbData
) == 0 )
699 CryptMemFree(one
.pbData
);
703 /* create an encryption key from a given salt and optional entropy */
705 BOOL
load_encryption_key(HCRYPTPROV hProv
, DATA_BLOB
* salt
,
706 DATA_BLOB
* pOptionalEntropy
, HCRYPTKEY
* phKey
)
709 HCRYPTHASH hSaltHash
;
710 char * szUsername
= NULL
;
714 /* create hash for salt */
715 if (!salt
|| !phKey
||
716 !CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hSaltHash
))
718 ERR("CryptCreateHash\n");
722 /* This should be the "logon credentials" instead of username */
723 dwError
=GetLastError();
725 if (!GetUserNameA(NULL
,&dwUsernameLen
) &&
726 GetLastError()==ERROR_MORE_DATA
&& dwUsernameLen
&&
727 (szUsername
= CryptMemAlloc(dwUsernameLen
)))
730 GetUserNameA( szUsername
, &dwUsernameLen
);
732 SetLastError(dwError
);
734 /* salt the hash with:
736 * - an "internal secret"
737 * - randomness (from the salt)
738 * - user-supplied entropy
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)))
748 ERR("CryptHashData\n");
752 /* produce a symmetric key */
753 if (rc
&& !CryptDeriveKey(hProv
,CRYPT32_PROTECTDATA_KEY_CALG
,
754 hSaltHash
,CRYPT_EXPORTABLE
,phKey
))
756 ERR("CryptDeriveKey\n");
761 CryptDestroyHash(hSaltHash
);
762 if (szUsername
) CryptMemFree(szUsername
);
767 /* debugging tool to print the structures of a ProtectData call */
769 report(DATA_BLOB
* pDataIn
, DATA_BLOB
* pOptionalEntropy
,
770 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
, DWORD dwFlags
)
772 TRACE("pPromptStruct: %p\n", pPromptStruct
);
775 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct
->cbSize
);
776 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)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
)
783 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags
);
784 TRACE_DATA_BLOB(pDataIn
);
785 if (pOptionalEntropy
)
787 TRACE_DATA_BLOB(pOptionalEntropy
);
788 TRACE(" %s\n",debugstr_an((LPCSTR
)pOptionalEntropy
->pbData
,pOptionalEntropy
->cbData
));
794 /***************************************************************************
795 * CryptProtectData [CRYPT32.@]
797 * Generate Cipher data from given Plain and Entropy data.
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
809 * TRUE If a Cipher was generated.
810 * FALSE If something failed and no Cipher is available.
813 * The true Windows encryption and keying mechanisms are unknown.
815 * dwFlags and pPromptStruct are currently ignored.
818 * Memory allocated in pDataOut must be freed with LocalFree.
821 BOOL WINAPI
CryptProtectData(DATA_BLOB
* pDataIn
,
823 DATA_BLOB
* pOptionalEntropy
,
825 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
,
832 struct protect_data_t protect_data
;
839 SetLastError(ERROR_SUCCESS
);
841 if (!pDataIn
|| !pDataOut
)
843 SetLastError(ERROR_INVALID_PARAMETER
);
847 /* debug: show our arguments */
848 report(pDataIn
,pOptionalEntropy
,pPromptStruct
,dwFlags
);
849 TRACE("\tszDataDescr: %p %s\n", szDataDescr
,
850 szDataDescr
? debugstr_w(szDataDescr
) : "");
852 /* Windows appears to create an empty szDataDescr instead of maintaining
855 szDataDescr
=(WCHAR
[]){'\0'};
857 /* get crypt context */
858 if (!CryptAcquireContextW(&hProv
,NULL
,NULL
,CRYPT32_PROTECTDATA_PROV
,CRYPT_VERIFYCONTEXT
))
860 ERR("CryptAcquireContextW failed\n");
864 /* populate our structure */
865 if (!fill_protect_data(&protect_data
,szDataDescr
,hProv
))
867 ERR("fill_protect_data\n");
872 if (!load_encryption_key(hProv
,&protect_data
.salt
,pOptionalEntropy
,&hKey
))
874 goto free_protect_data
;
877 /* create a hash for the encryption validation */
878 if (!CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hHash
))
880 ERR("CryptCreateHash\n");
884 /* calculate storage required */
885 dwLength
=pDataIn
->cbData
;
886 if (CryptEncrypt(hKey
, 0, TRUE
, 0, pDataIn
->pbData
, &dwLength
, 0) ||
887 GetLastError()!=ERROR_MORE_DATA
)
889 ERR("CryptEncrypt\n");
892 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength
);
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
)))
899 ERR("CryptMemAlloc\n");
902 memcpy(protect_data
.cipher
.pbData
,pDataIn
->pbData
,pDataIn
->cbData
);
905 dwLength
=pDataIn
->cbData
;
906 if (!CryptEncrypt(hKey
, hHash
, TRUE
, 0, protect_data
.cipher
.pbData
,
907 &dwLength
, protect_data
.cipher
.cbData
))
909 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
912 protect_data
.cipher
.cbData
=dwLength
;
914 /* debug: show the cipher */
915 TRACE_DATA_BLOB(&protect_data
.cipher
);
917 /* attach our fingerprint */
918 if (!convert_hash_to_blob(hHash
, &protect_data
.fingerprint
))
920 ERR("convert_hash_to_blob\n");
924 /* serialize into an opaque blob */
925 if (!serialize(&protect_data
, pDataOut
))
935 CryptDestroyHash(hHash
);
937 CryptDestroyKey(hKey
);
939 free_protect_data(&protect_data
);
941 CryptReleaseContext(hProv
,0);
943 /* If some error occurred, and no error code was set, force one. */
944 if (!rc
&& GetLastError()==ERROR_SUCCESS
)
946 SetLastError(ERROR_INVALID_DATA
);
951 SetLastError(ERROR_SUCCESS
);
953 TRACE_DATA_BLOB(pDataOut
);
956 TRACE("returning %s\n", rc
? "ok" : "FAIL");
962 /***************************************************************************
963 * CryptUnprotectData [CRYPT32.@]
965 * Generate Plain data and Description from given Cipher and Entropy data.
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
977 * TRUE If a Plain was generated.
978 * FALSE If something failed and no Plain is available.
981 * The true Windows encryption and keying mechanisms are unknown.
983 * dwFlags and pPromptStruct are currently ignored.
986 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
990 BOOL WINAPI
CryptUnprotectData(DATA_BLOB
* pDataIn
,
991 LPWSTR
* ppszDataDescr
,
992 DATA_BLOB
* pOptionalEntropy
,
994 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
,
1001 struct protect_data_t protect_data
;
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.";
1010 SetLastError(ERROR_SUCCESS
);
1012 if (!pDataIn
|| !pDataOut
)
1014 SetLastError(ERROR_INVALID_PARAMETER
);
1018 /* debug: show our arguments */
1019 report(pDataIn
,pOptionalEntropy
,pPromptStruct
,dwFlags
);
1020 TRACE("\tppszDataDescr: %p\n", ppszDataDescr
);
1022 /* take apart the opaque blob */
1023 if (!unserialize(pDataIn
, &protect_data
))
1025 SetLastError(ERROR_INVALID_DATA
);
1026 FIXME("%s\n",announce_bad_opaque_data
);
1030 /* perform basic validation on the resulting structure */
1031 if (!valid_protect_data(&protect_data
))
1033 SetLastError(ERROR_INVALID_DATA
);
1034 FIXME("%s\n",announce_bad_opaque_data
);
1035 goto free_protect_data
;
1038 /* get a crypt context */
1039 if (!CryptAcquireContextW(&hProv
,NULL
,NULL
,CRYPT32_PROTECTDATA_PROV
,CRYPT_VERIFYCONTEXT
))
1041 ERR("CryptAcquireContextW failed\n");
1042 goto free_protect_data
;
1046 if (!load_encryption_key(hProv
,&protect_data
.salt
,pOptionalEntropy
,&hKey
))
1051 /* create a hash for the decryption validation */
1052 if (!CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hHash
))
1054 ERR("CryptCreateHash\n");
1058 /* prepare for plaintext */
1059 pDataOut
->cbData
=protect_data
.cipher
.cbData
;
1060 if (!(pDataOut
->pbData
=LocalAlloc( LPTR
, pDataOut
->cbData
)))
1062 ERR("CryptMemAlloc\n");
1065 memcpy(pDataOut
->pbData
,protect_data
.cipher
.pbData
,protect_data
.cipher
.cbData
);
1068 if (!CryptDecrypt(hKey
, hHash
, TRUE
, 0, pDataOut
->pbData
,
1069 &pDataOut
->cbData
) ||
1070 /* check the hash fingerprint */
1071 pDataOut
->cbData
> protect_data
.cipher
.cbData
||
1072 !hash_matches_blob(hHash
, &protect_data
.fingerprint
))
1074 SetLastError(ERROR_INVALID_DATA
);
1076 LocalFree( pDataOut
->pbData
);
1077 pDataOut
->pbData
= NULL
;
1078 pDataOut
->cbData
= 0;
1083 /* Copy out the description */
1084 dwLength
= (lstrlenW(protect_data
.szDataDescr
)+1) * sizeof(WCHAR
);
1087 if (!(*ppszDataDescr
= LocalAlloc(LPTR
,dwLength
)))
1089 ERR("LocalAlloc (ppszDataDescr)\n");
1093 memcpy(*ppszDataDescr
,protect_data
.szDataDescr
,dwLength
);
1101 CryptDestroyHash(hHash
);
1103 CryptDestroyKey(hKey
);
1105 CryptReleaseContext(hProv
,0);
1107 free_protect_data(&protect_data
);
1109 /* If some error occurred, and no error code was set, force one. */
1110 if (!rc
&& GetLastError()==ERROR_SUCCESS
)
1112 SetLastError(ERROR_INVALID_DATA
);
1116 SetLastError(ERROR_SUCCESS
);
1120 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr
));
1122 TRACE_DATA_BLOB(pDataOut
);
1125 TRACE("returning %s\n", rc
? "ok" : "FAIL");