Leaked source code of windows server 2003
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

//////////////////////////////////////////////////////////////////////////////
//
// 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