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

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2000-2002 Microsoft Corporation
  4. //
  5. // Module Name:
  6. // EncryptedBSTRSrc.cpp
  7. //
  8. // Description:
  9. // Class to encrypt and decrypt BSTRs.
  10. //
  11. // Maintained By:
  12. // John Franco (jfranco) 15-APR-2002
  13. //
  14. //////////////////////////////////////////////////////////////////////////////
  15. #include "EncryptedBSTR.h"
  16. //////////////////////////////////////////////////////////////////////////////
  17. // Type Definitions
  18. //////////////////////////////////////////////////////////////////////////////
  19. typedef BOOL (*PFNCRYPTPROTECTMEMORY)( LPVOID, DWORD, DWORD );
  20. typedef BOOL (*PFNCRYPTUNPROTECTMEMORY)( LPVOID, DWORD, DWORD );
  21. //////////////////////////////////////////////////////////////////////////////
  22. //++
  23. //
  24. // class CCryptRoutines
  25. //
  26. // Description:
  27. // CryptProtectMemory and CryptUnprotectMemory are not available on early
  28. // releases of XP Client, which the admin pack must support. Therefore,
  29. // we cannot link to those routines implicitly. CCryptRoutines wraps the
  30. // work of loading crypt32.dll dynamically and looking for the exported
  31. // functions.
  32. //
  33. //--
  34. //////////////////////////////////////////////////////////////////////////////
  35. class CCryptRoutines
  36. {
  37. private:
  38. PFNCRYPTPROTECTMEMORY m_pfnCryptProtectMemory;
  39. PFNCRYPTUNPROTECTMEMORY m_pfnCryptUnprotectMemory;
  40. HMODULE m_hmodCrypt32;
  41. LONG m_nRefCount;
  42. CRITICAL_SECTION m_cs;
  43. BOOL m_fCritSecInitialized;
  44. DWORD m_scLoadStatus;
  45. static BOOL S_FBogusCryptRoutine( LPVOID, DWORD, DWORD );
  46. public:
  47. CCryptRoutines( void )
  48. : m_pfnCryptProtectMemory( NULL )
  49. , m_pfnCryptUnprotectMemory( NULL )
  50. , m_hmodCrypt32( NULL )
  51. , m_nRefCount( 0 )
  52. , m_fCritSecInitialized( FALSE )
  53. , m_scLoadStatus( ERROR_SUCCESS )
  54. {
  55. m_fCritSecInitialized = InitializeCriticalSectionAndSpinCount( &m_cs, RECOMMENDED_SPIN_COUNT );
  56. if ( m_fCritSecInitialized == FALSE )
  57. {
  58. TW32( GetLastError() );
  59. } // if
  60. } //*** CCryptRoutines::CCryptRoutines
  61. ~CCryptRoutines( void )
  62. {
  63. if ( m_hmodCrypt32 != NULL )
  64. {
  65. FreeLibrary( m_hmodCrypt32 );
  66. }
  67. if ( m_fCritSecInitialized )
  68. {
  69. DeleteCriticalSection( &m_cs );
  70. }
  71. } //*** CCryptRoutines::~CCryptRoutines
  72. void AddReferenceToRoutines( void );
  73. void ReleaseReferenceToRoutines( void );
  74. BOOL
  75. CryptProtectMemory(
  76. IN OUT LPVOID pDataIn, // in out data to encrypt
  77. IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
  78. IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
  79. );
  80. BOOL
  81. CryptUnprotectMemory(
  82. IN OUT LPVOID pDataIn, // in out data to decrypt
  83. IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
  84. IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
  85. );
  86. }; //*** class CCryptRoutines
  87. //////////////////////////////////////////////////////////////////////////////
  88. // Global Variables
  89. //////////////////////////////////////////////////////////////////////////////
  90. static CCryptRoutines g_crCryptRoutines;
  91. //****************************************************************************
  92. //
  93. // CCryptRoutines
  94. //
  95. //****************************************************************************
  96. //////////////////////////////////////////////////////////////////////////////
  97. //++
  98. //
  99. // CCryptRoutines::AddReferenceToRoutines
  100. //
  101. // Description:
  102. // Add a reference to the routines and load the addresses of the APIs
  103. // if not already done so.
  104. //
  105. // Arguments:
  106. // None.
  107. //
  108. // Return Values:
  109. // None.
  110. //
  111. //--
  112. //////////////////////////////////////////////////////////////////////////////
  113. void
  114. CCryptRoutines::AddReferenceToRoutines( void )
  115. {
  116. TraceFunc( "" );
  117. if ( m_fCritSecInitialized )
  118. {
  119. EnterCriticalSection( &m_cs );
  120. m_nRefCount += 1;
  121. if ( m_nRefCount == 1 )
  122. {
  123. Assert( m_hmodCrypt32 == NULL );
  124. //
  125. // Load the DLL containing the APIs.
  126. //
  127. m_hmodCrypt32 = LoadLibraryW( L"crypt32.dll" );
  128. if ( m_hmodCrypt32 == NULL )
  129. {
  130. m_scLoadStatus = TW32( GetLastError() );
  131. goto Cleanup;
  132. } // if: error loading the DLL
  133. //
  134. // Get the address of the APIs.
  135. //
  136. m_pfnCryptProtectMemory = reinterpret_cast< PFNCRYPTPROTECTMEMORY >( GetProcAddress( m_hmodCrypt32, "CryptProtectMemory" ) );
  137. if ( m_pfnCryptProtectMemory == NULL )
  138. {
  139. m_scLoadStatus = TW32( GetLastError() );
  140. goto Cleanup;
  141. } // if
  142. m_pfnCryptUnprotectMemory = reinterpret_cast< PFNCRYPTUNPROTECTMEMORY >( GetProcAddress( m_hmodCrypt32, "CryptUnprotectMemory" ) );
  143. if ( m_pfnCryptProtectMemory == NULL )
  144. {
  145. m_scLoadStatus = TW32( GetLastError() );
  146. m_pfnCryptProtectMemory = NULL;
  147. goto Cleanup;
  148. } // if
  149. } // if: first reference
  150. } // if critical section is initialized.
  151. Cleanup:
  152. if ( m_pfnCryptProtectMemory == NULL )
  153. {
  154. m_pfnCryptProtectMemory = S_FBogusCryptRoutine;
  155. } // if
  156. if ( m_pfnCryptUnprotectMemory == NULL )
  157. {
  158. m_pfnCryptUnprotectMemory = S_FBogusCryptRoutine;
  159. } // if
  160. if ( m_fCritSecInitialized )
  161. {
  162. LeaveCriticalSection( &m_cs );
  163. } // if
  164. TraceFuncExit();
  165. } //*** CCryptRoutines::AddReferenceToRoutines
  166. //////////////////////////////////////////////////////////////////////////////
  167. //++
  168. //
  169. // CCryptRoutines::ReleaseReferenceToRoutines
  170. //
  171. // Description:
  172. // Release a reference to the routines and free the library if this was
  173. // the last reference.
  174. //
  175. // Arguments:
  176. // None.
  177. //
  178. // Return Values:
  179. // None.
  180. //
  181. //--
  182. //////////////////////////////////////////////////////////////////////////////
  183. void
  184. CCryptRoutines::ReleaseReferenceToRoutines( void )
  185. {
  186. TraceFunc( "" );
  187. if ( m_fCritSecInitialized )
  188. {
  189. EnterCriticalSection( &m_cs );
  190. m_nRefCount -= 1;
  191. if ( m_nRefCount == 0 )
  192. {
  193. Assert( m_hmodCrypt32 != NULL );
  194. if ( m_hmodCrypt32 != NULL )
  195. {
  196. FreeLibrary( m_hmodCrypt32 );
  197. m_hmodCrypt32 = NULL;
  198. m_pfnCryptProtectMemory = NULL;
  199. m_pfnCryptUnprotectMemory = NULL;
  200. } // if
  201. } // if: last reference was released
  202. LeaveCriticalSection( &m_cs );
  203. } // if
  204. TraceFuncExit();
  205. } //*** CCryptRoutines::ReleaseReferenceToRoutines
  206. //////////////////////////////////////////////////////////////////////////////
  207. //++
  208. //
  209. // CCryptRoutines::CryptProtectMemory
  210. //
  211. // Description:
  212. // Encrypt memory. Required since XP doesn't have CryptProtectMemory.
  213. //
  214. // Arguments:
  215. // pDataIn
  216. // cbDataIn
  217. // dwFlags
  218. //
  219. // Return Values:
  220. // TRUE - Operation was successful.
  221. // FALSE - Operation failed. Call GetLastError().
  222. //
  223. //--
  224. //////////////////////////////////////////////////////////////////////////////
  225. BOOL
  226. CCryptRoutines::CryptProtectMemory(
  227. IN OUT LPVOID pDataIn, // in out data to encrypt
  228. IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
  229. IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
  230. )
  231. {
  232. TraceFunc( "" );
  233. BOOL fSuccess = TRUE;
  234. DWORD sc = ERROR_SUCCESS;
  235. fSuccess = (*m_pfnCryptProtectMemory)( pDataIn, cbDataIn, dwFlags );
  236. if ( fSuccess == FALSE )
  237. {
  238. sc = TW32( GetLastError() );
  239. }
  240. #ifdef DEBUG
  241. // Only needed for debug builds because TW32 might overwrite the last error.
  242. SetLastError( sc );
  243. #endif
  244. RETURN( fSuccess );
  245. } //*** CCryptRoutines::CryptProtectMemory
  246. //////////////////////////////////////////////////////////////////////////////
  247. //++
  248. //
  249. // CCryptRoutines::CryptUnprotectMemory
  250. //
  251. // Description:
  252. // Decrypt memory. Required since XP doesn't have CryptUnprotectMemory.
  253. //
  254. // Arguments:
  255. // pDataIn
  256. // cbDataIn
  257. // dwFlags
  258. //
  259. // Return Values:
  260. // TRUE - Operation was successful.
  261. // FALSE - Operation failed. Call GetLastError().
  262. //
  263. //--
  264. //////////////////////////////////////////////////////////////////////////////
  265. BOOL
  266. CCryptRoutines::CryptUnprotectMemory(
  267. IN OUT LPVOID pDataIn, // in out data to decrypt
  268. IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
  269. IN DWORD dwFlags // CRYPTPROTECTMEMORY_* flags from wincrypt.h
  270. )
  271. {
  272. TraceFunc( "" );
  273. BOOL fSuccess = TRUE;
  274. DWORD sc = ERROR_SUCCESS;
  275. fSuccess = (*m_pfnCryptUnprotectMemory)( pDataIn, cbDataIn, dwFlags );
  276. if ( fSuccess == FALSE )
  277. {
  278. sc = TW32( GetLastError() );
  279. }
  280. #ifdef DEBUG
  281. // Only needed for debug builds because TW32 might overwrite the last error.
  282. SetLastError( sc );
  283. #endif
  284. RETURN( fSuccess );
  285. } //*** CCryptRoutines::CryptUnprotectMemory
  286. //////////////////////////////////////////////////////////////////////////////
  287. //++
  288. //
  289. // CCryptRoutines::S_FBogusCryptRoutine
  290. //
  291. // Description:
  292. // Stand-in function for when the routines are not available.
  293. //
  294. // Arguments:
  295. // LPVOID
  296. // DWORD
  297. // DWORD
  298. //
  299. // Return Values:
  300. // TRUE - Pretend always to succeed.
  301. //
  302. //--
  303. //////////////////////////////////////////////////////////////////////////////
  304. BOOL
  305. CCryptRoutines::S_FBogusCryptRoutine( LPVOID, DWORD, DWORD )
  306. {
  307. return TRUE;
  308. } //*** CCryptRoutines::S_FBogusCryptRoutine
  309. //****************************************************************************
  310. //
  311. // CEncryptedBSTR
  312. //
  313. //****************************************************************************
  314. //////////////////////////////////////////////////////////////////////////////
  315. //++
  316. //
  317. // CEncryptedBSTR::CEncryptedBSTR
  318. //
  319. // Description:
  320. // Default constructor.
  321. //
  322. //--
  323. //////////////////////////////////////////////////////////////////////////////
  324. CEncryptedBSTR::CEncryptedBSTR( void )
  325. {
  326. TraceFunc( "" );
  327. m_dbBSTR.cbData = 0;
  328. m_dbBSTR.pbData = NULL;
  329. g_crCryptRoutines.AddReferenceToRoutines();
  330. TraceFuncExit();
  331. } //*** CEncryptedBSTR::CEncryptedBSTR
  332. //////////////////////////////////////////////////////////////////////////////
  333. //++
  334. //
  335. // CEncryptedBSTR::~CEncryptedBSTR
  336. //
  337. // Description:
  338. // Destructor.
  339. //
  340. //--
  341. //////////////////////////////////////////////////////////////////////////////
  342. CEncryptedBSTR::~CEncryptedBSTR( void )
  343. {
  344. TraceFunc( "" );
  345. Erase();
  346. g_crCryptRoutines.ReleaseReferenceToRoutines();
  347. TraceFuncExit();
  348. } //*** CEncryptedBSTR::~CEncryptedBSTR
  349. //////////////////////////////////////////////////////////////////////////////
  350. //++
  351. //
  352. // CEncryptedBSTR::HrSetWSTR
  353. //
  354. // Description:
  355. // Set new data into this object to be stored as encrypted data.
  356. //
  357. // Arguments:
  358. // pcwszIn - String to store.
  359. // cchIn - Number of characters in the string, not including NUL.
  360. //
  361. // Return Values:
  362. // S_OK - Operation completed successfully.
  363. // Other HRESULTs.
  364. //
  365. //--
  366. //////////////////////////////////////////////////////////////////////////////
  367. HRESULT
  368. CEncryptedBSTR::HrSetWSTR(
  369. PCWSTR pcwszIn
  370. , size_t cchIn
  371. )
  372. {
  373. TraceFunc( "" );
  374. HRESULT hr = S_OK;
  375. DATA_BLOB dbEncrypted = { 0, NULL };
  376. if ( cchIn > 0 )
  377. {
  378. BOOL fSuccess = FALSE;
  379. DWORD cbStringAndNull = (DWORD) ( ( cchIn + 1 ) * sizeof( *pcwszIn ) );
  380. DWORD cBlocks = ( cbStringAndNull / CRYPTPROTECTMEMORY_BLOCK_SIZE ) + 1;
  381. DWORD cbMemoryRequired = cBlocks * CRYPTPROTECTMEMORY_BLOCK_SIZE;
  382. dbEncrypted.pbData = new BYTE[ cbMemoryRequired ];
  383. if ( dbEncrypted.pbData == NULL )
  384. {
  385. hr = THR( E_OUTOFMEMORY );
  386. goto Cleanup;
  387. }
  388. dbEncrypted.cbData = cbMemoryRequired;
  389. CopyMemory( dbEncrypted.pbData, pcwszIn, cbStringAndNull );
  390. fSuccess = g_crCryptRoutines.CryptProtectMemory( dbEncrypted.pbData, dbEncrypted.cbData, CRYPTPROTECTMEMORY_SAME_PROCESS );
  391. if ( fSuccess == FALSE )
  392. {
  393. DWORD scLastError = TW32( GetLastError() );
  394. hr = HRESULT_FROM_WIN32( scLastError );
  395. goto Cleanup;
  396. } // if: error from CryptProtectMemory
  397. Erase();
  398. m_dbBSTR = dbEncrypted;
  399. dbEncrypted.pbData = NULL;
  400. dbEncrypted.cbData = 0;
  401. } // if: input data is not empty
  402. else
  403. {
  404. Erase();
  405. } // else: input data is empty
  406. Cleanup:
  407. if ( dbEncrypted.pbData != NULL )
  408. {
  409. delete [] dbEncrypted.pbData;
  410. }
  411. HRETURN( hr );
  412. } //*** CEncryptedBSTR::HrSetWSTR
  413. //////////////////////////////////////////////////////////////////////////////
  414. //++
  415. //
  416. // CEncryptedBSTR::HrGetBSTR
  417. //
  418. // Description:
  419. // Retrieve an unencrypted copy of the data.
  420. //
  421. // Arguments:
  422. // pbstrOut - BSTR to return data in.
  423. //
  424. // Return Values:
  425. // S_OK - Operation completed successfully.
  426. // E_OUTOFMEMORY - Error allocating memory.
  427. // Other HRESULTs.
  428. //
  429. //--
  430. //////////////////////////////////////////////////////////////////////////////
  431. HRESULT
  432. CEncryptedBSTR::HrGetBSTR( BSTR * pbstrOut ) const
  433. {
  434. TraceFunc( "" );
  435. HRESULT hr = S_OK;
  436. BYTE * pbDecrypted = NULL;
  437. if ( pbstrOut == NULL )
  438. {
  439. hr = THR( E_POINTER );
  440. goto Cleanup;
  441. }
  442. *pbstrOut = NULL;
  443. if ( m_dbBSTR.cbData > 0 )
  444. {
  445. BOOL fSuccess = FALSE;
  446. pbDecrypted = new BYTE[ m_dbBSTR.cbData ];
  447. if ( pbDecrypted == NULL )
  448. {
  449. hr = THR( E_OUTOFMEMORY );
  450. goto Cleanup;
  451. }
  452. CopyMemory( pbDecrypted, m_dbBSTR.pbData, m_dbBSTR.cbData );
  453. fSuccess = g_crCryptRoutines.CryptUnprotectMemory( pbDecrypted, m_dbBSTR.cbData, CRYPTPROTECTMEMORY_SAME_PROCESS );
  454. if ( fSuccess == FALSE )
  455. {
  456. DWORD scLastError = TW32( GetLastError() );
  457. hr = HRESULT_FROM_WIN32( scLastError );
  458. goto Cleanup;
  459. } // if: error from CryptUnprotectMemory
  460. *pbstrOut = TraceSysAllocString( reinterpret_cast< const OLECHAR* >( pbDecrypted ) );
  461. if ( *pbstrOut == NULL )
  462. {
  463. hr = E_OUTOFMEMORY;
  464. goto Cleanup;
  465. }
  466. } // if: data is not empty
  467. else // nothing to decrypt
  468. {
  469. hr = S_FALSE;
  470. } // else: data is empty
  471. Cleanup:
  472. if ( pbDecrypted != NULL )
  473. {
  474. ::SecureZeroMemory( pbDecrypted, m_dbBSTR.cbData );
  475. delete [] pbDecrypted;
  476. }
  477. HRETURN( hr );
  478. } //*** CEncryptedBSTR::HrGetBSTR
  479. //////////////////////////////////////////////////////////////////////////////
  480. //++
  481. //
  482. // CEncryptedBSTR::HrAssign
  483. //
  484. // Description:
  485. // Make a copy of another encrypted BSTR object to replace the
  486. // content we are currently holding.
  487. //
  488. // Arguments:
  489. // rSourceIn - Object to copy.
  490. //
  491. // Return Values:
  492. // S_OK - Operation completed successfully.
  493. // E_OUTOFMEMORY - Error allocating memory.
  494. //
  495. //--
  496. //////////////////////////////////////////////////////////////////////////////
  497. HRESULT
  498. CEncryptedBSTR::HrAssign( const CEncryptedBSTR & rSourceIn )
  499. {
  500. TraceFunc( "" );
  501. HRESULT hr = S_OK;
  502. BYTE * pbCopy = NULL;
  503. if ( rSourceIn.m_dbBSTR.cbData > 0 )
  504. {
  505. pbCopy = new BYTE[ rSourceIn.m_dbBSTR.cbData ];
  506. if ( pbCopy == NULL )
  507. {
  508. hr = THR( E_OUTOFMEMORY );
  509. goto Cleanup;
  510. }
  511. CopyMemory( pbCopy, rSourceIn.m_dbBSTR.pbData, rSourceIn.m_dbBSTR.cbData );
  512. Erase();
  513. m_dbBSTR.cbData = rSourceIn.m_dbBSTR.cbData;
  514. m_dbBSTR.pbData = pbCopy;
  515. pbCopy = NULL;
  516. } // if: input data is not empty
  517. else
  518. {
  519. Erase();
  520. } // else: input data is empty
  521. Cleanup:
  522. if ( pbCopy != NULL )
  523. {
  524. ::SecureZeroMemory( pbCopy, rSourceIn.m_dbBSTR.cbData );
  525. delete [] pbCopy;
  526. }
  527. HRETURN( hr );
  528. } //*** CEncryptedBSTR::HrAssign