📄 protectdata.c
字号:
return FALSE;
}
/* info1 */
if (!unserialize_string(ptr,&index,size,16,sizeof(BYTE),FALSE,
&pInfo->info1.pbData, &pInfo->info1.cbData))
{
ERR("reading info1 failed!\n");
return FALSE;
}
/* null0 */
if (!unserialize_dword(ptr,&index,size,&pInfo->null0))
{
ERR("reading null0 failed!\n");
return FALSE;
}
/* szDataDescr */
if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
(BYTE**)&pInfo->szDataDescr, NULL))
{
ERR("reading szDataDescr failed!\n");
return FALSE;
}
/* unknown0 */
if (!unserialize_dword(ptr,&index,size,&pInfo->unknown0))
{
ERR("reading unknown0 failed!\n");
return FALSE;
}
/* unknown1 */
if (!unserialize_dword(ptr,&index,size,&pInfo->unknown1))
{
ERR("reading unknown1 failed!\n");
return FALSE;
}
/* data0 */
if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
&pInfo->data0.pbData, &pInfo->data0.cbData))
{
ERR("reading data0 failed!\n");
return FALSE;
}
/* null1 */
if (!unserialize_dword(ptr,&index,size,&pInfo->null1))
{
ERR("reading null1 failed!\n");
return FALSE;
}
/* unknown2 */
if (!unserialize_dword(ptr,&index,size,&pInfo->unknown2))
{
ERR("reading unknown2 failed!\n");
return FALSE;
}
/* unknown3 */
if (!unserialize_dword(ptr,&index,size,&pInfo->unknown3))
{
ERR("reading unknown3 failed!\n");
return FALSE;
}
/* salt */
if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
&pInfo->salt.pbData, &pInfo->salt.cbData))
{
ERR("reading salt failed!\n");
return FALSE;
}
/* cipher */
if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
&pInfo->cipher.pbData, &pInfo->cipher.cbData))
{
ERR("reading cipher failed!\n");
return FALSE;
}
/* fingerprint */
if (!unserialize_string(ptr,&index,size,0,sizeof(BYTE),TRUE,
&pInfo->fingerprint.pbData, &pInfo->fingerprint.cbData))
{
ERR("reading fingerprint failed!\n");
return FALSE;
}
/* allow structure size to be too big (since some applications
* will pad this up to 256 bytes, it seems) */
if (index>size)
{
/* this is an impossible-to-reach test, but if the padding
* issue is ever understood, this may become more useful */
ERR("loaded corrupt structure! (used %u expected %u)\n",
(unsigned int)index, (unsigned int)size);
status=FALSE;
}
return status;
}
/* perform sanity checks */
static
BOOL valid_protect_data(const struct protect_data_t *pInfo)
{
BOOL status=TRUE;
TRACE("called\n");
if (pInfo->count0 != 0x0001)
{
ERR("count0 != 0x0001 !\n");
status=FALSE;
}
if (pInfo->count1 != 0x0001)
{
ERR("count0 != 0x0001 !\n");
status=FALSE;
}
if (pInfo->null0 != 0x0000)
{
ERR("null0 != 0x0000 !\n");
status=FALSE;
}
if (pInfo->null1 != 0x0000)
{
ERR("null1 != 0x0000 !\n");
status=FALSE;
}
/* since we have no idea what info0 is used for, and it seems
* rather constant, we can test for a Wine-specific magic string
* there to be reasonably sure we're using data created by the Wine
* implementation of CryptProtectData.
*/
if (pInfo->info0.cbData!=strlen(crypt_magic_str)+1 ||
strcmp( (LPCSTR)pInfo->info0.pbData,crypt_magic_str) != 0)
{
ERR("info0 magic value not matched !\n");
status=FALSE;
}
if (!status)
{
ERR("unrecognized CryptProtectData block\n");
}
return status;
}
static
void free_protect_data(struct protect_data_t * pInfo)
{
TRACE("called\n");
if (!pInfo) return;
CryptMemFree(pInfo->info0.pbData);
CryptMemFree(pInfo->info1.pbData);
CryptMemFree(pInfo->szDataDescr);
CryptMemFree(pInfo->data0.pbData);
CryptMemFree(pInfo->salt.pbData);
CryptMemFree(pInfo->cipher.pbData);
CryptMemFree(pInfo->fingerprint.pbData);
}
/* copies a string into a data blob */
static
BYTE *convert_str_to_blob(LPCSTR str, DATA_BLOB *blob)
{
if (!str || !blob) return NULL;
blob->cbData=strlen(str)+1;
if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
{
blob->cbData=0;
}
else {
strcpy((LPSTR)blob->pbData, str);
}
return blob->pbData;
}
/*
* Populates everything except "cipher" and "fingerprint".
*/
static
BOOL fill_protect_data(struct protect_data_t * pInfo, LPCWSTR szDataDescr,
HCRYPTPROV hProv)
{
DWORD dwStrLen;
TRACE("called\n");
if (!pInfo) return FALSE;
dwStrLen=lstrlenW(szDataDescr);
memset(pInfo,0,sizeof(*pInfo));
pInfo->count0=0x0001;
convert_str_to_blob(crypt_magic_str, &pInfo->info0);
pInfo->count1=0x0001;
convert_str_to_blob(crypt_magic_str, &pInfo->info1);
pInfo->null0=0x0000;
if ((pInfo->szDataDescr=CryptMemAlloc((dwStrLen+1)*sizeof(WCHAR))))
{
memcpy(pInfo->szDataDescr,szDataDescr,(dwStrLen+1)*sizeof(WCHAR));
}
pInfo->unknown0=0x0000;
pInfo->unknown1=0x0000;
convert_str_to_blob(crypt_magic_str, &pInfo->data0);
pInfo->null1=0x0000;
pInfo->unknown2=0x0000;
pInfo->unknown3=0x0000;
/* allocate memory to hold a salt */
pInfo->salt.cbData=CRYPT32_PROTECTDATA_SALT_LEN;
if ((pInfo->salt.pbData=CryptMemAlloc(pInfo->salt.cbData)))
{
/* generate random salt */
if (!CryptGenRandom(hProv, pInfo->salt.cbData, pInfo->salt.pbData))
{
ERR("CryptGenRandom\n");
free_protect_data(pInfo);
return FALSE;
}
}
/* debug: show our salt */
TRACE_DATA_BLOB(&pInfo->salt);
pInfo->cipher.cbData=0;
pInfo->cipher.pbData=NULL;
pInfo->fingerprint.cbData=0;
pInfo->fingerprint.pbData=NULL;
/* check all the allocations at once */
if (!pInfo->info0.pbData ||
!pInfo->info1.pbData ||
!pInfo->szDataDescr ||
!pInfo->data0.pbData ||
!pInfo->salt.pbData
)
{
ERR("could not allocate protect_data structures\n");
free_protect_data(pInfo);
return FALSE;
}
return TRUE;
}
static
BOOL convert_hash_to_blob(HCRYPTHASH hHash, DATA_BLOB * blob)
{
DWORD dwSize;
TRACE("called\n");
if (!blob) return FALSE;
dwSize=sizeof(DWORD);
if (!CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&blob->cbData,
&dwSize, 0))
{
ERR("failed to get hash size\n");
return FALSE;
}
if (!(blob->pbData=CryptMemAlloc(blob->cbData)))
{
ERR("failed to allocate blob memory\n");
return FALSE;
}
dwSize=blob->cbData;
if (!CryptGetHashParam(hHash, HP_HASHVAL, blob->pbData, &dwSize, 0))
{
ERR("failed to get hash value\n");
CryptMemFree(blob->pbData);
blob->pbData=NULL;
blob->cbData=0;
return FALSE;
}
return TRUE;
}
/* test that a given hash matches an exported-to-blob hash value */
static
BOOL hash_matches_blob(HCRYPTHASH hHash, const DATA_BLOB *two)
{
BOOL rc = FALSE;
DATA_BLOB one;
if (!two || !two->pbData) return FALSE;
if (!convert_hash_to_blob(hHash,&one)) {
return FALSE;
}
if ( one.cbData == two->cbData &&
memcmp( one.pbData, two->pbData, one.cbData ) == 0 )
{
rc = TRUE;
}
CryptMemFree(one.pbData);
return rc;
}
/* create an encryption key from a given salt and optional entropy */
static
BOOL load_encryption_key(HCRYPTPROV hProv, const DATA_BLOB *salt,
const DATA_BLOB *pOptionalEntropy, HCRYPTKEY *phKey)
{
BOOL rc = TRUE;
HCRYPTHASH hSaltHash;
char * szUsername = NULL;
DWORD dwUsernameLen;
DWORD dwError;
/* create hash for salt */
if (!salt || !phKey ||
!CryptCreateHash(hProv,CRYPT32_PROTECTDATA_HASH_CALG,0,0,&hSaltHash))
{
ERR("CryptCreateHash\n");
return FALSE;
}
/* This should be the "logon credentials" instead of username */
dwError=GetLastError();
dwUsernameLen = 0;
if (!GetUserNameA(NULL,&dwUsernameLen) &&
GetLastError()==ERROR_MORE_DATA && dwUsernameLen &&
(szUsername = CryptMemAlloc(dwUsernameLen)))
{
szUsername[0]='\0';
GetUserNameA( szUsername, &dwUsernameLen );
}
SetLastError(dwError);
/* salt the hash with:
* - the user id
* - an "internal secret"
* - randomness (from the salt)
* - user-supplied entropy
*/
if ((szUsername && !CryptHashData(hSaltHash,(LPBYTE)szUsername,dwUsernameLen,0)) ||
!CryptHashData(hSaltHash,crypt32_protectdata_secret,
sizeof(crypt32_protectdata_secret)-1,0) ||
!CryptHashData(hSaltHash,salt->pbData,salt->cbData,0) ||
(pOptionalEntropy && !CryptHashData(hSaltHash,
pOptionalEntropy->pbData,
pOptionalEntropy->cbData,0)))
{
ERR("CryptHashData\n");
rc = FALSE;
}
/* produce a symmetric key */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -