You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1025 lines
28 KiB
1025 lines
28 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// File: pwutil.cpp
|
|
//
|
|
// Module: Common Source
|
|
//
|
|
// Synopsis: Simple encryption funcs - borrowed from RAS
|
|
//
|
|
// Copyright (c) 1994-1999 Microsoft Corporation
|
|
//
|
|
// Author: nickball Created 08/03/99
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
|
|
#define PASSWORDMAGIC 0xA5
|
|
|
|
|
|
|
|
VOID
|
|
ReverseSzA(
|
|
CHAR* psz )
|
|
|
|
/* Reverses order of characters in 'psz'.
|
|
*/
|
|
{
|
|
CHAR* pszBegin;
|
|
CHAR* pszEnd;
|
|
|
|
for (pszBegin = psz, pszEnd = psz + lstrlenA( psz ) - 1;
|
|
pszBegin < pszEnd;
|
|
++pszBegin, --pszEnd)
|
|
{
|
|
CHAR ch = *pszBegin;
|
|
*pszBegin = *pszEnd;
|
|
*pszEnd = ch;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ReverseSzW(
|
|
WCHAR* psz )
|
|
|
|
/* Reverses order of characters in 'psz'.
|
|
*/
|
|
{
|
|
WCHAR* pszBegin;
|
|
WCHAR* pszEnd;
|
|
|
|
for (pszBegin = psz, pszEnd = psz + lstrlenW( psz ) - 1;
|
|
pszBegin < pszEnd;
|
|
++pszBegin, --pszEnd)
|
|
{
|
|
WCHAR ch = *pszBegin;
|
|
*pszBegin = *pszEnd;
|
|
*pszEnd = ch;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CmDecodePasswordA(
|
|
IN OUT CHAR* pszPassword )
|
|
|
|
/* Un-obfuscate 'pszPassword' in place.
|
|
**
|
|
** Returns Nothing
|
|
*/
|
|
{
|
|
CmEncodePasswordA( pszPassword );
|
|
}
|
|
|
|
|
|
VOID
|
|
CmDecodePasswordW(
|
|
IN OUT WCHAR* pszPassword )
|
|
|
|
/* Un-obfuscate 'pszPassword' in place.
|
|
**
|
|
** Returns the address of 'pszPassword'.
|
|
*/
|
|
{
|
|
CmEncodePasswordW( pszPassword );
|
|
}
|
|
|
|
|
|
VOID
|
|
CmEncodePasswordA(
|
|
IN OUT CHAR* pszPassword )
|
|
|
|
/* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
|
|
**
|
|
** Returns Nothing
|
|
*/
|
|
{
|
|
if (pszPassword)
|
|
{
|
|
CHAR* psz;
|
|
|
|
ReverseSzA( pszPassword );
|
|
|
|
for (psz = pszPassword; *psz != '\0'; ++psz)
|
|
{
|
|
if (*psz != PASSWORDMAGIC)
|
|
*psz ^= PASSWORDMAGIC;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CmEncodePasswordW(
|
|
IN OUT WCHAR* pszPassword )
|
|
|
|
/* Obfuscate 'pszPassword' in place to foil memory scans for passwords.
|
|
**
|
|
** Returns Nothing
|
|
*/
|
|
{
|
|
if (pszPassword)
|
|
{
|
|
WCHAR* psz;
|
|
|
|
ReverseSzW( pszPassword );
|
|
|
|
for (psz = pszPassword; *psz != L'\0'; ++psz)
|
|
{
|
|
if (*psz != PASSWORDMAGIC)
|
|
*psz ^= PASSWORDMAGIC;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CmWipePasswordA(
|
|
IN OUT CHAR* pszPassword )
|
|
|
|
/* Zero out the memory occupied by a password.
|
|
**
|
|
** Returns Nothing
|
|
*/
|
|
{
|
|
if (pszPassword)
|
|
{
|
|
CHAR* psz = pszPassword;
|
|
|
|
//
|
|
// We are assuming the string is NULL terminated, thus we just need to pass
|
|
// the actual string length (converted to bytes) to be wiped. The is no need
|
|
// to include the NULL character in the count.
|
|
//
|
|
psz = (CHAR*)CmSecureZeroMemory((PVOID)psz, lstrlenA(psz) * sizeof(CHAR));
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
CmWipePasswordW(
|
|
IN OUT WCHAR* pszPassword )
|
|
|
|
/* Zero out the memory occupied by a password.
|
|
**
|
|
** Returns Nothing
|
|
*/
|
|
{
|
|
if (pszPassword)
|
|
{
|
|
WCHAR* psz = pszPassword;
|
|
|
|
//
|
|
// We are assuming the string is NULL terminated, thus we just need to pass
|
|
// the actual string length (converted to bytes) to be wiped. The is no need
|
|
// to include the NULL character in the count.
|
|
//
|
|
psz = (WCHAR*)CmSecureZeroMemory((PVOID)psz, lstrlenW(psz) * sizeof(WCHAR));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: CmSecureZeroMemory
|
|
//
|
|
// Synopsis: RtlSecureZeroMemory isn't available on all platforms so we took
|
|
// its implementation.
|
|
//
|
|
// Arguments: ptr - memory pointer
|
|
// cnt - size in bytes of memory to clear
|
|
//
|
|
// Returns: poniter to beginning of memory
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
PVOID CmSecureZeroMemory(IN PVOID ptr, IN SIZE_T cnt)
|
|
{
|
|
if (ptr)
|
|
{
|
|
volatile char *vptr = (volatile char *)ptr;
|
|
while (cnt)
|
|
{
|
|
*vptr = 0;
|
|
vptr++;
|
|
cnt--;
|
|
}
|
|
}
|
|
return ptr;
|
|
}
|
|
|
|
|
|
// Only include this code in CMDial32.dll
|
|
#ifdef _ICM_INC
|
|
|
|
//+----------------------------------------------------------------------------
|
|
// Class: CSecurePassword
|
|
//
|
|
// Function: CSecurePassword
|
|
//
|
|
// Synopsis: Constructor
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
// History: 11/05/2002 tomkel Created
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CSecurePassword::CSecurePassword()
|
|
{
|
|
this->Init();
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ~CSecurePassword
|
|
//
|
|
// Synopsis: Destructor. Unloads DLL, tries to clear memory & free memory.
|
|
// Makes sure we don't have a memory leak.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
CSecurePassword::~CSecurePassword()
|
|
{
|
|
this->UnInit();
|
|
|
|
//
|
|
// Assert if m_iAllocAndFreeCounter isn't zero. It means we are leaking memory.
|
|
// Each GetPasswordWithAlloc call increments this
|
|
// Each ClearAndFree call decrements this.
|
|
//
|
|
MYDBGASSERT(0 == m_iAllocAndFreeCounter);
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: Init
|
|
//
|
|
// Synopsis: Initializes member variables.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::Init()
|
|
{
|
|
m_iAllocAndFreeCounter = 0;
|
|
m_fIsLibAndFuncPtrsAvail = FALSE;
|
|
m_pEncryptedPW = NULL;
|
|
|
|
fnCryptProtectData = NULL;
|
|
fnCryptUnprotectData = NULL;
|
|
|
|
m_fIsEmptyString = TRUE;
|
|
m_fIsHandleToPassword = FALSE;
|
|
|
|
// By default just set it to PWLEN
|
|
m_dwMaxDataLen = PWLEN;
|
|
|
|
this->ClearMemberVars();
|
|
}
|
|
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetPassword
|
|
//
|
|
// Synopsis: We take this string that is passed in and store it
|
|
// internally. Based on the OS it encrypts
|
|
// or encodes it, thus we don't store it in clear. This method handles
|
|
// 0 length strings, which can be used to clear the member
|
|
// variable. If a RAS password handle (consists of 16 '*'),
|
|
// there is no need for us to encrypt it. To optimize this
|
|
// we set an member flag specifying that currently this
|
|
// instance just hold a handle to a password. On downlevel
|
|
// platforms we don't use expensive encryption calls, thus
|
|
// the logic doesn't distinguish between a normal password
|
|
// and a password handle.
|
|
//
|
|
// Arguments: szPassword - password in clear text.
|
|
//
|
|
// Returns: TRUE - if everything succeeded
|
|
// FALSE - if something failed
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CSecurePassword::SetPassword(IN LPWSTR pszPassword)
|
|
{
|
|
BOOL fRetCode = FALSE;
|
|
DWORD dwRetCode = ERROR_SUCCESS;
|
|
DWORD dwPwLen = 0;
|
|
//
|
|
// OS_NT5 expands to a few function calls, so just cache the result and reuse it below
|
|
//
|
|
BOOL fIsNT5OrAbove = OS_NT5;
|
|
|
|
//
|
|
// If there is an allocated blob then free it first so we don't leak memory.
|
|
//
|
|
this->ClearMemberVars();
|
|
|
|
m_fIsEmptyString = ((NULL == pszPassword) || (TEXT('\0') == pszPassword[0]));
|
|
|
|
if (m_fIsEmptyString)
|
|
{
|
|
//
|
|
// No need to continue, since password can be NULL the code below that compares
|
|
// it to a handle (16 *s) would be dereferencing a NULL
|
|
//
|
|
m_fIsHandleToPassword = FALSE;
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Check whether this is a handle to a password (****************)
|
|
//
|
|
m_fIsHandleToPassword = (fIsNT5OrAbove && (0 == lstrcmpW(c_pszSavedPasswordToken, pszPassword)));
|
|
|
|
//
|
|
// If the internal flag is set, there is no need to encrypt or decrypt this string.
|
|
//
|
|
if (m_fIsHandleToPassword)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Make sure the password that is being encrypted is shorter than the allowed maximum
|
|
//
|
|
dwPwLen = lstrlenU(pszPassword);
|
|
if (m_dwMaxDataLen < dwPwLen)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (fIsNT5OrAbove)
|
|
{
|
|
m_pEncryptedPW = (DATA_BLOB*)CmMalloc(sizeof(DATA_BLOB));
|
|
|
|
if (m_pEncryptedPW)
|
|
{
|
|
dwRetCode = this->EncodePassword((dwPwLen + 1) * sizeof(WCHAR), (PBYTE)pszPassword, m_pEncryptedPW);
|
|
|
|
if (ERROR_SUCCESS == dwRetCode)
|
|
{
|
|
fRetCode = TRUE;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Free the allocated DATA_BLOB so that decryption doesn't cause issue in case caller
|
|
// ends up calling it. And reset internal flags.
|
|
//
|
|
this->ClearMemberVars();
|
|
m_fIsEmptyString = TRUE;
|
|
m_fIsHandleToPassword = FALSE;
|
|
CMTRACE1(TEXT("CSecurePassword::SetPassword - this->EncodePassword failed. 0x%x"), dwRetCode);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Downlevel (Win9x, NT4) we don't support encryption
|
|
//
|
|
lstrcpynU(m_tszPassword, pszPassword, CELEMS(m_tszPassword));
|
|
CmEncodePassword(m_tszPassword);
|
|
fRetCode = TRUE;
|
|
}
|
|
|
|
MYDBGASSERT(fRetCode);
|
|
return fRetCode;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetPasswordWithAlloc
|
|
//
|
|
// Synopsis: Allocates a buffer and copies the clear-text password into it.
|
|
// Based on the OS it decrypts or decodes it since it's not stored
|
|
// in clear. If the internal password is an empty string we allocate
|
|
// an empty string buffer. This is done for consistency since the caller
|
|
// needs to call our free method so memory isn't leaked. If we are storing
|
|
// a RAS password handle (consists of 16 '*') we actually didn't store it,
|
|
// but only set our internal flag. In this case we need to allocate a buffer
|
|
// with 16 * and return it. On downlevel platforms we don't use expensive
|
|
// decryption calls, thus the logic doesn't distinguish between a
|
|
// normal password and a password handle.
|
|
//
|
|
// Arguments: pszClearPw - holds a pointer to a buffer that was allocated by this
|
|
// class.
|
|
// pcbClearPw - hold the size of the allocated buffer in bytes
|
|
//
|
|
// Returns: TRUE - if everything succeeded
|
|
// FALSE - if something failed
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CSecurePassword::GetPasswordWithAlloc(OUT LPWSTR* pszClearPw, OUT DWORD* pcbClearPw)
|
|
{
|
|
BOOL fRetCode = FALSE;
|
|
DWORD dwRetCode = ERROR_SUCCESS;
|
|
DWORD cbData = 0;
|
|
PBYTE pbData = NULL;
|
|
|
|
if ((NULL == pszClearPw) || (NULL == pcbClearPw))
|
|
{
|
|
MYDBGASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
*pszClearPw = NULL;
|
|
*pcbClearPw = 0;
|
|
|
|
if (OS_NT5)
|
|
{
|
|
if (m_fIsEmptyString)
|
|
{
|
|
//
|
|
// In case there is nothing saved in this class, just allocate an empty string
|
|
// and return it back. This at least doesn't have to decrypt and empty string.
|
|
//
|
|
DWORD cbLen = sizeof(WCHAR);
|
|
|
|
LPWSTR szTemp = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, cbLen);
|
|
if (szTemp)
|
|
{
|
|
*pszClearPw = szTemp;
|
|
*pcbClearPw = cbLen;
|
|
fRetCode = TRUE;
|
|
m_iAllocAndFreeCounter++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Check if this instance is just a handle to a RAS password (16 *)
|
|
// If so, then just allocate that string and return it to the caller,
|
|
// otherwise proceed normally and decrypt our blob.
|
|
//
|
|
if (m_fIsHandleToPassword)
|
|
{
|
|
size_t nLen = lstrlenW(c_pszSavedPasswordToken) + 1;
|
|
DWORD cbLen = nLen * sizeof(WCHAR);
|
|
|
|
LPWSTR szTemp = (LPWSTR)LocalAlloc(LMEM_ZEROINIT, cbLen);
|
|
if (szTemp)
|
|
{
|
|
lstrcpynW(szTemp, c_pszSavedPasswordToken, nLen);
|
|
|
|
*pszClearPw = szTemp;
|
|
*pcbClearPw = cbLen;
|
|
fRetCode = TRUE;
|
|
m_iAllocAndFreeCounter++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (m_pEncryptedPW)
|
|
{
|
|
dwRetCode = this->DecodePassword(m_pEncryptedPW, &cbData, &pbData);
|
|
if ((NO_ERROR == dwRetCode) && pbData && cbData)
|
|
{
|
|
*pszClearPw = (LPWSTR)pbData;
|
|
*pcbClearPw = cbData;
|
|
fRetCode = TRUE;
|
|
m_iAllocAndFreeCounter++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Downlevel (Win9x, NT4) doesn't support 16 *
|
|
//
|
|
|
|
size_t nLen = lstrlenU(m_tszPassword) + 1;
|
|
|
|
LPTSTR pszBuffer = (LPWSTR)CmMalloc(nLen * sizeof(TCHAR));
|
|
|
|
if (pszBuffer)
|
|
{
|
|
//
|
|
// Copy our encoded buffer to the newly allocated buffer
|
|
// We can do this because d/encoding is done in place
|
|
//
|
|
lstrcpynU(pszBuffer, m_tszPassword, nLen);
|
|
|
|
//
|
|
// Decode the outgoing buffer
|
|
//
|
|
CmDecodePassword(pszBuffer);
|
|
|
|
*pszClearPw = (LPWSTR)pszBuffer;
|
|
*pcbClearPw = nLen * sizeof(TCHAR);
|
|
|
|
fRetCode = TRUE;
|
|
m_iAllocAndFreeCounter++;
|
|
}
|
|
}
|
|
|
|
MYDBGASSERT(fRetCode);
|
|
return fRetCode;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ClearAndFree
|
|
//
|
|
// Synopsis: Clear then free a buffer that was allocated by this class. Notice that
|
|
// on downlevel platforms the way a buffer is freed differs. That
|
|
// is because encrypting and decrypting needs us to free it
|
|
// using LocalFree. For downlevel platforms we chose CM's standard
|
|
// way of allocating memory (CmMalloc) and it now needs to be
|
|
// freed using CmFree.
|
|
//
|
|
// Arguments: pszClearPw - holds a pointer to a buffer that was allocated by this
|
|
// class.
|
|
// cbClearPw - size of the allocated buffer in bytes
|
|
//
|
|
// Returns: TRUE - if everything succeeded
|
|
// FALSE - if something failed
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::ClearAndFree(IN OUT LPWSTR* pszClearPw, IN DWORD cbClearPw)
|
|
{
|
|
if ((NULL == pszClearPw) || (0 == cbClearPw))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (NULL == *pszClearPw)
|
|
{
|
|
return;
|
|
}
|
|
|
|
CmSecureZeroMemory(*pszClearPw, cbClearPw);
|
|
|
|
if (OS_NT5)
|
|
{
|
|
//
|
|
// Uses LocalFree because CryptProtectData requires this way
|
|
// to free its memory
|
|
//
|
|
|
|
LocalFree(*pszClearPw);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// We used CmMalloc to allocate so we need to call CmFree
|
|
//
|
|
|
|
CmFree(*pszClearPw);
|
|
}
|
|
|
|
*pszClearPw = NULL;
|
|
m_iAllocAndFreeCounter--;
|
|
|
|
return;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: ClearMemberVars
|
|
//
|
|
// Synopsis: Clears our member variables. Notice that we only clear the
|
|
// passwords & member variables. This doesn't mean that m_fIsEmptyString
|
|
// should be set. This needs to be a private method
|
|
// because it doesn't reset the empty or password handle flags. Thus
|
|
// outside callers should NOT use this, because it would create an invalid
|
|
// state.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::ClearMemberVars()
|
|
{
|
|
if (OS_NT5)
|
|
{
|
|
if (m_pEncryptedPW)
|
|
{
|
|
this->FreePassword(m_pEncryptedPW);
|
|
CmFree(m_pEncryptedPW);
|
|
m_pEncryptedPW = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Zero out the password buffer
|
|
//
|
|
CmSecureZeroMemory((PVOID)m_tszPassword, sizeof(m_tszPassword));
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: UnInit
|
|
//
|
|
// Synopsis: Unloads DLL, clear and frees memory.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::UnInit()
|
|
{
|
|
this->UnloadCrypt32();
|
|
this->ClearMemberVars();
|
|
m_fIsHandleToPassword = FALSE;
|
|
m_fIsEmptyString = FALSE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: UnloadCrypt32
|
|
//
|
|
// Synopsis: Unloads DLL
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: none
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::UnloadCrypt32()
|
|
{
|
|
fnCryptProtectData = NULL;
|
|
fnCryptUnprotectData = NULL;
|
|
m_dllCrypt32.Unload();
|
|
m_fIsLibAndFuncPtrsAvail = FALSE;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: EncodePassword
|
|
//
|
|
// Synopsis: Encrypts data using CryptProtectData
|
|
//
|
|
// Arguments: cbPassword - size of buffer in bytes
|
|
// pbPassword - pointer to a buffer to encrypt
|
|
// pDataBlobPassword - pointer to an allocated DATA_BLOB structure
|
|
//
|
|
// Returns: none
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
DWORD CSecurePassword::EncodePassword(IN DWORD cbPassword,
|
|
IN PBYTE pbPassword,
|
|
OUT DATA_BLOB* pDataBlobPassword)
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
DATA_BLOB DataBlobIn;
|
|
|
|
if(NULL == pDataBlobPassword)
|
|
{
|
|
dwErr = E_INVALIDARG;
|
|
CMTRACE(TEXT("CSecurePassword::EncodePassword - NULL == pDataBlobPassword"));
|
|
goto done;
|
|
}
|
|
|
|
if( (0 == cbPassword)
|
|
|| (NULL == pbPassword))
|
|
{
|
|
//
|
|
// nothing to encrypt.
|
|
//
|
|
dwErr = E_INVALIDARG;
|
|
CMTRACE(TEXT("CSecurePassword::EncodePassword - E_INVALIDARG"));
|
|
goto done;
|
|
}
|
|
|
|
|
|
//
|
|
// If Crypt32.DLL is not loaded, try to loaded and get the
|
|
// function pointers.
|
|
//
|
|
if (FALSE == m_fIsLibAndFuncPtrsAvail)
|
|
{
|
|
if (FALSE == this->LoadCrypt32AndGetFuncPtrs())
|
|
{
|
|
//
|
|
// This failed, thus we can't continue. We should free memory.
|
|
//
|
|
this->ClearMemberVars();
|
|
m_fIsEmptyString = TRUE;
|
|
m_fIsHandleToPassword = FALSE;
|
|
|
|
dwErr = ERROR_DLL_INIT_FAILED;
|
|
CMTRACE(TEXT("CSecurePassword::EncodePassword - this-> LoadCrypt32AndGetFuncPtrs failed."));
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
ZeroMemory(pDataBlobPassword, sizeof(DATA_BLOB));
|
|
|
|
DataBlobIn.cbData = cbPassword;
|
|
DataBlobIn.pbData = pbPassword;
|
|
|
|
if (fnCryptProtectData)
|
|
{
|
|
LPCWSTR wszDesc[] = {TEXT("Readable description of data.")};
|
|
LPWSTR pszDesc = NULL;
|
|
|
|
if (OS_W2K)
|
|
{
|
|
//
|
|
// The crypto API needs this, but only on Win2K
|
|
//
|
|
pszDesc = (LPWSTR)wszDesc;
|
|
}
|
|
|
|
if(!fnCryptProtectData(
|
|
&DataBlobIn,
|
|
(LPCWSTR)pszDesc,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
CRYPTPROTECT_UI_FORBIDDEN,
|
|
pDataBlobPassword))
|
|
{
|
|
dwErr = GetLastError();
|
|
CMTRACE1(TEXT("CSecurePassword::EncodePassword - fnCryptProtectData failed. 0x%x"), dwErr);
|
|
|
|
goto done;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CMTRACE(TEXT("CSecurePassword::EncodePassword - ERROR_FUNCTION_NOT_CALLED"));
|
|
dwErr = ERROR_FUNCTION_NOT_CALLED;
|
|
}
|
|
|
|
done:
|
|
|
|
MYDBGASSERT(NO_ERROR == dwErr);
|
|
return dwErr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: DecodePassword
|
|
//
|
|
// Synopsis: Decrypts data using CryptUnprotectData
|
|
//
|
|
// Arguments: pDataBlobPassword - pointer to a DATA_BLOB structure to be decrypted
|
|
// cbPassword - pointer that holds the size of buffer in bytes
|
|
// pbPassword - pointer to a buffer to encrypt
|
|
//
|
|
//
|
|
// Returns: none
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
DWORD CSecurePassword::DecodePassword(IN DATA_BLOB* pDataBlobPassword,
|
|
OUT DWORD* pcbPassword,
|
|
OUT PBYTE* ppbPassword)
|
|
{
|
|
DWORD dwErr = NO_ERROR;
|
|
DATA_BLOB DataOut;
|
|
|
|
if( (NULL == pDataBlobPassword)
|
|
|| (NULL == pcbPassword)
|
|
|| (NULL == ppbPassword))
|
|
{
|
|
dwErr = E_INVALIDARG;
|
|
goto done;
|
|
}
|
|
|
|
*pcbPassword = 0;
|
|
*ppbPassword = NULL;
|
|
|
|
if( (NULL == pDataBlobPassword->pbData)
|
|
|| (0 == pDataBlobPassword->cbData))
|
|
{
|
|
//
|
|
// nothing to decrypt. Just return success.
|
|
//
|
|
goto done;
|
|
}
|
|
|
|
|
|
//
|
|
// If Crypt32.DLL is not loaded, try to loaded and get the
|
|
// function pointers.
|
|
//
|
|
if (FALSE == m_fIsLibAndFuncPtrsAvail)
|
|
{
|
|
if (FALSE == this->LoadCrypt32AndGetFuncPtrs())
|
|
{
|
|
//
|
|
// This failed, thus we can't continue. We should free memory.
|
|
//
|
|
this->ClearMemberVars();
|
|
m_fIsEmptyString = TRUE;
|
|
m_fIsHandleToPassword = FALSE;
|
|
|
|
dwErr = ERROR_DLL_INIT_FAILED;
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
|
|
ZeroMemory(&DataOut, sizeof(DATA_BLOB));
|
|
|
|
if (fnCryptUnprotectData)
|
|
{
|
|
if(!fnCryptUnprotectData(
|
|
pDataBlobPassword,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
CRYPTPROTECT_UI_FORBIDDEN,
|
|
&DataOut))
|
|
{
|
|
dwErr = GetLastError();
|
|
goto done;
|
|
}
|
|
|
|
dwErr = NO_ERROR;
|
|
*pcbPassword = DataOut.cbData;
|
|
*ppbPassword = DataOut.pbData;
|
|
}
|
|
else
|
|
{
|
|
dwErr = ERROR_FUNCTION_NOT_CALLED;
|
|
}
|
|
|
|
|
|
done:
|
|
MYDBGASSERT(NO_ERROR == dwErr);
|
|
|
|
return dwErr;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: FreePassword
|
|
//
|
|
// Synopsis: Frees data in DATA_BLOB structure
|
|
//
|
|
// Arguments: pDBPassword - pointer to a DATA_BLOB structure
|
|
//
|
|
// Returns: none
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::FreePassword(IN DATA_BLOB *pDBPassword)
|
|
{
|
|
if(NULL == pDBPassword)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(NULL != pDBPassword->pbData)
|
|
{
|
|
CmSecureZeroMemory(pDBPassword->pbData, pDBPassword->cbData);
|
|
LocalFree(pDBPassword->pbData);
|
|
}
|
|
|
|
//
|
|
// Clear sensitive data.
|
|
//
|
|
CmSecureZeroMemory(pDBPassword, sizeof(DATA_BLOB));
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: LoadCrypt32AndGetFuncPtrs
|
|
//
|
|
// Synopsis: Loads crypt32.dll and gets function pointer to needed methods
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: TRUE - if .DLL was loaded and function pointers were retrieved
|
|
// FALSE - when an error was encountered
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CSecurePassword::LoadCrypt32AndGetFuncPtrs()
|
|
{
|
|
BOOL fRetVal = FALSE;
|
|
|
|
if (OS_NT5)
|
|
{
|
|
if (FALSE == m_fIsLibAndFuncPtrsAvail)
|
|
{
|
|
fRetVal = m_dllCrypt32.Load(TEXT("crypt32.dll"));
|
|
|
|
if (fRetVal)
|
|
{
|
|
fnCryptProtectData = (fnCryptProtectDataFunc)m_dllCrypt32.GetProcAddress("CryptProtectData");
|
|
fnCryptUnprotectData = (fnCryptUnprotectDataFunc)m_dllCrypt32.GetProcAddress("CryptUnprotectData");
|
|
|
|
if (fnCryptProtectData && fnCryptUnprotectData)
|
|
{
|
|
CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - success"));
|
|
m_fIsLibAndFuncPtrsAvail = TRUE;
|
|
fRetVal = TRUE;
|
|
}
|
|
else
|
|
{
|
|
CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - missing function pointers"));
|
|
|
|
this->UnloadCrypt32();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CMTRACE(TEXT("CSecurePassword::LoadCrypt32AndGetFuncPtrs - m_dllCrypt32.Load failed"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fRetVal = m_fIsLibAndFuncPtrsAvail;
|
|
}
|
|
}
|
|
|
|
MYDBGASSERT(fRetVal);
|
|
|
|
return fRetVal;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsEmptyString
|
|
//
|
|
// Synopsis: Used as a shortcut so we don't have to encrypt/decrypt in case
|
|
// we stored an empty string.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: TRUE - if instance is suppose to be holding an empty string
|
|
// FALSE - if currenttly saved string is not empty
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CSecurePassword::IsEmptyString()
|
|
{
|
|
return m_fIsEmptyString;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: IsHandleToPassword
|
|
//
|
|
// Synopsis: Used as a shortcut so we don't have to encrypt/decrypt in case
|
|
// we stored a handle to a RAS password (16 *).
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: TRUE - if instance is suppose to be holding ****************
|
|
// FALSE - if currenttly saved string is a normal password
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
BOOL CSecurePassword::IsHandleToPassword()
|
|
{
|
|
return m_fIsHandleToPassword;
|
|
}
|
|
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: SetMaxDataLenToProtect
|
|
//
|
|
// Synopsis: Set the maximum length password to protect. This value will be
|
|
// checked when encrypting a password.
|
|
//
|
|
// Arguments: dwMaxDataLen - maximum password length in characters
|
|
//
|
|
// Returns: Nothing
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
VOID CSecurePassword::SetMaxDataLenToProtect(DWORD dwMaxDataLen)
|
|
{
|
|
m_dwMaxDataLen = dwMaxDataLen;
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Function: GetMaxDataLenToProtect
|
|
//
|
|
// Synopsis: Get the maximum length password that this class can protect.
|
|
//
|
|
// Arguments: none
|
|
//
|
|
// Returns: DWORD - maximum password length
|
|
//
|
|
//+----------------------------------------------------------------------------
|
|
DWORD CSecurePassword::GetMaxDataLenToProtect()
|
|
{
|
|
return m_dwMaxDataLen;
|
|
}
|
|
|
|
|
|
#endif // _ICM_INC
|
|
|
|
|