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.
624 lines
17 KiB
624 lines
17 KiB
//////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copyright (c) 2000-2002 Microsoft Corporation
|
|
//
|
|
// Module Name:
|
|
// EncryptedBSTRSrc.cpp
|
|
//
|
|
// Description:
|
|
// Class to encrypt and decrypt BSTRs.
|
|
//
|
|
// Maintained By:
|
|
// John Franco (jfranco) 15-APR-2002
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "EncryptedBSTR.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Type Definitions
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef BOOL (*PFNCRYPTPROTECTMEMORY)( LPVOID, DWORD, DWORD );
|
|
typedef BOOL (*PFNCRYPTUNPROTECTMEMORY)( LPVOID, DWORD, DWORD );
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// class CCryptRoutines
|
|
//
|
|
// Description:
|
|
// CryptProtectMemory and CryptUnprotectMemory are not available on early
|
|
// releases of XP Client, which the admin pack must support. Therefore,
|
|
// we cannot link to those routines implicitly. CCryptRoutines wraps the
|
|
// work of loading crypt32.dll dynamically and looking for the exported
|
|
// functions.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
class CCryptRoutines
|
|
{
|
|
private:
|
|
PFNCRYPTPROTECTMEMORY m_pfnCryptProtectMemory;
|
|
PFNCRYPTUNPROTECTMEMORY m_pfnCryptUnprotectMemory;
|
|
HMODULE m_hmodCrypt32;
|
|
LONG m_nRefCount;
|
|
CRITICAL_SECTION m_cs;
|
|
BOOL m_fCritSecInitialized;
|
|
DWORD m_scLoadStatus;
|
|
|
|
static BOOL S_FBogusCryptRoutine( LPVOID, DWORD, DWORD );
|
|
|
|
public:
|
|
CCryptRoutines( void )
|
|
: m_pfnCryptProtectMemory( NULL )
|
|
, m_pfnCryptUnprotectMemory( NULL )
|
|
, m_hmodCrypt32( NULL )
|
|
, m_nRefCount( 0 )
|
|
, m_fCritSecInitialized( FALSE )
|
|
, m_scLoadStatus( ERROR_SUCCESS )
|
|
{
|
|
m_fCritSecInitialized = InitializeCriticalSectionAndSpinCount( &m_cs, RECOMMENDED_SPIN_COUNT );
|
|
if ( m_fCritSecInitialized == FALSE )
|
|
{
|
|
TW32( GetLastError() );
|
|
} // if
|
|
|
|
} //*** CCryptRoutines::CCryptRoutines
|
|
|
|
~CCryptRoutines( void )
|
|
{
|
|
if ( m_hmodCrypt32 != NULL )
|
|
{
|
|
FreeLibrary( m_hmodCrypt32 );
|
|
}
|
|
|
|
if ( m_fCritSecInitialized )
|
|
{
|
|
DeleteCriticalSection( &m_cs );
|
|
}
|
|
|
|
} //*** CCryptRoutines::~CCryptRoutines
|
|
|
|
void AddReferenceToRoutines( void );
|
|
void ReleaseReferenceToRoutines( void );
|
|
|
|
BOOL
|
|
CryptProtectMemory(
|
|
IN OUT LPVOID pDataIn, // in out data to encrypt
|
|
IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
|
|
);
|
|
|
|
BOOL
|
|
CryptUnprotectMemory(
|
|
IN OUT LPVOID pDataIn, // in out data to decrypt
|
|
IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
|
|
);
|
|
|
|
}; //*** class CCryptRoutines
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// Global Variables
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
static CCryptRoutines g_crCryptRoutines;
|
|
|
|
|
|
//****************************************************************************
|
|
//
|
|
// CCryptRoutines
|
|
//
|
|
//****************************************************************************
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CCryptRoutines::AddReferenceToRoutines
|
|
//
|
|
// Description:
|
|
// Add a reference to the routines and load the addresses of the APIs
|
|
// if not already done so.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CCryptRoutines::AddReferenceToRoutines( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
if ( m_fCritSecInitialized )
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
m_nRefCount += 1;
|
|
|
|
if ( m_nRefCount == 1 )
|
|
{
|
|
Assert( m_hmodCrypt32 == NULL );
|
|
|
|
//
|
|
// Load the DLL containing the APIs.
|
|
//
|
|
|
|
m_hmodCrypt32 = LoadLibraryW( L"crypt32.dll" );
|
|
if ( m_hmodCrypt32 == NULL )
|
|
{
|
|
m_scLoadStatus = TW32( GetLastError() );
|
|
goto Cleanup;
|
|
} // if: error loading the DLL
|
|
|
|
//
|
|
// Get the address of the APIs.
|
|
//
|
|
|
|
m_pfnCryptProtectMemory = reinterpret_cast< PFNCRYPTPROTECTMEMORY >( GetProcAddress( m_hmodCrypt32, "CryptProtectMemory" ) );
|
|
if ( m_pfnCryptProtectMemory == NULL )
|
|
{
|
|
m_scLoadStatus = TW32( GetLastError() );
|
|
goto Cleanup;
|
|
} // if
|
|
|
|
m_pfnCryptUnprotectMemory = reinterpret_cast< PFNCRYPTUNPROTECTMEMORY >( GetProcAddress( m_hmodCrypt32, "CryptUnprotectMemory" ) );
|
|
if ( m_pfnCryptProtectMemory == NULL )
|
|
{
|
|
m_scLoadStatus = TW32( GetLastError() );
|
|
m_pfnCryptProtectMemory = NULL;
|
|
goto Cleanup;
|
|
} // if
|
|
} // if: first reference
|
|
} // if critical section is initialized.
|
|
|
|
Cleanup:
|
|
|
|
if ( m_pfnCryptProtectMemory == NULL )
|
|
{
|
|
m_pfnCryptProtectMemory = S_FBogusCryptRoutine;
|
|
} // if
|
|
|
|
if ( m_pfnCryptUnprotectMemory == NULL )
|
|
{
|
|
m_pfnCryptUnprotectMemory = S_FBogusCryptRoutine;
|
|
} // if
|
|
|
|
if ( m_fCritSecInitialized )
|
|
{
|
|
LeaveCriticalSection( &m_cs );
|
|
} // if
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CCryptRoutines::AddReferenceToRoutines
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CCryptRoutines::ReleaseReferenceToRoutines
|
|
//
|
|
// Description:
|
|
// Release a reference to the routines and free the library if this was
|
|
// the last reference.
|
|
//
|
|
// Arguments:
|
|
// None.
|
|
//
|
|
// Return Values:
|
|
// None.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
void
|
|
CCryptRoutines::ReleaseReferenceToRoutines( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
if ( m_fCritSecInitialized )
|
|
{
|
|
EnterCriticalSection( &m_cs );
|
|
|
|
m_nRefCount -= 1;
|
|
|
|
if ( m_nRefCount == 0 )
|
|
{
|
|
Assert( m_hmodCrypt32 != NULL );
|
|
if ( m_hmodCrypt32 != NULL )
|
|
{
|
|
FreeLibrary( m_hmodCrypt32 );
|
|
m_hmodCrypt32 = NULL;
|
|
m_pfnCryptProtectMemory = NULL;
|
|
m_pfnCryptUnprotectMemory = NULL;
|
|
} // if
|
|
} // if: last reference was released
|
|
|
|
LeaveCriticalSection( &m_cs );
|
|
} // if
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CCryptRoutines::ReleaseReferenceToRoutines
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CCryptRoutines::CryptProtectMemory
|
|
//
|
|
// Description:
|
|
// Encrypt memory. Required since XP doesn't have CryptProtectMemory.
|
|
//
|
|
// Arguments:
|
|
// pDataIn
|
|
// cbDataIn
|
|
// dwFlags
|
|
//
|
|
// Return Values:
|
|
// TRUE - Operation was successful.
|
|
// FALSE - Operation failed. Call GetLastError().
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CCryptRoutines::CryptProtectMemory(
|
|
IN OUT LPVOID pDataIn, // in out data to encrypt
|
|
IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
BOOL fSuccess = TRUE;
|
|
DWORD sc = ERROR_SUCCESS;
|
|
|
|
fSuccess = (*m_pfnCryptProtectMemory)( pDataIn, cbDataIn, dwFlags );
|
|
if ( fSuccess == FALSE )
|
|
{
|
|
sc = TW32( GetLastError() );
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// Only needed for debug builds because TW32 might overwrite the last error.
|
|
SetLastError( sc );
|
|
#endif
|
|
RETURN( fSuccess );
|
|
|
|
} //*** CCryptRoutines::CryptProtectMemory
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CCryptRoutines::CryptUnprotectMemory
|
|
//
|
|
// Description:
|
|
// Decrypt memory. Required since XP doesn't have CryptUnprotectMemory.
|
|
//
|
|
// Arguments:
|
|
// pDataIn
|
|
// cbDataIn
|
|
// dwFlags
|
|
//
|
|
// Return Values:
|
|
// TRUE - Operation was successful.
|
|
// FALSE - Operation failed. Call GetLastError().
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CCryptRoutines::CryptUnprotectMemory(
|
|
IN OUT LPVOID pDataIn, // in out data to decrypt
|
|
IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
BOOL fSuccess = TRUE;
|
|
DWORD sc = ERROR_SUCCESS;
|
|
|
|
fSuccess = (*m_pfnCryptUnprotectMemory)( pDataIn, cbDataIn, dwFlags );
|
|
if ( fSuccess == FALSE )
|
|
{
|
|
sc = TW32( GetLastError() );
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
// Only needed for debug builds because TW32 might overwrite the last error.
|
|
SetLastError( sc );
|
|
#endif
|
|
RETURN( fSuccess );
|
|
|
|
} //*** CCryptRoutines::CryptUnprotectMemory
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CCryptRoutines::S_FBogusCryptRoutine
|
|
//
|
|
// Description:
|
|
// Stand-in function for when the routines are not available.
|
|
//
|
|
// Arguments:
|
|
// LPVOID
|
|
// DWORD
|
|
// DWORD
|
|
//
|
|
// Return Values:
|
|
// TRUE - Pretend always to succeed.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
BOOL
|
|
CCryptRoutines::S_FBogusCryptRoutine( LPVOID, DWORD, DWORD )
|
|
{
|
|
return TRUE;
|
|
|
|
} //*** CCryptRoutines::S_FBogusCryptRoutine
|
|
|
|
|
|
//****************************************************************************
|
|
//
|
|
// CEncryptedBSTR
|
|
//
|
|
//****************************************************************************
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CEncryptedBSTR::CEncryptedBSTR
|
|
//
|
|
// Description:
|
|
// Default constructor.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CEncryptedBSTR::CEncryptedBSTR( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
m_dbBSTR.cbData = 0;
|
|
m_dbBSTR.pbData = NULL;
|
|
|
|
g_crCryptRoutines.AddReferenceToRoutines();
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CEncryptedBSTR::CEncryptedBSTR
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CEncryptedBSTR::~CEncryptedBSTR
|
|
//
|
|
// Description:
|
|
// Destructor.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
CEncryptedBSTR::~CEncryptedBSTR( void )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
Erase();
|
|
|
|
g_crCryptRoutines.ReleaseReferenceToRoutines();
|
|
|
|
TraceFuncExit();
|
|
|
|
} //*** CEncryptedBSTR::~CEncryptedBSTR
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CEncryptedBSTR::HrSetWSTR
|
|
//
|
|
// Description:
|
|
// Set new data into this object to be stored as encrypted data.
|
|
//
|
|
// Arguments:
|
|
// pcwszIn - String to store.
|
|
// cchIn - Number of characters in the string, not including NUL.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CEncryptedBSTR::HrSetWSTR(
|
|
PCWSTR pcwszIn
|
|
, size_t cchIn
|
|
)
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
DATA_BLOB dbEncrypted = { 0, NULL };
|
|
|
|
if ( cchIn > 0 )
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
DWORD cbStringAndNull = (DWORD) ( ( cchIn + 1 ) * sizeof( *pcwszIn ) );
|
|
DWORD cBlocks = ( cbStringAndNull / CRYPTPROTECTMEMORY_BLOCK_SIZE ) + 1;
|
|
DWORD cbMemoryRequired = cBlocks * CRYPTPROTECTMEMORY_BLOCK_SIZE;
|
|
|
|
dbEncrypted.pbData = new BYTE[ cbMemoryRequired ];
|
|
if ( dbEncrypted.pbData == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
}
|
|
dbEncrypted.cbData = cbMemoryRequired;
|
|
|
|
CopyMemory( dbEncrypted.pbData, pcwszIn, cbStringAndNull );
|
|
fSuccess = g_crCryptRoutines.CryptProtectMemory( dbEncrypted.pbData, dbEncrypted.cbData, CRYPTPROTECTMEMORY_SAME_PROCESS );
|
|
if ( fSuccess == FALSE )
|
|
{
|
|
DWORD scLastError = TW32( GetLastError() );
|
|
hr = HRESULT_FROM_WIN32( scLastError );
|
|
goto Cleanup;
|
|
} // if: error from CryptProtectMemory
|
|
|
|
Erase();
|
|
m_dbBSTR = dbEncrypted;
|
|
dbEncrypted.pbData = NULL;
|
|
dbEncrypted.cbData = 0;
|
|
} // if: input data is not empty
|
|
else
|
|
{
|
|
Erase();
|
|
} // else: input data is empty
|
|
|
|
Cleanup:
|
|
|
|
if ( dbEncrypted.pbData != NULL )
|
|
{
|
|
delete [] dbEncrypted.pbData;
|
|
}
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CEncryptedBSTR::HrSetWSTR
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CEncryptedBSTR::HrGetBSTR
|
|
//
|
|
// Description:
|
|
// Retrieve an unencrypted copy of the data.
|
|
//
|
|
// Arguments:
|
|
// pbstrOut - BSTR to return data in.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// E_OUTOFMEMORY - Error allocating memory.
|
|
// Other HRESULTs.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CEncryptedBSTR::HrGetBSTR( BSTR * pbstrOut ) const
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
BYTE * pbDecrypted = NULL;
|
|
|
|
if ( pbstrOut == NULL )
|
|
{
|
|
hr = THR( E_POINTER );
|
|
goto Cleanup;
|
|
}
|
|
*pbstrOut = NULL;
|
|
|
|
if ( m_dbBSTR.cbData > 0 )
|
|
{
|
|
BOOL fSuccess = FALSE;
|
|
|
|
pbDecrypted = new BYTE[ m_dbBSTR.cbData ];
|
|
if ( pbDecrypted == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
}
|
|
|
|
CopyMemory( pbDecrypted, m_dbBSTR.pbData, m_dbBSTR.cbData );
|
|
fSuccess = g_crCryptRoutines.CryptUnprotectMemory( pbDecrypted, m_dbBSTR.cbData, CRYPTPROTECTMEMORY_SAME_PROCESS );
|
|
if ( fSuccess == FALSE )
|
|
{
|
|
DWORD scLastError = TW32( GetLastError() );
|
|
hr = HRESULT_FROM_WIN32( scLastError );
|
|
goto Cleanup;
|
|
} // if: error from CryptUnprotectMemory
|
|
|
|
*pbstrOut = TraceSysAllocString( reinterpret_cast< const OLECHAR* >( pbDecrypted ) );
|
|
if ( *pbstrOut == NULL )
|
|
{
|
|
hr = E_OUTOFMEMORY;
|
|
goto Cleanup;
|
|
}
|
|
} // if: data is not empty
|
|
else // nothing to decrypt
|
|
{
|
|
hr = S_FALSE;
|
|
} // else: data is empty
|
|
|
|
Cleanup:
|
|
|
|
if ( pbDecrypted != NULL )
|
|
{
|
|
::SecureZeroMemory( pbDecrypted, m_dbBSTR.cbData );
|
|
delete [] pbDecrypted;
|
|
}
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CEncryptedBSTR::HrGetBSTR
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
//++
|
|
//
|
|
// CEncryptedBSTR::HrAssign
|
|
//
|
|
// Description:
|
|
// Make a copy of another encrypted BSTR object to replace the
|
|
// content we are currently holding.
|
|
//
|
|
// Arguments:
|
|
// rSourceIn - Object to copy.
|
|
//
|
|
// Return Values:
|
|
// S_OK - Operation completed successfully.
|
|
// E_OUTOFMEMORY - Error allocating memory.
|
|
//
|
|
//--
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
HRESULT
|
|
CEncryptedBSTR::HrAssign( const CEncryptedBSTR & rSourceIn )
|
|
{
|
|
TraceFunc( "" );
|
|
|
|
HRESULT hr = S_OK;
|
|
BYTE * pbCopy = NULL;
|
|
|
|
if ( rSourceIn.m_dbBSTR.cbData > 0 )
|
|
{
|
|
pbCopy = new BYTE[ rSourceIn.m_dbBSTR.cbData ];
|
|
if ( pbCopy == NULL )
|
|
{
|
|
hr = THR( E_OUTOFMEMORY );
|
|
goto Cleanup;
|
|
}
|
|
CopyMemory( pbCopy, rSourceIn.m_dbBSTR.pbData, rSourceIn.m_dbBSTR.cbData );
|
|
|
|
Erase();
|
|
m_dbBSTR.cbData = rSourceIn.m_dbBSTR.cbData;
|
|
m_dbBSTR.pbData = pbCopy;
|
|
pbCopy = NULL;
|
|
} // if: input data is not empty
|
|
else
|
|
{
|
|
Erase();
|
|
} // else: input data is empty
|
|
|
|
Cleanup:
|
|
|
|
if ( pbCopy != NULL )
|
|
{
|
|
::SecureZeroMemory( pbCopy, rSourceIn.m_dbBSTR.cbData );
|
|
delete [] pbCopy;
|
|
}
|
|
|
|
HRETURN( hr );
|
|
|
|
} //*** CEncryptedBSTR::HrAssign
|