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.
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?)
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.
95 DATA_BLOB info0
; /* using this to hold crypt_magic_str */
99 WCHAR
* szDataDescr
; /* serialized differently than the DATA_BLOBs */
101 DWORD cipher_key_len
;
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 */
116 hex_str(const unsigned char *p
, int n
)
122 ptr
= wine_dbg_sprintf("%s","");
127 ptr
= wine_dbg_sprintf("%s%s",ptr
,report
);
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)); \
142 void serialize_dword(DWORD value
,BYTE
** ptr
)
144 /*TRACE("called\n");*/
146 memcpy(*ptr
,&value
,sizeof(DWORD
));
151 void serialize_string(const BYTE
*str
, BYTE
**ptr
, DWORD len
, DWORD width
,
154 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
158 serialize_dword(len
,ptr
);
160 memcpy(*ptr
,str
,len
*width
);
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
)
176 memcpy(value
,&(ptr
[*index
]),sizeof(DWORD
));
177 *index
+=sizeof(DWORD
);
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
;
192 if (!unserialize_dword(ptr
,index
,size
,&len
))
196 if (*index
+len
*width
>size
)
201 if (!(*data
= CryptMemAlloc( len
*width
)))
206 memcpy(*data
,&(ptr
[*index
]),len
*width
);
217 BOOL
serialize(const struct protect_data_t
*pInfo
, DATA_BLOB
*pSerial
)
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
)
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
);
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
;
267 serialize_dword(pInfo
->count0
,&ptr
);
268 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
271 serialize_string(pInfo
->info0
.pbData
,&ptr
,
272 pInfo
->info0
.cbData
,sizeof(BYTE
),FALSE
);
273 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
276 serialize_dword(pInfo
->count1
,&ptr
);
277 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
280 serialize_string(pInfo
->info1
.pbData
,&ptr
,
281 pInfo
->info1
.cbData
,sizeof(BYTE
),FALSE
);
282 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
285 serialize_dword(pInfo
->null0
,&ptr
);
286 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
289 serialize_string((BYTE
*)pInfo
->szDataDescr
,&ptr
,
290 (dwStrLen
+1)*sizeof(WCHAR
),sizeof(BYTE
),TRUE
);
291 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
294 serialize_dword(pInfo
->cipher_alg
,&ptr
);
295 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
297 serialize_dword(pInfo
->cipher_key_len
,&ptr
);
298 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
301 serialize_string(pInfo
->data0
.pbData
,&ptr
,
302 pInfo
->data0
.cbData
,sizeof(BYTE
),TRUE
);
303 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
306 serialize_dword(pInfo
->null1
,&ptr
);
307 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
310 serialize_dword(pInfo
->hash_alg
,&ptr
);
311 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
313 serialize_dword(pInfo
->hash_len
,&ptr
);
314 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
317 serialize_string(pInfo
->salt
.pbData
,&ptr
,
318 pInfo
->salt
.cbData
,sizeof(BYTE
),TRUE
);
319 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
322 serialize_string(pInfo
->cipher
.pbData
,&ptr
,
323 pInfo
->cipher
.cbData
,sizeof(BYTE
),TRUE
);
324 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
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
, dwStruct
);
335 LocalFree(pSerial
->pbData
);
336 pSerial
->pbData
=NULL
;
345 BOOL
unserialize(const DATA_BLOB
*pSerial
, struct protect_data_t
*pInfo
)
354 if (!pInfo
|| !pSerial
|| !pSerial
->pbData
)
359 size
=pSerial
->cbData
;
362 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->count0
))
364 ERR("reading count0 failed!\n");
369 if (!unserialize_string(ptr
,&index
,size
,16,sizeof(BYTE
),FALSE
,
370 &pInfo
->info0
.pbData
, &pInfo
->info0
.cbData
))
372 ERR("reading info0 failed!\n");
377 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->count1
))
379 ERR("reading count1 failed!\n");
384 if (!unserialize_string(ptr
,&index
,size
,16,sizeof(BYTE
),FALSE
,
385 &pInfo
->info1
.pbData
, &pInfo
->info1
.cbData
))
387 ERR("reading info1 failed!\n");
392 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->null0
))
394 ERR("reading null0 failed!\n");
399 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
400 (BYTE
**)&pInfo
->szDataDescr
, NULL
))
402 ERR("reading szDataDescr failed!\n");
407 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->cipher_alg
))
409 ERR("reading cipher_alg failed!\n");
414 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->cipher_key_len
))
416 ERR("reading cipher_key_len failed!\n");
421 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
422 &pInfo
->data0
.pbData
, &pInfo
->data0
.cbData
))
424 ERR("reading data0 failed!\n");
429 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->null1
))
431 ERR("reading null1 failed!\n");
436 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->hash_alg
))
438 ERR("reading hash_alg failed!\n");
443 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->hash_len
))
445 ERR("reading hash_len failed!\n");
450 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
451 &pInfo
->salt
.pbData
, &pInfo
->salt
.cbData
))
453 ERR("reading salt failed!\n");
458 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
459 &pInfo
->cipher
.pbData
, &pInfo
->cipher
.cbData
))
461 ERR("reading cipher failed!\n");
466 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
467 &pInfo
->fingerprint
.pbData
, &pInfo
->fingerprint
.cbData
))
469 ERR("reading fingerprint failed!\n");
473 /* allow structure size to be too big (since some applications
474 * will pad this up to 256 bytes, it seems) */
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", index
, size
);
486 /* perform sanity checks */
488 BOOL
valid_protect_data(const struct protect_data_t
*pInfo
)
494 if (pInfo
->count0
!= 0x0001)
496 ERR("count0 != 0x0001 !\n");
499 if (pInfo
->count1
!= 0x0001)
501 ERR("count0 != 0x0001 !\n");
504 if (pInfo
->null0
!= 0x0000)
506 ERR("null0 != 0x0000 !\n");
509 if (pInfo
->null1
!= 0x0000)
511 ERR("null1 != 0x0000 !\n");
514 /* since we have no idea what info0 is used for, and it seems
515 * rather constant, we can test for a Wine-specific magic string
516 * there to be reasonably sure we're using data created by the Wine
517 * implementation of CryptProtectData.
519 if (pInfo
->info0
.cbData
!=strlen(crypt_magic_str
)+1 ||
520 strcmp( (LPCSTR
)pInfo
->info0
.pbData
,crypt_magic_str
) != 0)
522 ERR("info0 magic value not matched !\n");
528 ERR("unrecognized CryptProtectData block\n");
535 void free_protect_data(struct protect_data_t
* pInfo
)
541 CryptMemFree(pInfo
->info0
.pbData
);
542 CryptMemFree(pInfo
->info1
.pbData
);
543 CryptMemFree(pInfo
->szDataDescr
);
544 CryptMemFree(pInfo
->data0
.pbData
);
545 CryptMemFree(pInfo
->salt
.pbData
);
546 CryptMemFree(pInfo
->cipher
.pbData
);
547 CryptMemFree(pInfo
->fingerprint
.pbData
);
550 /* copies a string into a data blob */
552 BYTE
*convert_str_to_blob(LPCSTR str
, DATA_BLOB
*blob
)
554 if (!str
|| !blob
) return NULL
;
556 blob
->cbData
=strlen(str
)+1;
557 if (!(blob
->pbData
=CryptMemAlloc(blob
->cbData
)))
562 strcpy((LPSTR
)blob
->pbData
, str
);
569 * Populates everything except "cipher" and "fingerprint".
572 BOOL
fill_protect_data(struct protect_data_t
* pInfo
, LPCWSTR szDataDescr
,
579 if (!pInfo
) return FALSE
;
581 dwStrLen
=lstrlenW(szDataDescr
);
583 memset(pInfo
,0,sizeof(*pInfo
));
585 pInfo
->count0
=0x0001;
587 convert_str_to_blob(crypt_magic_str
, &pInfo
->info0
);
589 pInfo
->count1
=0x0001;
591 convert_str_to_blob(crypt_magic_str
, &pInfo
->info1
);
595 if ((pInfo
->szDataDescr
=CryptMemAlloc((dwStrLen
+1)*sizeof(WCHAR
))))
597 memcpy(pInfo
->szDataDescr
,szDataDescr
,(dwStrLen
+1)*sizeof(WCHAR
));
600 pInfo
->cipher_alg
=CRYPT32_PROTECTDATA_KEY_CALG
;
601 pInfo
->cipher_key_len
=CRYPT32_PROTECTDATA_KEY_LEN
;
603 convert_str_to_blob(crypt_magic_str
, &pInfo
->data0
);
606 pInfo
->hash_alg
=CRYPT32_PROTECTDATA_HASH_CALG
;
607 pInfo
->hash_len
=CRYPT32_PROTECTDATA_HASH_LEN
;
609 /* allocate memory to hold a salt */
610 pInfo
->salt
.cbData
=CRYPT32_PROTECTDATA_SALT_LEN
;
611 if ((pInfo
->salt
.pbData
=CryptMemAlloc(pInfo
->salt
.cbData
)))
613 /* generate random salt */
614 if (!CryptGenRandom(hProv
, pInfo
->salt
.cbData
, pInfo
->salt
.pbData
))
616 ERR("CryptGenRandom\n");
617 free_protect_data(pInfo
);
622 /* debug: show our salt */
623 TRACE_DATA_BLOB(&pInfo
->salt
);
625 pInfo
->cipher
.cbData
=0;
626 pInfo
->cipher
.pbData
=NULL
;
628 pInfo
->fingerprint
.cbData
=0;
629 pInfo
->fingerprint
.pbData
=NULL
;
631 /* check all the allocations at once */
632 if (!pInfo
->info0
.pbData
||
633 !pInfo
->info1
.pbData
||
634 !pInfo
->szDataDescr
||
635 !pInfo
->data0
.pbData
||
639 ERR("could not allocate protect_data structures\n");
640 free_protect_data(pInfo
);
648 BOOL
convert_hash_to_blob(HCRYPTHASH hHash
, DATA_BLOB
* blob
)
654 if (!blob
) return FALSE
;
656 dwSize
=sizeof(DWORD
);
657 if (!CryptGetHashParam(hHash
, HP_HASHSIZE
, (BYTE
*)&blob
->cbData
,
660 ERR("failed to get hash size\n");
664 if (!(blob
->pbData
=CryptMemAlloc(blob
->cbData
)))
666 ERR("failed to allocate blob memory\n");
671 if (!CryptGetHashParam(hHash
, HP_HASHVAL
, blob
->pbData
, &dwSize
, 0))
673 ERR("failed to get hash value\n");
674 CryptMemFree(blob
->pbData
);
683 /* test that a given hash matches an exported-to-blob hash value */
685 BOOL
hash_matches_blob(HCRYPTHASH hHash
, const DATA_BLOB
*two
)
690 if (!two
|| !two
->pbData
) return FALSE
;
692 if (!convert_hash_to_blob(hHash
,&one
)) {
696 if ( one
.cbData
== two
->cbData
&&
697 memcmp( one
.pbData
, two
->pbData
, one
.cbData
) == 0 )
702 CryptMemFree(one
.pbData
);
706 /* create an encryption key from a given salt and optional entropy */
708 BOOL
load_encryption_key(HCRYPTPROV hProv
, DWORD key_len
, const DATA_BLOB
*salt
,
709 const DATA_BLOB
*pOptionalEntropy
, HCRYPTKEY
*phKey
)
712 HCRYPTHASH hSaltHash
;
713 char * szUsername
= NULL
;
717 /* create hash for salt */
718 if (!salt
|| !phKey
||
719 !CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hSaltHash
))
721 ERR("CryptCreateHash\n");
725 /* This should be the "logon credentials" instead of username */
726 dwError
=GetLastError();
728 if (!GetUserNameA(NULL
,&dwUsernameLen
) &&
729 GetLastError()==ERROR_MORE_DATA
&& dwUsernameLen
&&
730 (szUsername
= CryptMemAlloc(dwUsernameLen
)))
733 GetUserNameA( szUsername
, &dwUsernameLen
);
735 SetLastError(dwError
);
737 /* salt the hash with:
739 * - an "internal secret"
740 * - randomness (from the salt)
741 * - user-supplied entropy
743 if ((szUsername
&& !CryptHashData(hSaltHash
,(LPBYTE
)szUsername
,dwUsernameLen
,0)) ||
744 !CryptHashData(hSaltHash
,crypt32_protectdata_secret
,
745 sizeof(crypt32_protectdata_secret
)-1,0) ||
746 !CryptHashData(hSaltHash
,salt
->pbData
,salt
->cbData
,0) ||
747 (pOptionalEntropy
&& !CryptHashData(hSaltHash
,
748 pOptionalEntropy
->pbData
,
749 pOptionalEntropy
->cbData
,0)))
751 ERR("CryptHashData\n");
755 /* produce a symmetric key */
756 if (rc
&& !CryptDeriveKey(hProv
,CRYPT32_PROTECTDATA_KEY_CALG
,
757 hSaltHash
,key_len
<< 16 | CRYPT_EXPORTABLE
,phKey
))
759 ERR("CryptDeriveKey\n");
764 CryptDestroyHash(hSaltHash
);
765 CryptMemFree(szUsername
);
770 /* debugging tool to print the structures of a ProtectData call */
772 report(const DATA_BLOB
* pDataIn
, const DATA_BLOB
* pOptionalEntropy
,
773 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
, DWORD dwFlags
)
775 TRACE("pPromptStruct: %p\n", pPromptStruct
);
778 TRACE(" cbSize: 0x%x\n", pPromptStruct
->cbSize
);
779 TRACE(" dwPromptFlags: 0x%x\n", pPromptStruct
->dwPromptFlags
);
780 TRACE(" hwndApp: %p\n", pPromptStruct
->hwndApp
);
781 TRACE(" szPrompt: %p %s\n",
782 pPromptStruct
->szPrompt
,
783 pPromptStruct
->szPrompt
? debugstr_w(pPromptStruct
->szPrompt
)
786 TRACE("dwFlags: 0x%04x\n", dwFlags
);
787 TRACE_DATA_BLOB(pDataIn
);
788 if (pOptionalEntropy
)
790 TRACE_DATA_BLOB(pOptionalEntropy
);
791 TRACE(" %s\n",debugstr_an((LPCSTR
)pOptionalEntropy
->pbData
,pOptionalEntropy
->cbData
));
797 /***************************************************************************
798 * CryptProtectData [CRYPT32.@]
800 * Generate Cipher data from given Plain and Entropy data.
803 * pDataIn [I] Plain data to be enciphered
804 * szDataDescr [I] Optional Unicode string describing the Plain data
805 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
806 * pvReserved [I] Reserved, must be NULL
807 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
808 * dwFlags [I] Flags describing options to the ciphering
809 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
812 * TRUE If a Cipher was generated.
813 * FALSE If something failed and no Cipher is available.
816 * The true Windows encryption and keying mechanisms are unknown.
818 * dwFlags and pPromptStruct are currently ignored.
821 * Memory allocated in pDataOut must be freed with LocalFree.
824 BOOL WINAPI
CryptProtectData(DATA_BLOB
* pDataIn
,
826 DATA_BLOB
* pOptionalEntropy
,
828 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
,
832 static const WCHAR empty_str
[1];
835 struct protect_data_t protect_data
;
842 SetLastError(ERROR_SUCCESS
);
844 if (!pDataIn
|| !pDataOut
)
846 SetLastError(ERROR_INVALID_PARAMETER
);
850 /* debug: show our arguments */
851 report(pDataIn
,pOptionalEntropy
,pPromptStruct
,dwFlags
);
852 TRACE("\tszDataDescr: %p %s\n", szDataDescr
,
853 szDataDescr
? debugstr_w(szDataDescr
) : "");
855 /* Windows appears to create an empty szDataDescr instead of maintaining
858 szDataDescr
= empty_str
;
860 /* get crypt context */
861 if (!CryptAcquireContextW(&hProv
,NULL
,MS_ENHANCED_PROV_W
,CRYPT32_PROTECTDATA_PROV
,CRYPT_VERIFYCONTEXT
))
863 ERR("CryptAcquireContextW failed\n");
867 /* populate our structure */
868 if (!fill_protect_data(&protect_data
,szDataDescr
,hProv
))
870 ERR("fill_protect_data\n");
875 if (!load_encryption_key(hProv
,protect_data
.cipher_key_len
,&protect_data
.salt
,pOptionalEntropy
,&hKey
))
877 goto free_protect_data
;
880 /* create a hash for the encryption validation */
881 if (!CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hHash
))
883 ERR("CryptCreateHash\n");
887 /* calculate storage required */
888 dwLength
=pDataIn
->cbData
;
889 if (CryptEncrypt(hKey
, 0, TRUE
, 0, pDataIn
->pbData
, &dwLength
, 0) ||
890 GetLastError()!=ERROR_MORE_DATA
)
892 ERR("CryptEncrypt\n");
895 TRACE("required encrypted storage: %u\n", dwLength
);
897 /* copy plain text into cipher area for CryptEncrypt call */
898 protect_data
.cipher
.cbData
=dwLength
;
899 if (!(protect_data
.cipher
.pbData
=CryptMemAlloc(
900 protect_data
.cipher
.cbData
)))
902 ERR("CryptMemAlloc\n");
905 memcpy(protect_data
.cipher
.pbData
,pDataIn
->pbData
,pDataIn
->cbData
);
908 dwLength
=pDataIn
->cbData
;
909 if (!CryptEncrypt(hKey
, hHash
, TRUE
, 0, protect_data
.cipher
.pbData
,
910 &dwLength
, protect_data
.cipher
.cbData
))
912 ERR("CryptEncrypt %u\n", GetLastError());
915 protect_data
.cipher
.cbData
=dwLength
;
917 /* debug: show the cipher */
918 TRACE_DATA_BLOB(&protect_data
.cipher
);
920 /* attach our fingerprint */
921 if (!convert_hash_to_blob(hHash
, &protect_data
.fingerprint
))
923 ERR("convert_hash_to_blob\n");
927 /* serialize into an opaque blob */
928 if (!serialize(&protect_data
, pDataOut
))
938 CryptDestroyHash(hHash
);
940 CryptDestroyKey(hKey
);
942 free_protect_data(&protect_data
);
944 CryptReleaseContext(hProv
,0);
946 /* If some error occurred, and no error code was set, force one. */
947 if (!rc
&& GetLastError()==ERROR_SUCCESS
)
949 SetLastError(ERROR_INVALID_DATA
);
954 SetLastError(ERROR_SUCCESS
);
956 TRACE_DATA_BLOB(pDataOut
);
959 TRACE("returning %s\n", rc
? "ok" : "FAIL");
965 /***************************************************************************
966 * CryptUnprotectData [CRYPT32.@]
968 * Generate Plain data and Description from given Cipher and Entropy data.
971 * pDataIn [I] Cipher data to be decoded
972 * ppszDataDescr [O] Optional Unicode string describing the Plain data
973 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
974 * pvReserved [I] Reserved, must be NULL
975 * pPromptStruct [I] Structure describing if/how to prompt during decoding
976 * dwFlags [I] Flags describing options to the decoding
977 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
980 * TRUE If a Plain was generated.
981 * FALSE If something failed and no Plain is available.
984 * The true Windows encryption and keying mechanisms are unknown.
986 * dwFlags and pPromptStruct are currently ignored.
989 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
993 BOOL WINAPI
CryptUnprotectData(DATA_BLOB
* pDataIn
,
994 LPWSTR
* ppszDataDescr
,
995 DATA_BLOB
* pOptionalEntropy
,
997 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
,
1004 struct protect_data_t protect_data
;
1009 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.";
1013 SetLastError(ERROR_SUCCESS
);
1015 if (!pDataIn
|| !pDataOut
)
1017 SetLastError(ERROR_INVALID_PARAMETER
);
1020 if (!pDataIn
->cbData
)
1022 SetLastError(ERROR_INVALID_DATA
);
1026 /* debug: show our arguments */
1027 report(pDataIn
,pOptionalEntropy
,pPromptStruct
,dwFlags
);
1028 TRACE("\tppszDataDescr: %p\n", ppszDataDescr
);
1030 /* take apart the opaque blob */
1031 if (!unserialize(pDataIn
, &protect_data
))
1033 SetLastError(ERROR_INVALID_DATA
);
1034 FIXME("%s\n",announce_bad_opaque_data
);
1038 /* perform basic validation on the resulting structure */
1039 if (!valid_protect_data(&protect_data
))
1041 SetLastError(ERROR_INVALID_DATA
);
1042 FIXME("%s\n",announce_bad_opaque_data
);
1043 goto free_protect_data
;
1046 /* get a crypt context */
1047 if (!CryptAcquireContextW(&hProv
,NULL
,MS_ENHANCED_PROV_W
,CRYPT32_PROTECTDATA_PROV
,CRYPT_VERIFYCONTEXT
))
1049 ERR("CryptAcquireContextW failed\n");
1050 goto free_protect_data
;
1054 if (!load_encryption_key(hProv
,protect_data
.cipher_key_len
,&protect_data
.salt
,pOptionalEntropy
,&hKey
))
1059 /* create a hash for the decryption validation */
1060 if (!CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hHash
))
1062 ERR("CryptCreateHash\n");
1066 /* prepare for plaintext */
1067 pDataOut
->cbData
=protect_data
.cipher
.cbData
;
1068 if (!(pDataOut
->pbData
=LocalAlloc( LPTR
, pDataOut
->cbData
)))
1070 ERR("CryptMemAlloc\n");
1073 memcpy(pDataOut
->pbData
,protect_data
.cipher
.pbData
,protect_data
.cipher
.cbData
);
1076 if (!CryptDecrypt(hKey
, hHash
, TRUE
, 0, pDataOut
->pbData
,
1077 &pDataOut
->cbData
) ||
1078 /* check the hash fingerprint */
1079 pDataOut
->cbData
> protect_data
.cipher
.cbData
||
1080 !hash_matches_blob(hHash
, &protect_data
.fingerprint
))
1082 SetLastError(ERROR_INVALID_DATA
);
1084 LocalFree( pDataOut
->pbData
);
1085 pDataOut
->pbData
= NULL
;
1086 pDataOut
->cbData
= 0;
1091 /* Copy out the description */
1092 dwLength
= (lstrlenW(protect_data
.szDataDescr
)+1) * sizeof(WCHAR
);
1095 if (!(*ppszDataDescr
= LocalAlloc(LPTR
,dwLength
)))
1097 ERR("LocalAlloc (ppszDataDescr)\n");
1101 memcpy(*ppszDataDescr
,protect_data
.szDataDescr
,dwLength
);
1109 CryptDestroyHash(hHash
);
1111 CryptDestroyKey(hKey
);
1113 CryptReleaseContext(hProv
,0);
1115 free_protect_data(&protect_data
);
1117 /* If some error occurred, and no error code was set, force one. */
1118 if (!rc
&& GetLastError()==ERROR_SUCCESS
)
1120 SetLastError(ERROR_INVALID_DATA
);
1124 SetLastError(ERROR_SUCCESS
);
1128 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr
));
1130 TRACE_DATA_BLOB(pDataOut
);
1133 TRACE("returning %s\n", rc
? "ok" : "FAIL");