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.
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
50 #define CRYPT32_PROTECTDATA_PROV PROV_RSA_FULL
51 #define CRYPT32_PROTECTDATA_HASH_CALG CALG_MD5
52 #define CRYPT32_PROTECTDATA_KEY_CALG CALG_RC2
53 #define CRYPT32_PROTECTDATA_SALT_LEN 16
55 #define CRYPT32_PROTECTDATA_SECRET "I'm hunting wabbits"
58 * The data format returned by the real Windows CryptProtectData seems
59 * to be something like this:
61 DWORD count0; - how many "info0_*[16]" blocks follow (was always 1)
62 BYTE info0_0[16]; - unknown information
64 DWORD count1; - how many "info1_*[16]" blocks follow (was always 1)
65 BYTE info1_0[16]; - unknown information
67 DWORD null0; - NULL "end of records"?
68 DWORD str_len; - length of WCHAR string including term
69 WCHAR str[str_len]; - The "dataDescription" value
70 DWORD unknown0; - unknown value (seems large, but only WORD large)
71 DWORD unknown1; - unknown value (seems small, less than a BYTE)
72 DWORD data_len; - length of data (was 16 in samples)
73 BYTE data[data_len]; - unknown data (fingerprint?)
75 DWORD unknown2; - unknown value (seems large, but only WORD large)
76 DWORD unknown3; - unknown value (seems small, less than a BYTE)
77 DWORD salt_len; - length of salt(?) data
78 BYTE salt[salt_len]; - salt(?) for symmetric encryption
79 DWORD cipher_len; - length of cipher(?) data - was close to plain len
80 BYTE cipher[cipher_len]; - cipher text?
81 DWORD crc_len; - length of fingerprint(?) data - was 20 byte==160b SHA1
82 BYTE crc[crc_len]; - fingerprint of record?
84 * The data structures used in Wine are modelled after this guess.
90 DATA_BLOB info0
; /* using this to hold crypt_magic_str */
94 WCHAR
* szDataDescr
; /* serialized differently than the DATA_BLOBs */
95 DWORD unknown0
; /* perhaps the HASH alg const should go here? */
99 DWORD unknown2
; /* perhaps the KEY alg const should go here? */
103 DATA_BLOB fingerprint
;
106 /* this is used to check if an incoming structure was built by Wine */
107 static const char * crypt_magic_str
= "Wine Crypt32 ok";
109 /* debugging tool to print strings of hex chars */
111 hex_str(unsigned char *p
, int n
)
117 ptr
= wine_dbg_sprintf("%s","");
122 ptr
= wine_dbg_sprintf("%s%s",ptr
,report
);
125 sprintf(report
+strlen(report
),"%s%02x", r
? "," : "", *p
++);
127 return wine_dbg_sprintf("%s%s",ptr
,report
);
130 #define TRACE_DATA_BLOB(blob) do { \
131 TRACE("%s cbData: %u\n", #blob ,(unsigned int)((blob)->cbData)); \
132 TRACE("%s pbData @ 0x%x:%s\n", #blob ,(unsigned int)((blob)->pbData), \
133 hex_str((blob)->pbData, (blob)->cbData)); \
137 void serialize_dword(DWORD value
,BYTE
** ptr
)
139 /*TRACE("called\n");*/
141 memcpy(*ptr
,&value
,sizeof(DWORD
));
146 void serialize_string(BYTE
* str
,BYTE
** ptr
,DWORD len
, DWORD width
,
149 /*TRACE("called %ux%u\n",(unsigned int)len,(unsigned int)width);*/
153 serialize_dword(len
,ptr
);
155 memcpy(*ptr
,str
,len
*width
);
160 BOOL
unserialize_dword(BYTE
* ptr
, DWORD
*index
, DWORD size
, DWORD
* value
)
162 /*TRACE("called\n");*/
164 if (!ptr
|| !index
|| !value
) return FALSE
;
166 if (*index
+sizeof(DWORD
)>size
)
171 memcpy(value
,&(ptr
[*index
]),sizeof(DWORD
));
172 *index
+=sizeof(DWORD
);
178 BOOL
unserialize_string(BYTE
* ptr
, DWORD
*index
, DWORD size
,
179 DWORD len
, DWORD width
, BOOL inline_len
,
180 BYTE
** data
, DWORD
* stored
)
182 /*TRACE("called\n");*/
184 if (!ptr
|| !data
) return FALSE
;
187 if (!unserialize_dword(ptr
,index
,size
,&len
))
191 if (*index
+len
*width
>size
)
196 if (!(*data
= HeapAlloc( GetProcessHeap(), 0, len
*width
)))
201 memcpy(*data
,&(ptr
[*index
]),len
*width
);
212 BOOL
serialize(struct protect_data_t
* pInfo
, DATA_BLOB
* pSerial
)
220 if (!pInfo
|| !pInfo
->szDataDescr
|| !pSerial
||
221 !pInfo
->info0
.pbData
|| !pInfo
->info1
.pbData
||
222 !pInfo
->data0
.pbData
|| !pInfo
->salt
.pbData
||
223 !pInfo
->cipher
.pbData
|| !pInfo
->fingerprint
.pbData
)
228 if (pInfo
->info0
.cbData
!=16)
230 ERR("protect_data_t info0 not 16 bytes long\n");
233 if (pInfo
->info1
.cbData
!=16)
235 ERR("protect_data_t info1 not 16 bytes long\n");
238 dwStrLen
=lstrlenW(pInfo
->szDataDescr
);
241 pSerial
->cbData
+=sizeof(DWORD
)*8; /* 8 raw DWORDs */
242 pSerial
->cbData
+=sizeof(DWORD
)*4; /* 4 BLOBs with size */
243 pSerial
->cbData
+=pInfo
->info0
.cbData
;
244 pSerial
->cbData
+=pInfo
->info1
.cbData
;
245 pSerial
->cbData
+=(dwStrLen
+1)*sizeof(WCHAR
) + 4; /* str, null, size */
246 pSerial
->cbData
+=pInfo
->data0
.cbData
;
247 pSerial
->cbData
+=pInfo
->salt
.cbData
;
248 pSerial
->cbData
+=pInfo
->cipher
.cbData
;
249 pSerial
->cbData
+=pInfo
->fingerprint
.cbData
;
251 /* save the actual structure size */
252 dwStruct
= pSerial
->cbData
;
253 /* There may be a 256 byte minimum, but I can't prove it. */
254 /*if (pSerial->cbData<256) pSerial->cbData=256;*/
256 pSerial
->pbData
=LocalAlloc(LPTR
,pSerial
->cbData
);
257 if (!pSerial
->pbData
) return FALSE
;
262 serialize_dword(pInfo
->count0
,&ptr
);
263 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
266 serialize_string(pInfo
->info0
.pbData
,&ptr
,
267 pInfo
->info0
.cbData
,sizeof(BYTE
),FALSE
);
268 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
271 serialize_dword(pInfo
->count1
,&ptr
);
272 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
275 serialize_string(pInfo
->info1
.pbData
,&ptr
,
276 pInfo
->info1
.cbData
,sizeof(BYTE
),FALSE
);
277 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
280 serialize_dword(pInfo
->null0
,&ptr
);
281 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
284 serialize_string((BYTE
*)pInfo
->szDataDescr
,&ptr
,
285 (dwStrLen
+1)*sizeof(WCHAR
),sizeof(BYTE
),TRUE
);
286 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
289 serialize_dword(pInfo
->unknown0
,&ptr
);
290 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
292 serialize_dword(pInfo
->unknown1
,&ptr
);
293 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
296 serialize_string(pInfo
->data0
.pbData
,&ptr
,
297 pInfo
->data0
.cbData
,sizeof(BYTE
),TRUE
);
298 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
301 serialize_dword(pInfo
->null1
,&ptr
);
302 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
305 serialize_dword(pInfo
->unknown2
,&ptr
);
306 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
308 serialize_dword(pInfo
->unknown3
,&ptr
);
309 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
312 serialize_string(pInfo
->salt
.pbData
,&ptr
,
313 pInfo
->salt
.cbData
,sizeof(BYTE
),TRUE
);
314 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
317 serialize_string(pInfo
->cipher
.pbData
,&ptr
,
318 pInfo
->cipher
.cbData
,sizeof(BYTE
),TRUE
);
319 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
322 serialize_string(pInfo
->fingerprint
.pbData
,&ptr
,
323 pInfo
->fingerprint
.cbData
,sizeof(BYTE
),TRUE
);
324 /*TRACE("used %u\n",ptr-pSerial->pbData);*/
326 if (ptr
- pSerial
->pbData
!= dwStruct
)
328 ERR("struct size changed!? %u != expected %u\n",
329 ptr
- pSerial
->pbData
, (unsigned int)dwStruct
);
330 LocalFree(pSerial
->pbData
);
331 pSerial
->pbData
=NULL
;
340 BOOL
unserialize(DATA_BLOB
* pSerial
, struct protect_data_t
* pInfo
)
349 if (!pInfo
|| !pSerial
|| !pSerial
->pbData
)
354 size
=pSerial
->cbData
;
357 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->count0
))
359 ERR("reading count0 failed!\n");
364 if (!unserialize_string(ptr
,&index
,size
,16,sizeof(BYTE
),FALSE
,
365 &pInfo
->info0
.pbData
, &pInfo
->info0
.cbData
))
367 ERR("reading info0 failed!\n");
372 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->count1
))
374 ERR("reading count1 failed!\n");
379 if (!unserialize_string(ptr
,&index
,size
,16,sizeof(BYTE
),FALSE
,
380 &pInfo
->info1
.pbData
, &pInfo
->info1
.cbData
))
382 ERR("reading info1 failed!\n");
387 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->null0
))
389 ERR("reading null0 failed!\n");
394 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
395 (BYTE
**)&pInfo
->szDataDescr
, NULL
))
397 ERR("reading szDataDescr failed!\n");
402 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown0
))
404 ERR("reading unknown0 failed!\n");
409 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown1
))
411 ERR("reading unknown1 failed!\n");
416 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
417 &pInfo
->data0
.pbData
, &pInfo
->data0
.cbData
))
419 ERR("reading data0 failed!\n");
424 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->null1
))
426 ERR("reading null1 failed!\n");
431 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown2
))
433 ERR("reading unknown2 failed!\n");
438 if (!unserialize_dword(ptr
,&index
,size
,&pInfo
->unknown3
))
440 ERR("reading unknown3 failed!\n");
445 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
446 &pInfo
->salt
.pbData
, &pInfo
->salt
.cbData
))
448 ERR("reading salt failed!\n");
453 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
454 &pInfo
->cipher
.pbData
, &pInfo
->cipher
.cbData
))
456 ERR("reading cipher failed!\n");
461 if (!unserialize_string(ptr
,&index
,size
,0,sizeof(BYTE
),TRUE
,
462 &pInfo
->fingerprint
.pbData
, &pInfo
->fingerprint
.cbData
))
464 ERR("reading fingerprint failed!\n");
468 /* allow structure size to be too big (since some applications
469 * will pad this up to 256 bytes, it seems) */
472 /* this is an impossible-to-reach test, but if the padding
473 * issue is ever understood, this may become more useful */
474 ERR("loaded corrupt structure! (used %u expected %u)\n",
475 (unsigned int)index
, (unsigned int)size
);
482 /* perform sanity checks */
484 BOOL
valid_protect_data(struct protect_data_t
* pInfo
)
490 if (pInfo
->count0
!= 0x0001)
492 ERR("count0 != 0x0001 !\n");
495 if (pInfo
->count1
!= 0x0001)
497 ERR("count0 != 0x0001 !\n");
500 if (pInfo
->null0
!= 0x0000)
502 ERR("null0 != 0x0000 !\n");
505 if (pInfo
->null1
!= 0x0000)
507 ERR("null1 != 0x0000 !\n");
510 /* since we have no idea what info0 is used for, and it seems
511 * rather constant, we can test for a Wine-specific magic string
512 * there to be reasonably sure we're using data created by the Wine
513 * implementation of CryptProtectData.
515 if (pInfo
->info0
.cbData
!=strlen(crypt_magic_str
)+1 ||
516 strcmp(pInfo
->info0
.pbData
,crypt_magic_str
) != 0)
518 ERR("info0 magic value not matched !\n");
524 ERR("unrecognized CryptProtectData block\n");
531 void free_protect_data(struct protect_data_t
* pInfo
)
537 if (pInfo
->info0
.pbData
)
538 HeapFree( GetProcessHeap(), 0, pInfo
->info0
.pbData
);
539 if (pInfo
->info1
.pbData
)
540 HeapFree( GetProcessHeap(), 0, pInfo
->info1
.pbData
);
541 if (pInfo
->szDataDescr
)
542 HeapFree( GetProcessHeap(), 0, pInfo
->szDataDescr
);
543 if (pInfo
->data0
.pbData
)
544 HeapFree( GetProcessHeap(), 0, pInfo
->data0
.pbData
);
545 if (pInfo
->salt
.pbData
)
546 HeapFree( GetProcessHeap(), 0, pInfo
->salt
.pbData
);
547 if (pInfo
->cipher
.pbData
)
548 HeapFree( GetProcessHeap(), 0, pInfo
->cipher
.pbData
);
549 if (pInfo
->fingerprint
.pbData
)
550 HeapFree( GetProcessHeap(), 0, pInfo
->fingerprint
.pbData
);
553 /* copies a string into a data blob */
555 BYTE
* convert_str_to_blob(char* str
, DATA_BLOB
* blob
)
557 if (!str
|| !blob
) return NULL
;
559 blob
->cbData
=strlen(str
)+1;
560 if (!(blob
->pbData
=HeapAlloc(GetProcessHeap(),0,blob
->cbData
)))
565 strcpy(blob
->pbData
, str
);
572 * Populates everything except "cipher" and "fingerprint".
575 BOOL
fill_protect_data(struct protect_data_t
* pInfo
, LPCWSTR szDataDescr
,
582 if (!pInfo
) return FALSE
;
584 dwStrLen
=lstrlenW(szDataDescr
);
586 memset(pInfo
,0,sizeof(*pInfo
));
588 pInfo
->count0
=0x0001;
590 convert_str_to_blob((char*)crypt_magic_str
,&pInfo
->info0
);
592 pInfo
->count1
=0x0001;
594 convert_str_to_blob((char*)crypt_magic_str
,&pInfo
->info1
);
598 if ((pInfo
->szDataDescr
=HeapAlloc( GetProcessHeap(), 0, (dwStrLen
+1)*sizeof(WCHAR
))))
600 memcpy(pInfo
->szDataDescr
,szDataDescr
,(dwStrLen
+1)*sizeof(WCHAR
));
603 pInfo
->unknown0
=0x0000;
604 pInfo
->unknown1
=0x0000;
606 convert_str_to_blob((char*)crypt_magic_str
,&pInfo
->data0
);
609 pInfo
->unknown2
=0x0000;
610 pInfo
->unknown3
=0x0000;
612 /* allocate memory to hold a salt */
613 pInfo
->salt
.cbData
=CRYPT32_PROTECTDATA_SALT_LEN
;
614 if ((pInfo
->salt
.pbData
=HeapAlloc( GetProcessHeap(),0,pInfo
->salt
.cbData
)))
616 /* generate random salt */
617 if (!CryptGenRandom(hProv
, pInfo
->salt
.cbData
, pInfo
->salt
.pbData
))
619 ERR("CryptGenRandom\n");
620 free_protect_data(pInfo
);
625 /* debug: show our salt */
626 TRACE_DATA_BLOB(&pInfo
->salt
);
628 pInfo
->cipher
.cbData
=0;
629 pInfo
->cipher
.pbData
=NULL
;
631 pInfo
->fingerprint
.cbData
=0;
632 pInfo
->fingerprint
.pbData
=NULL
;
634 /* check all the allocations at once */
635 if (!pInfo
->info0
.pbData
||
636 !pInfo
->info1
.pbData
||
637 !pInfo
->szDataDescr
||
638 !pInfo
->data0
.pbData
||
642 ERR("could not allocate protect_data structures\n");
643 free_protect_data(pInfo
);
651 BOOL
convert_hash_to_blob(HCRYPTHASH hHash
, DATA_BLOB
* blob
)
657 if (!blob
) return FALSE
;
659 dwSize
=sizeof(DWORD
);
660 if (!CryptGetHashParam(hHash
, HP_HASHSIZE
, (BYTE
*)&blob
->cbData
,
663 ERR("failed to get hash size\n");
667 if (!(blob
->pbData
=HeapAlloc( GetProcessHeap(), 0, blob
->cbData
)))
669 ERR("failed to allocate blob memory\n");
674 if (!CryptGetHashParam(hHash
, HP_HASHVAL
, blob
->pbData
, &dwSize
, 0))
676 ERR("failed to get hash value\n");
677 HeapFree( GetProcessHeap(), 0, blob
->pbData
);
686 /* test that a given hash matches an exported-to-blob hash value */
688 BOOL
hash_matches_blob(HCRYPTHASH hHash
, DATA_BLOB
* two
)
693 if (!two
|| !two
->pbData
) return FALSE
;
695 if (!convert_hash_to_blob(hHash
,&one
)) {
699 if ( one
.cbData
== two
->cbData
&&
700 memcmp( one
.pbData
, two
->pbData
, one
.cbData
) == 0 )
705 HeapFree( GetProcessHeap(), 0, one
.pbData
);
709 /* create an encryption key from a given salt and optional entropy */
711 BOOL
load_encryption_key(HCRYPTPROV hProv
, DATA_BLOB
* salt
,
712 DATA_BLOB
* pOptionalEntropy
, HCRYPTKEY
* phKey
)
715 HCRYPTHASH hSaltHash
;
716 char * szUsername
= NULL
;
720 /* create hash for salt */
721 if (!salt
|| !phKey
||
722 !CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hSaltHash
))
724 ERR("CryptCreateHash\n");
728 /* This should be the "logon credentials" instead of username */
729 dwError
=GetLastError();
731 if (!GetUserNameA(NULL
,&dwUsernameLen
) &&
732 GetLastError()==ERROR_MORE_DATA
&& dwUsernameLen
&&
733 (szUsername
= HeapAlloc( GetProcessHeap(), 0, dwUsernameLen
)))
736 GetUserNameA( szUsername
, &dwUsernameLen
);
738 SetLastError(dwError
);
740 /* salt the hash with:
742 * - an "internal secret"
743 * - randomness (from the salt)
744 * - user-supplied entropy
746 if ((szUsername
&& !CryptHashData(hSaltHash
,szUsername
,dwUsernameLen
,0)) ||
747 !CryptHashData(hSaltHash
,CRYPT32_PROTECTDATA_SECRET
,
748 strlen(CRYPT32_PROTECTDATA_SECRET
),0) ||
749 !CryptHashData(hSaltHash
,salt
->pbData
,salt
->cbData
,0) ||
750 (pOptionalEntropy
&& !CryptHashData(hSaltHash
,
751 pOptionalEntropy
->pbData
,
752 pOptionalEntropy
->cbData
,0)))
754 ERR("CryptHashData\n");
758 /* produce a symmetric key */
759 if (rc
&& !CryptDeriveKey(hProv
,CRYPT32_PROTECTDATA_KEY_CALG
,
760 hSaltHash
,CRYPT_EXPORTABLE
,phKey
))
762 ERR("CryptDeriveKey\n");
767 CryptDestroyHash(hSaltHash
);
768 if (szUsername
) HeapFree( GetProcessHeap(), 0, szUsername
);
773 /* debugging tool to print the structures of a ProtectData call */
775 report(DATA_BLOB
* pDataIn
, DATA_BLOB
* pOptionalEntropy
,
776 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
, DWORD dwFlags
)
778 TRACE("pPromptStruct: 0x%x\n",(unsigned int)pPromptStruct
);
781 TRACE(" cbSize: 0x%x\n",(unsigned int)pPromptStruct
->cbSize
);
782 TRACE(" dwPromptFlags: 0x%x\n",(unsigned int)pPromptStruct
->dwPromptFlags
);
783 TRACE(" hwndApp: 0x%x\n",(unsigned int)pPromptStruct
->hwndApp
);
784 TRACE(" szPrompt: 0x%x %s\n",
785 (unsigned int)pPromptStruct
->szPrompt
,
786 pPromptStruct
->szPrompt
? debugstr_w(pPromptStruct
->szPrompt
)
789 TRACE("dwFlags: 0x%04x\n",(unsigned int)dwFlags
);
790 TRACE_DATA_BLOB(pDataIn
);
791 if (pOptionalEntropy
)
793 TRACE_DATA_BLOB(pOptionalEntropy
);
794 TRACE(" %s\n",debugstr_an(pOptionalEntropy
->pbData
,pOptionalEntropy
->cbData
));
800 /***************************************************************************
801 * CryptProtectData [CRYPT32.@]
803 * Generate Cipher data from given Plain and Entropy data.
806 * pDataIn [I] Plain data to be enciphered
807 * szDataDescr [I] Optional Unicode string describing the Plain data
808 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
809 * pvReserved [I] Reserved, must be NULL
810 * pPromptStruct [I] Structure describing if/how to prompt during ciphering
811 * dwFlags [I] Flags describing options to the ciphering
812 * pDataOut [O] Resulting Cipher data, for calls to CryptUnprotectData
815 * TRUE If a Cipher was generated.
816 * FALSE If something failed and no Cipher is available.
819 * The true Windows encryption and keying mechanisms are unknown.
821 * dwFlags and pPromptStruct are currently ignored.
824 * Memory allocated in pDataOut must be freed with LocalFree.
827 BOOL WINAPI
CryptProtectData(DATA_BLOB
* pDataIn
,
829 DATA_BLOB
* pOptionalEntropy
,
831 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
,
838 struct protect_data_t protect_data
;
845 SetLastError(ERROR_SUCCESS
);
847 if (!pDataIn
|| !pDataOut
)
849 SetLastError(ERROR_INVALID_PARAMETER
);
853 /* debug: show our arguments */
854 report(pDataIn
,pOptionalEntropy
,pPromptStruct
,dwFlags
);
855 TRACE("\tszDataDescr: 0x%x %s\n",(unsigned int)szDataDescr
,
856 szDataDescr
? debugstr_w(szDataDescr
) : "");
858 /* Windows appears to create an empty szDataDescr instead of maintaining
861 szDataDescr
=(WCHAR
[]){'\0'};
863 /* get crypt context */
864 if (!CryptAcquireContextW(&hProv
,NULL
,NULL
,CRYPT32_PROTECTDATA_PROV
,CRYPT_VERIFYCONTEXT
))
866 ERR("CryptAcquireContextW failed\n");
870 /* populate our structure */
871 if (!fill_protect_data(&protect_data
,szDataDescr
,hProv
))
873 ERR("fill_protect_data\n");
878 if (!load_encryption_key(hProv
,&protect_data
.salt
,pOptionalEntropy
,&hKey
))
880 goto free_protect_data
;
883 /* create a hash for the encryption validation */
884 if (!CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hHash
))
886 ERR("CryptCreateHash\n");
890 /* calculate storage required */
891 dwLength
=pDataIn
->cbData
;
892 if (CryptEncrypt(hKey
, 0, TRUE
, 0, pDataIn
->pbData
, &dwLength
, 0) ||
893 GetLastError()!=ERROR_MORE_DATA
)
895 ERR("CryptEncrypt\n");
898 TRACE("required encrypted storage: %u\n",(unsigned int)dwLength
);
900 /* copy plain text into cipher area for CryptEncrypt call */
901 protect_data
.cipher
.cbData
=dwLength
;
902 if (!(protect_data
.cipher
.pbData
=HeapAlloc( GetProcessHeap(), 0,
903 protect_data
.cipher
.cbData
)))
908 memcpy(protect_data
.cipher
.pbData
,pDataIn
->pbData
,pDataIn
->cbData
);
911 dwLength
=pDataIn
->cbData
;
912 if (!CryptEncrypt(hKey
, hHash
, TRUE
, 0, protect_data
.cipher
.pbData
,
913 &dwLength
, protect_data
.cipher
.cbData
))
915 ERR("CryptEncrypt %u\n",(unsigned int)GetLastError());
918 protect_data
.cipher
.cbData
=dwLength
;
920 /* debug: show the cipher */
921 TRACE_DATA_BLOB(&protect_data
.cipher
);
923 /* attach our fingerprint */
924 if (!convert_hash_to_blob(hHash
, &protect_data
.fingerprint
))
926 ERR("convert_hash_to_blob\n");
930 /* serialize into an opaque blob */
931 if (!serialize(&protect_data
, pDataOut
))
941 CryptDestroyHash(hHash
);
943 CryptDestroyKey(hKey
);
945 free_protect_data(&protect_data
);
947 CryptReleaseContext(hProv
,0);
949 /* If some error occurred, and no error code was set, force one. */
950 if (!rc
&& GetLastError()==ERROR_SUCCESS
)
952 SetLastError(ERROR_INVALID_DATA
);
957 SetLastError(ERROR_SUCCESS
);
959 TRACE_DATA_BLOB(pDataOut
);
962 TRACE("returning %s\n", rc
? "ok" : "FAIL");
968 /***************************************************************************
969 * CryptUnprotectData [CRYPT32.@]
971 * Generate Plain data and Description from given Cipher and Entropy data.
974 * pDataIn [I] Cipher data to be decoded
975 * ppszDataDescr [O] Optional Unicode string describing the Plain data
976 * pOptionalEntropy [I] Optional entropy data to adjust cipher, can be NULL
977 * pvReserved [I] Reserved, must be NULL
978 * pPromptStruct [I] Structure describing if/how to prompt during decoding
979 * dwFlags [I] Flags describing options to the decoding
980 * pDataOut [O] Resulting Plain data, from calls to CryptProtectData
983 * TRUE If a Plain was generated.
984 * FALSE If something failed and no Plain is available.
987 * The true Windows encryption and keying mechanisms are unknown.
989 * dwFlags and pPromptStruct are currently ignored.
992 * Memory allocated in pDataOut and non-NULL ppszDataDescr must be freed
996 BOOL WINAPI
CryptUnprotectData(DATA_BLOB
* pDataIn
,
997 LPWSTR
* ppszDataDescr
,
998 DATA_BLOB
* pOptionalEntropy
,
1000 CRYPTPROTECT_PROMPTSTRUCT
* pPromptStruct
,
1002 DATA_BLOB
* pDataOut
)
1007 struct protect_data_t protect_data
;
1012 const char * announce_bad_opaque_data
= "CryptUnprotectData received a DATA_BLOB that seems to have NOT been generated by Wine. Please enable tracing ('export WINEDEBUG=crypt') to see details.";
1016 SetLastError(ERROR_SUCCESS
);
1018 if (!pDataIn
|| !pDataOut
)
1020 SetLastError(ERROR_INVALID_PARAMETER
);
1024 /* debug: show our arguments */
1025 report(pDataIn
,pOptionalEntropy
,pPromptStruct
,dwFlags
);
1026 TRACE("\tppszDataDescr: 0x%x\n",(unsigned int)ppszDataDescr
);
1028 /* take apart the opaque blob */
1029 if (!unserialize(pDataIn
, &protect_data
))
1031 SetLastError(ERROR_INVALID_DATA
);
1032 FIXME("%s\n",announce_bad_opaque_data
);
1036 /* perform basic validation on the resulting structure */
1037 if (!valid_protect_data(&protect_data
))
1039 SetLastError(ERROR_INVALID_DATA
);
1040 FIXME("%s\n",announce_bad_opaque_data
);
1041 goto free_protect_data
;
1044 /* get a crypt context */
1045 if (!CryptAcquireContextW(&hProv
,NULL
,NULL
,CRYPT32_PROTECTDATA_PROV
,CRYPT_VERIFYCONTEXT
))
1047 ERR("CryptAcquireContextW failed\n");
1048 goto free_protect_data
;
1052 if (!load_encryption_key(hProv
,&protect_data
.salt
,pOptionalEntropy
,&hKey
))
1057 /* create a hash for the decryption validation */
1058 if (!CryptCreateHash(hProv
,CRYPT32_PROTECTDATA_HASH_CALG
,0,0,&hHash
))
1060 ERR("CryptCreateHash\n");
1064 /* prepare for plaintext */
1065 pDataOut
->cbData
=protect_data
.cipher
.cbData
;
1066 if (!(pDataOut
->pbData
=LocalAlloc( LPTR
, pDataOut
->cbData
)))
1071 memcpy(pDataOut
->pbData
,protect_data
.cipher
.pbData
,protect_data
.cipher
.cbData
);
1074 if (!CryptDecrypt(hKey
, hHash
, TRUE
, 0, pDataOut
->pbData
,
1075 &pDataOut
->cbData
) ||
1076 /* check the hash fingerprint */
1077 pDataOut
->cbData
> protect_data
.cipher
.cbData
||
1078 !hash_matches_blob(hHash
, &protect_data
.fingerprint
))
1080 SetLastError(ERROR_INVALID_DATA
);
1082 LocalFree( pDataOut
->pbData
);
1083 pDataOut
->pbData
= NULL
;
1084 pDataOut
->cbData
= 0;
1089 /* Copy out the description */
1090 dwLength
= (lstrlenW(protect_data
.szDataDescr
)+1) * sizeof(WCHAR
);
1093 if (!(*ppszDataDescr
= LocalAlloc(LPTR
,dwLength
)))
1095 ERR("LocalAlloc (ppszDataDescr)\n");
1099 memcpy(*ppszDataDescr
,protect_data
.szDataDescr
,dwLength
);
1107 CryptDestroyHash(hHash
);
1109 CryptDestroyKey(hKey
);
1111 CryptReleaseContext(hProv
,0);
1113 free_protect_data(&protect_data
);
1115 /* If some error occurred, and no error code was set, force one. */
1116 if (!rc
&& GetLastError()==ERROR_SUCCESS
)
1118 SetLastError(ERROR_INVALID_DATA
);
1122 SetLastError(ERROR_SUCCESS
);
1126 TRACE("szDataDescr: %s\n",debugstr_w(*ppszDataDescr
));
1128 TRACE_DATA_BLOB(pDataOut
);
1131 TRACE("returning %s\n", rc
? "ok" : "FAIL");