Source code of Windows XP (NT5)
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.

1668 lines
52 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: cmsecure.cpp
  4. //
  5. // Module: CMSECURE.LIB
  6. //
  7. // Synopsis: CM Crypto APIs
  8. // Three methods are support for decryption:
  9. // CBCEncryption CMSECURE_ET_CBC_CIPHER
  10. // Simple xor encryption CMSECURE_ET_STREAM_CIPHER
  11. // CryptoApi CMSECURE_ET_RC2
  12. // Two methods are supported for encryption
  13. // CBCEncryption
  14. // CryptoApi
  15. //
  16. // CBCEncryption algorithm: Cipher Block Chaining Mode with initializing variable
  17. // EnCipher: C[i] = E[k](p[i] XOR C[i-1])
  18. // DeCipher: P[i] = C[i-1] XOR D[k](C[i])
  19. // P: Plain text
  20. // C: Cipher text
  21. // E[k]: Encryption function with key
  22. // D[k]: Decryption function with key
  23. //
  24. // Copyright (c) 1996-1998 Microsoft Corporation
  25. //
  26. // Author: henryt created 05/21/97
  27. // fengsun changed encryption algorithm 08/21/97
  28. //
  29. //+----------------------------------------------------------------------------
  30. #include "cryptfnc.h"
  31. #include "userinfo_str.h"
  32. //////////////////////////////////////////////////////////////////////////
  33. // defines
  34. //////////////////////////////////////////////////////////////////////////
  35. // we want 40-bit encryption exactly for pre-shared key
  36. const DWORD c_dwEncryptKeyLength = 40;
  37. //
  38. // the max len for the const string for session key generation
  39. //
  40. #define MAX_KEY_STRING_LEN 40
  41. #define EXTRA_UUDECODE_BUF_LEN 10
  42. //////////////////////////////////////////////////////////////////////////
  43. // Globals
  44. //////////////////////////////////////////////////////////////////////////
  45. static CCryptFunctions* g_pCryptFnc = NULL;
  46. static long g_nRefCount=0; // the reference count, CryptoApi is unloaded when the count is 0
  47. static BOOL g_fFastEncryption;
  48. //
  49. // the const string for session key generation
  50. //
  51. static const TCHAR gc_szKeyStr[] = TEXT("Please enter your password");
  52. //////////////////////////////////////////////////////////////////////////
  53. // Func prototypes
  54. //////////////////////////////////////////////////////////////////////////
  55. static int CBCEncipherData(const char* pszKey, const BYTE* pbData, int dwDataLength,
  56. BYTE* pbOut, int dwOutBufferLength);
  57. static int CBCDecipherData(const char* pszKey, const BYTE* pbData, int dwDataLength,
  58. BYTE* pbOut, int dwOutBufferLength);
  59. inline int CBCDecipherBufferSize(int dataSize);
  60. inline int CBCEncipherBufferSize(int dataSize);
  61. static BOOL
  62. StreamCipherEncryptData(
  63. LPTSTR pszKey, // password
  64. LPBYTE pbData, // Data to be encrypted
  65. DWORD dwDataLength, // Length of data in bytes
  66. LPBYTE *ppbEncryptedData, // Encrypted secret key will be stored here
  67. DWORD *pdwEncryptedBufferLen, // Length of this buffer
  68. PFN_CMSECUREALLOC pfnAlloc,
  69. PFN_CMSECUREFREE pfnFree
  70. );
  71. static BOOL
  72. StreamCipherDecryptData(
  73. LPTSTR pszKey, // password
  74. LPBYTE pbEncryptedData, // Encrypted data
  75. DWORD dwEncrytedDataLen, // Length of encrypted data
  76. LPBYTE *ppbData, // Decrypted Data will be stored here
  77. DWORD *pdwDataBufferLength,// Length of the above buffer in bytes
  78. PFN_CMSECUREALLOC pfnAlloc,
  79. PFN_CMSECUREFREE pfnFree,
  80. DWORD dwEncryptionType
  81. );
  82. static LPTSTR
  83. reverse(
  84. LPTSTR s
  85. );
  86. static void
  87. GenerateKeyString(
  88. IN OUT LPTSTR pszBuf,
  89. IN DWORD dwBufLen
  90. );
  91. static BOOL SetKeyString(IN OUT LPTSTR pszBuf, IN DWORD dwBufLen, IN DWORD dwEncryptionType,
  92. IN PFN_CMSECUREALLOC pfnAlloc,
  93. IN PFN_CMSECUREFREE pfnFree,
  94. IN LPSTR pszUserKey,
  95. OUT BOOL *pfMoreSecure);
  96. static BOOL GetKeyString(IN OUT LPTSTR pszBuf, IN DWORD * pdwBufLen, IN DWORD dwEncryptionType,
  97. IN PFN_CMSECUREALLOC pfnAlloc,
  98. IN PFN_CMSECUREFREE pfnFree,
  99. IN LPSTR pszUserKey,
  100. OUT BOOL *pfMoreSecure);
  101. static BOOL GetCurrentKey(PTCHAR szTempKeyStr, DWORD dwTempKeyStrMaxLen,
  102. IN PFN_CMSECUREALLOC pfnAlloc,
  103. IN PFN_CMSECUREFREE pfnFree);
  104. //////////////////////////////////////////////////////////////////////////
  105. // Implementations
  106. //////////////////////////////////////////////////////////////////////////
  107. //+---------------------------------------------------------------------------
  108. //
  109. // Function: InitCryptoApi
  110. //
  111. // Synopsis: Initialize the CryptoApi.
  112. //
  113. // Arguments:
  114. //
  115. // Returns: Pointer to CCryptFunctions, if success
  116. // NULL if failure
  117. //
  118. // History: fengsun Created 8/22/97
  119. //
  120. //----------------------------------------------------------------------------
  121. static CCryptFunctions* InitCryptoApi()
  122. {
  123. CCryptFunctions* pCryptFnc = new CCryptFunctions();
  124. if (pCryptFnc == NULL)
  125. return NULL;
  126. if (pCryptFnc->InitCrypt())
  127. {
  128. return pCryptFnc;
  129. }
  130. else
  131. {
  132. delete pCryptFnc;
  133. return NULL;
  134. }
  135. }
  136. //+---------------------------------------------------------------------------
  137. //
  138. // Function: InitSecure
  139. //
  140. // Synopsis: Initialize the security/encryption routines.
  141. //
  142. // Arguments: fFastEncryption : TRUE will use a faster algorithm vs a more secure one
  143. //
  144. // Returns: TRUE if success, always return TRUE
  145. // FALSE if failure
  146. //
  147. // History: henryt Created 5/20/97
  148. // fengsun modified
  149. //
  150. //----------------------------------------------------------------------------
  151. BOOL
  152. InitSecure(
  153. BOOL fFastEncryption
  154. )
  155. {
  156. MYDBGASSERT(g_nRefCount>=0);
  157. InterlockedIncrement(&g_nRefCount);
  158. //
  159. // If already initialized, increase the RefCount and return
  160. //
  161. if (g_nRefCount>1)
  162. {
  163. return TRUE;
  164. }
  165. MYDBGASSERT(g_pCryptFnc == NULL); // not initialized yet
  166. g_fFastEncryption = fFastEncryption;
  167. if (!fFastEncryption)
  168. {
  169. //
  170. // CryptoApi is slow on Win95
  171. // If more secure is desired, try the CryptoApi
  172. // Ignore return value of InitCrypt()
  173. //
  174. g_pCryptFnc = InitCryptoApi();
  175. }
  176. //
  177. // CryptoApi is not available for Win95 Gold
  178. // we'll use stream cipher.
  179. //
  180. return TRUE;
  181. }
  182. //+---------------------------------------------------------------------------
  183. //
  184. // Function: DeInitSecure
  185. //
  186. // Synopsis: Clean up function for the security/encryption routines.
  187. //
  188. // Arguments: NONE
  189. //
  190. // Returns: NONE
  191. //
  192. // History: henryt Created 5/20/97
  193. //
  194. //----------------------------------------------------------------------------
  195. void
  196. DeInitSecure(
  197. void
  198. )
  199. {
  200. MYDBGASSERT(g_nRefCount>=1);
  201. //
  202. // DeInit the CryptoApi if RefCount is down to 0
  203. //
  204. if (InterlockedDecrement(&g_nRefCount) <=0) // if ( (--g_nRefCount) <=0 )
  205. {
  206. if (g_pCryptFnc)
  207. {
  208. delete g_pCryptFnc;
  209. g_pCryptFnc = NULL;
  210. }
  211. }
  212. }
  213. //+---------------------------------------------------------------------------
  214. //
  215. // Function: StreamCipherEncryptData
  216. //
  217. // Synopsis: data encryption using stream cipher algorithm.
  218. //
  219. // Arguments: NONE
  220. //
  221. // Returns: NONE
  222. //
  223. // History: henryt Created 6/9/97
  224. // fengsun modified 8/21/97
  225. // to use Cipher Block Chaning Mode Algorithm
  226. //
  227. //----------------------------------------------------------------------------
  228. static BOOL
  229. StreamCipherEncryptData(
  230. LPTSTR pszKey, // password
  231. LPBYTE pbData, // Data to be encrypted
  232. DWORD dwDataLength, // Length of data in bytes
  233. LPBYTE *ppbEncryptedData, // Encrypted secret key will be stored here
  234. DWORD *pdwEncryptedBufferLen, // Length of this buffer
  235. PFN_CMSECUREALLOC pfnAlloc,
  236. PFN_CMSECUREFREE pfnFree
  237. )
  238. {
  239. LPBYTE pbTmpBuf = NULL;
  240. BOOL fOk = FALSE;
  241. BOOL fRet;
  242. if (!pszKey || !pbData || !dwDataLength || !ppbEncryptedData || !pdwEncryptedBufferLen)
  243. {
  244. CMASSERTMSG(FALSE, TEXT("StreamCipherEncryptData - invalid input params"));
  245. return FALSE;
  246. }
  247. //
  248. // Alloc a buffer to hold enciphered data
  249. //
  250. DWORD dwEncipherBufferLen = CBCEncipherBufferSize(dwDataLength);
  251. if (pfnAlloc)
  252. {
  253. pbTmpBuf = (LPBYTE)pfnAlloc(dwEncipherBufferLen);
  254. }
  255. else
  256. {
  257. pbTmpBuf = (LPBYTE)HeapAlloc(GetProcessHeap(),
  258. HEAP_ZERO_MEMORY,
  259. dwEncipherBufferLen);
  260. }
  261. if (!pbTmpBuf)
  262. {
  263. goto cleanup;
  264. }
  265. //
  266. // encipher the data
  267. //
  268. dwEncipherBufferLen = CBCEncipherData(pszKey, pbData, dwDataLength, pbTmpBuf, dwEncipherBufferLen);
  269. //
  270. // we now have the data encrypted. we need to uuencode it.
  271. //
  272. DWORD cbBuf;
  273. cbBuf = 2*dwEncipherBufferLen + EXTRA_UUDECODE_BUF_LEN; // enough for uuencode
  274. if (pfnAlloc)
  275. {
  276. *ppbEncryptedData = (LPBYTE)pfnAlloc(cbBuf);
  277. }
  278. else
  279. {
  280. *ppbEncryptedData = (LPBYTE)HeapAlloc(GetProcessHeap(),
  281. HEAP_ZERO_MEMORY,
  282. cbBuf);
  283. }
  284. if (!*ppbEncryptedData)
  285. {
  286. goto cleanup;
  287. }
  288. fRet = uuencode(pbTmpBuf, dwEncipherBufferLen, (CHAR*)*ppbEncryptedData, cbBuf);
  289. MYDBGASSERT(fRet);
  290. if (!fRet)
  291. {
  292. if (pfnFree)
  293. {
  294. pfnFree(*ppbEncryptedData);
  295. }
  296. else
  297. {
  298. HeapFree(GetProcessHeap(), 0, *ppbEncryptedData);
  299. }
  300. *ppbEncryptedData = NULL;
  301. goto cleanup;
  302. }
  303. //
  304. // set the encrypted buffer len
  305. //
  306. *pdwEncryptedBufferLen = lstrlen((LPSTR)*ppbEncryptedData);
  307. fOk = TRUE;
  308. cleanup:
  309. if (pbTmpBuf)
  310. {
  311. if (pfnFree)
  312. {
  313. pfnFree(pbTmpBuf);
  314. }
  315. else
  316. {
  317. HeapFree(GetProcessHeap(), 0, pbTmpBuf);
  318. }
  319. }
  320. return fOk;
  321. }
  322. //+---------------------------------------------------------------------------
  323. //
  324. // Function: StreamCipherDecryptData
  325. //
  326. // Synopsis: data decryption using stream cipher algorithm.
  327. //
  328. // Arguments: NONE
  329. //
  330. // Returns: NONE
  331. //
  332. // History: henryt Created 6/9/97
  333. // fengsun modified 8/21/97
  334. // to use Cipher Block Chaning Modem Algorithm
  335. //
  336. //----------------------------------------------------------------------------
  337. static BOOL
  338. StreamCipherDecryptData(
  339. LPTSTR pszKey, // password
  340. LPBYTE pbEncryptedData, // Encrypted data
  341. DWORD dwEncryptedDataLen, // Length of encrypted data
  342. LPBYTE *ppbData, // Decrypted Data will be stored here
  343. DWORD *pdwDataBufferLength,// Length of the above buffer in bytes
  344. PFN_CMSECUREALLOC pfnAlloc,
  345. PFN_CMSECUREFREE pfnFree,
  346. DWORD dwEncryptionType
  347. )
  348. {
  349. BOOL fRet = FALSE;
  350. DWORD dwUUDecodeBufLen;
  351. if (!pszKey || !pbEncryptedData || !dwEncryptedDataLen || !pdwDataBufferLength)
  352. {
  353. CMASSERTMSG(FALSE, TEXT("StreamCipherDecryptData - invalid input params"));
  354. return FALSE;
  355. }
  356. //
  357. // set uudecode output buf size
  358. //
  359. dwUUDecodeBufLen = dwEncryptedDataLen + EXTRA_UUDECODE_BUF_LEN;
  360. //
  361. // alloc memory for output buffer
  362. //
  363. if (pfnAlloc)
  364. {
  365. *ppbData = (LPBYTE)pfnAlloc(dwUUDecodeBufLen);
  366. }
  367. else
  368. {
  369. *ppbData = (LPBYTE)HeapAlloc(GetProcessHeap(),
  370. HEAP_ZERO_MEMORY,
  371. dwUUDecodeBufLen);
  372. }
  373. if (!*ppbData)
  374. {
  375. goto cleanup;
  376. }
  377. //
  378. // uudecode it first
  379. //
  380. fRet = uudecode((char*)pbEncryptedData, (CHAR*)*ppbData, &dwUUDecodeBufLen);
  381. MYDBGASSERT(fRet);
  382. if (!fRet)
  383. {
  384. if (pfnFree)
  385. {
  386. pfnFree(*ppbData);
  387. }
  388. else
  389. {
  390. HeapFree(GetProcessHeap(), 0, *ppbData);
  391. }
  392. *ppbData = NULL;
  393. goto cleanup;
  394. }
  395. switch(dwEncryptionType)
  396. {
  397. case CMSECURE_ET_STREAM_CIPHER:
  398. {
  399. //
  400. // Simple decipher algorithm used in old version
  401. //
  402. DWORD dwLen = lstrlen(pszKey);
  403. if (dwLen)
  404. {
  405. for (DWORD dwIdx = 0; dwIdx < dwUUDecodeBufLen; dwIdx++)
  406. {
  407. *(*ppbData + dwIdx) ^= pszKey[dwIdx % dwLen];
  408. }
  409. *pdwDataBufferLength = dwUUDecodeBufLen;
  410. fRet = TRUE;
  411. }
  412. }
  413. break;
  414. case CMSECURE_ET_CBC_CIPHER:
  415. //
  416. // Inplace decipher
  417. //
  418. *pdwDataBufferLength = CBCDecipherData(pszKey, *ppbData, dwUUDecodeBufLen,
  419. *ppbData, dwUUDecodeBufLen);
  420. fRet = TRUE;
  421. break;
  422. default:
  423. MYDBGASSERT(FALSE);
  424. }
  425. cleanup:
  426. return fRet;
  427. }
  428. //+---------------------------------------------------------------------------
  429. //
  430. // Function: EncryptData
  431. //
  432. // Synopsis: Encrypt the data buffer.
  433. //
  434. // Arguments: IN PBYTE pbData, // Data to be encrypted
  435. // IN DWORD dwDataLength, // Length of data in bytes
  436. // OUT PBYTE pbEncryptedData, // Encrypted secret key will be stored here
  437. // OUT DWORD *pdwEncrytedBufferLen // Length of this buffer
  438. // IN PCMSECUREALLOC pfnAlloc // memory allocator(if NULL, then the default is used.
  439. // // Win32 - HeapAlloc(GetProcessHeap(), ...)
  440. // IN PCMSECUREFREE pfnFree // memory deallocator(if NULL, then the default is used.
  441. // // Win32 - HeapFree(GetProcessHeap(), ...)
  442. // IN LPTSTR pszUserKey // Reg key where to store encrypted key
  443. //
  444. // Returns: TRUE if success
  445. // FALSE if failure
  446. //
  447. // History: henryt Created 5/20/97
  448. //
  449. //----------------------------------------------------------------------------
  450. BOOL
  451. EncryptData(
  452. IN LPBYTE pbData, // Data to be encrypted
  453. IN DWORD dwDataLength, // Length of data in bytes
  454. OUT LPBYTE *ppbEncryptedData, // Encrypted secret key will be stored here
  455. OUT LPDWORD pdwEncrytedBufferLen, // Length of this buffer
  456. OUT LPDWORD pEncryptionType, // type of the encryption used
  457. IN PFN_CMSECUREALLOC pfnAlloc,
  458. IN PFN_CMSECUREFREE pfnFree,
  459. IN LPSTR pszUserKey
  460. )
  461. {
  462. BOOL fOk = FALSE;
  463. TCHAR szKeyStr[MAX_KEY_STRING_LEN + 1]={0};
  464. BOOL fMoreSecure = FALSE;
  465. DWORD dwUseKey = *pEncryptionType;
  466. //
  467. // get a key string for session key generation
  468. //
  469. SetKeyString(szKeyStr, MAX_KEY_STRING_LEN, dwUseKey, pfnAlloc, pfnFree, pszUserKey, &fMoreSecure);
  470. *pEncryptionType = CMSECURE_ET_NOT_ENCRYPTED;
  471. //
  472. // If user want use CryptoApi and it is available
  473. //
  474. if (!g_fFastEncryption && g_pCryptFnc)
  475. {
  476. //
  477. // encrypt the data with the key string
  478. //
  479. if (fOk = g_pCryptFnc->EncryptDataWithKey(
  480. szKeyStr, // Key
  481. pbData, // Secret key
  482. dwDataLength, // Length of secret key
  483. ppbEncryptedData, // Encrypted data will be stored here
  484. pdwEncrytedBufferLen, // Length of this buffer
  485. pfnAlloc, // mem allocator
  486. pfnFree, // mem deallocator
  487. 0)) // not specifying keylength
  488. {
  489. *pEncryptionType = CMSECURE_ET_RC2;
  490. //
  491. // If the key is randomly generated then we want to make sure we
  492. // set the random key mask
  493. //
  494. if (fMoreSecure)
  495. {
  496. *pEncryptionType |= CMSECURE_ET_RANDOM_KEY_MASK;
  497. }
  498. }
  499. }
  500. if (!fOk)
  501. {
  502. if (fOk = StreamCipherEncryptData(
  503. szKeyStr, // Key
  504. pbData, // Secret key
  505. dwDataLength, // Length of secret key
  506. ppbEncryptedData, // Encrypted data will be stored here
  507. pdwEncrytedBufferLen, // Length of this buffer
  508. pfnAlloc, // mem allocator
  509. pfnFree)) // mem deallocator
  510. {
  511. *pEncryptionType = CMSECURE_ET_CBC_CIPHER;
  512. //
  513. // If the key is randomly generated then we want to make sure we
  514. // set the random key mask
  515. //
  516. if (fMoreSecure)
  517. {
  518. *pEncryptionType |= CMSECURE_ET_RANDOM_KEY_MASK;
  519. }
  520. }
  521. }
  522. ZeroMemory((LPVOID)szKeyStr, sizeof(szKeyStr));
  523. return fOk;
  524. }
  525. //+---------------------------------------------------------------------------
  526. //
  527. // Function: DecryptData
  528. //
  529. // Synopsis: Decrypt the data buffer.
  530. //
  531. // Arguments: IN PBYTE pbEncryptedData, // Encrypted data
  532. // IN DWORD dwEncrytedDataLen // Length of encrypted data
  533. // OUT PBYTE *ppbData, // Decrypted Data will be stored here
  534. // OUT DWORD *pdwDataBufferLength, // Length of the above buffer in bytes
  535. // IN PCMSECUREALLOC pfnAlloc // memory allocator(if NULL, then the default is used.
  536. // // Win32 - HeapAlloc(GetProcessHeap(), ...)
  537. // IN PCMSECUREFREE pfnFree // memory deallocator(if NULL, then the default is used.
  538. // // Win32 - HeapFree(GetProcessHeap(), ...)
  539. // IN LPTSTR pszUserKey // Reg key where to store encrypted key
  540. //
  541. // Returns: TRUE if success
  542. // FALSE if failure
  543. //
  544. // History: henryt Created 5/20/97
  545. //
  546. //----------------------------------------------------------------------------
  547. BOOL
  548. DecryptData(
  549. IN LPBYTE pbEncryptedData, // Encrypted data
  550. IN DWORD dwEncrytedDataLen, // Length of encrypted data
  551. OUT LPBYTE *ppbData, // Decrypted Data will be stored here
  552. OUT LPDWORD pdwDataBufferLength, // Length of the above buffer in bytes
  553. IN DWORD dwEncryptionType, // encryption type for decryption
  554. IN PFN_CMSECUREALLOC pfnAlloc,
  555. IN PFN_CMSECUREFREE pfnFree,
  556. IN LPSTR pszUserKey
  557. )
  558. {
  559. TCHAR szKeyStr[MAX_KEY_STRING_LEN + 1]={0}; // Plus NULL
  560. DWORD dwRet = 0xf; // some non-zero value
  561. BOOL fMoreSecure = FALSE;
  562. //
  563. // To speed things up we only want to generate a key
  564. // in case the data is encrypted
  565. //
  566. if (CMSECURE_ET_NOT_ENCRYPTED != dwEncryptionType)
  567. {
  568. //
  569. // get a key string for session key generation
  570. //
  571. //
  572. // Here we don't care if the pszUserKey is NULL, the called function will determine
  573. // this and set fMoreSecure appropriately. Right now we don't check for the random key mask
  574. // in dwEncryptionType, but if it isn't set the blob (encrypted key) will not be in the registry
  575. // thus it will try to default to using the hardcoded key. This should probably be made more explicit
  576. // in the code at a later time.
  577. //
  578. DWORD dwMaxSize = MAX_KEY_STRING_LEN;
  579. GetKeyString(szKeyStr, &dwMaxSize, dwEncryptionType, pfnAlloc, pfnFree, pszUserKey, &fMoreSecure);
  580. //
  581. // If the random key bit mask is set, we better have have fMoreSecure flag set to true.
  582. // This has to be always true in order for decryption to work
  583. //
  584. CMASSERTMSG(((dwEncryptionType & CMSECURE_ET_RANDOM_KEY_MASK) && fMoreSecure), TEXT("DecryptData - Trying to use mismatched keys"));
  585. }
  586. //
  587. // Clear the random key mask
  588. //
  589. dwEncryptionType &= ~CMSECURE_ET_RANDOM_KEY_MASK;
  590. dwEncryptionType &= ~CMSECURE_ET_USE_SECOND_RND_KEY;
  591. switch (dwEncryptionType)
  592. {
  593. case CMSECURE_ET_RC2:
  594. if (g_fFastEncryption && !g_pCryptFnc)
  595. {
  596. //
  597. // if we want fast encryption initially,
  598. // We have to initialize the CryptoApi now
  599. //
  600. g_pCryptFnc = InitCryptoApi();
  601. }
  602. if (g_pCryptFnc)
  603. {
  604. dwRet = g_pCryptFnc->DecryptDataWithKey(
  605. szKeyStr, // Key
  606. pbEncryptedData, // Encrypted data
  607. dwEncrytedDataLen, // Length of encrypted data
  608. ppbData, // decrypted data
  609. pdwDataBufferLength, // Length of decrypted data
  610. pfnAlloc, // mem allocator
  611. pfnFree, // mem deallocator
  612. 0); // not specifying keylength
  613. }
  614. break;
  615. case CMSECURE_ET_STREAM_CIPHER:
  616. case CMSECURE_ET_CBC_CIPHER:
  617. //
  618. // Use our own encryption algorithm
  619. //
  620. dwRet = (DWORD)!StreamCipherDecryptData(
  621. szKeyStr, // Key
  622. pbEncryptedData, // Encrypted data
  623. dwEncrytedDataLen, // Length of encrypted data
  624. ppbData, // decrypted data
  625. pdwDataBufferLength, // Length of decrypted data
  626. pfnAlloc, // mem allocator
  627. pfnFree, // mem deallocator
  628. dwEncryptionType // Encryption type used
  629. );
  630. break;
  631. case CMSECURE_ET_NOT_ENCRYPTED:
  632. //
  633. // Just copy the exact contents into the OUT buffer
  634. //
  635. if (pbEncryptedData && dwEncrytedDataLen &&
  636. ppbData && pdwDataBufferLength)
  637. {
  638. if (pfnAlloc)
  639. {
  640. *ppbData = (LPBYTE)pfnAlloc(dwEncrytedDataLen);
  641. }
  642. else
  643. {
  644. *ppbData = (LPBYTE)HeapAlloc(GetProcessHeap(),
  645. HEAP_ZERO_MEMORY,
  646. dwEncrytedDataLen);
  647. }
  648. if (*ppbData)
  649. {
  650. CopyMemory(*ppbData, pbEncryptedData, dwEncrytedDataLen);
  651. *pdwDataBufferLength = dwEncrytedDataLen;
  652. dwRet = 0; // the return statement correctly returns TRUE
  653. }
  654. }
  655. break;
  656. default:
  657. MYDBGASSERT(FALSE);
  658. break;
  659. }
  660. ZeroMemory((LPVOID)szKeyStr, sizeof(szKeyStr));
  661. return (!dwRet);
  662. }
  663. //+----------------------------------------------------------------------------
  664. //
  665. // Func: EncryptString
  666. //
  667. // Desc: encrypt a given (Ansi) string using RC2 encryption
  668. //
  669. // Args: pszToEncrypt -- Ansi string to be encrypted
  670. // pszUserKey -- Key to use for Encryption
  671. // ppbEncryptedData -- Encrypted secret key will be stored here(memory will be allocated)
  672. // pdwEncrytedBufferLen -- Length of this buffer
  673. //
  674. // Return: BOOL (FALSE if a fatal error occurred, else TRUE)
  675. //
  676. // Notes: The encryption type must be at least RC2, and exactly 40-bit
  677. //
  678. //-----------------------------------------------------------------------------
  679. BOOL
  680. EncryptString(
  681. IN LPSTR pszToEncrypt, // Ansi string to be encrypted
  682. IN LPSTR pszUserKey, // Key to use for Encryption
  683. OUT LPBYTE * ppbEncryptedData, // Encrypted secret key will be stored here(memory will be allocated)
  684. OUT LPDWORD pdwEncrytedBufferLen, // Length of this buffer
  685. IN PFN_CMSECUREALLOC pfnAlloc,
  686. IN PFN_CMSECUREFREE pfnFree
  687. )
  688. {
  689. BOOL fOk = FALSE;
  690. CMASSERTMSG(pszToEncrypt, TEXT("EncryptData - first arg must be a valid string"));
  691. CMASSERTMSG(pszUserKey, TEXT("EncryptData - second arg must be a valid user key"));
  692. DWORD dwDataLength = lstrlen(pszToEncrypt) + 1; // get the NULL in as well.
  693. if (!g_fFastEncryption && g_pCryptFnc)
  694. {
  695. if (fOk = g_pCryptFnc->EncryptDataWithKey(
  696. pszUserKey, // Key
  697. (LPBYTE)pszToEncrypt, // Secret key
  698. dwDataLength, // Length of secret key
  699. ppbEncryptedData, // Encrypted data will be stored here
  700. pdwEncrytedBufferLen, // Length of this buffer
  701. pfnAlloc,
  702. pfnFree,
  703. c_dwEncryptKeyLength))
  704. {
  705. CMTRACE(TEXT("EncryptString - succeeded."));
  706. }
  707. }
  708. return fOk;
  709. }
  710. //+----------------------------------------------------------------------------
  711. //
  712. // Func: DecryptString
  713. //
  714. // Desc: encrypt a given (Ansi) string using RC2 encryption
  715. //
  716. // Args: pszToEncrypt -- Ansi string to be encrypted
  717. // pszUserKey -- Key to use for Encryption
  718. // ppbEncryptedData -- Encrypted secret key will be stored here(memory will be allocated)
  719. // pdwEncrytedBufferLen -- Length of this buffer
  720. //
  721. // Return: BOOL (FALSE if a fatal error occurred, else TRUE)
  722. //
  723. // Notes: The encryption type must be at least RC2, and exactly 40-bit
  724. //
  725. //-----------------------------------------------------------------------------
  726. BOOL
  727. DecryptString(
  728. IN LPBYTE pbEncryptedData, // Encrypted data
  729. IN DWORD dwEncrytedDataLen, // Length of encrypted data
  730. IN LPSTR pszUserKey, // Registry key to store encrypted key for passwords
  731. OUT LPBYTE * ppbData, // Decrypted Data will be stored here
  732. OUT LPDWORD pdwDataBufferLength, // Length of the above buffer in bytes
  733. IN PFN_CMSECUREALLOC pfnAlloc,
  734. IN PFN_CMSECUREFREE pfnFree
  735. )
  736. {
  737. DWORD dwRet = 0xf; // some non-zero value
  738. if (!g_fFastEncryption && g_pCryptFnc)
  739. {
  740. dwRet = g_pCryptFnc->DecryptDataWithKey(
  741. pszUserKey, // Key
  742. pbEncryptedData, // Encrypted data
  743. dwEncrytedDataLen, // Length of encrypted data
  744. ppbData, // decrypted data
  745. pdwDataBufferLength, // Length of decrypted data
  746. pfnAlloc,
  747. pfnFree,
  748. c_dwEncryptKeyLength); // 40-bit
  749. }
  750. return (!dwRet);
  751. }
  752. //+---------------------------------------------------------------------------
  753. //
  754. // Function: CBCEncipherBufferSize
  755. //
  756. // Synopsis: Get the buffer size needed for Enciphering
  757. //
  758. // Arguments: dataSize sizeof data to be enciphered
  759. //
  760. // Returns: Encipher buffer size needed
  761. //
  762. // History: fengsun Created 8/21/97
  763. //
  764. //----------------------------------------------------------------------------
  765. inline int CBCEncipherBufferSize(int dataSize)
  766. {
  767. MYDBGASSERT(dataSize > 0);
  768. //
  769. // We need one byte to hold the initializing variable
  770. //
  771. return dataSize + 1;
  772. }
  773. //+---------------------------------------------------------------------------
  774. //
  775. // Function: CBCDecipherBufferSize
  776. //
  777. // Synopsis: Get the buffer size needed for Deciphering
  778. //
  779. // Arguments: dataSize sizeof data to be Deciphered
  780. //
  781. // Returns: Decipher buffer size needed
  782. //
  783. // History: fengsun Created 8/21/97
  784. //
  785. //----------------------------------------------------------------------------
  786. inline int CBCDecipherBufferSize(int dataSize)
  787. {
  788. MYDBGASSERT(dataSize > 1);
  789. return dataSize - 1;
  790. }
  791. //+---------------------------------------------------------------------------
  792. //
  793. // Function: EncryptByte
  794. //
  795. // Synopsis: Encrypt a single byte
  796. //
  797. // Arguments: pszKey key string
  798. // byteSource byte to be encrypted
  799. // param aditional parameter for encryption
  800. //
  801. // Returns: byte encrypted
  802. //
  803. // History: fengsun Created 8/21/97
  804. //
  805. //----------------------------------------------------------------------------
  806. inline BYTE EncryptByte(LPCTSTR pszKey, BYTE byteSource, BYTE Param)
  807. {
  808. if (NULL == pszKey)
  809. {
  810. return NULL;
  811. }
  812. DWORD dwLen = lstrlen(pszKey);
  813. if (0 == dwLen)
  814. {
  815. return NULL;
  816. }
  817. return ((byteSource ^ (BYTE)pszKey[Param % dwLen]) + Param);
  818. }
  819. //+---------------------------------------------------------------------------
  820. //
  821. // Function: DecryptByte
  822. //
  823. // Synopsis: Decrypt a single byte
  824. //
  825. // Arguments: pszKey key string
  826. // byteSource byte to be Decrypted
  827. // param aditional parameter for encryption
  828. //
  829. // Returns: byte decrypted
  830. //
  831. // History: fengsun Created 8/21/97
  832. //
  833. //----------------------------------------------------------------------------
  834. inline BYTE DecryptByte(LPCTSTR pszKey, BYTE byteSource, BYTE Param)
  835. {
  836. if (NULL == pszKey)
  837. {
  838. return NULL;
  839. }
  840. DWORD dwLen = lstrlen(pszKey);
  841. if (0 == dwLen)
  842. {
  843. return NULL;
  844. }
  845. return ((byteSource - Param) ^ (BYTE)pszKey[Param % dwLen]);
  846. }
  847. //+---------------------------------------------------------------------------
  848. //
  849. // Function: CBCEncipherData
  850. //
  851. // Synopsis: Encipher a block of data
  852. //
  853. // Arguments: pszKey key string
  854. // pbData Data to be enciphered
  855. // dwDataLength size of pbData
  856. // pbOut Buffer for encipher result
  857. // dwOutBufferLength size of pbOut, must be >= CBCEncipherBufferSize(dwDataLength)
  858. //
  859. // Returns: size of encipher byte in pbOut, 0 means failed
  860. //
  861. // History: fengsun Created 8/21/97
  862. //
  863. //----------------------------------------------------------------------------
  864. static int CBCEncipherData(const char* pszKey, const BYTE* pbData, int dwDataLength,
  865. BYTE* pbOut, int dwOutBufferLength)
  866. {
  867. MYDBGASSERT(pszKey != NULL);
  868. MYDBGASSERT(pbData != NULL);
  869. MYDBGASSERT(pbOut != NULL);
  870. MYDBGASSERT(dwDataLength > 0);
  871. MYDBGASSERT(pbData != pbOut);
  872. if (dwDataLength <= 0)
  873. return 0;
  874. if (dwOutBufferLength < CBCEncipherBufferSize(dwDataLength))
  875. return 0;
  876. dwOutBufferLength = CBCEncipherBufferSize(dwDataLength);
  877. //
  878. // Add a random number as the initializing variable (first byte)
  879. //
  880. pbOut[0] = (BYTE)((GetTickCount() >> 4 ) % 256);
  881. //
  882. // encipher it
  883. //
  884. // EnCipher: C[i] = E[k](p[i] XOR C[i-1])
  885. //
  886. BYTE lastPlainText = pbOut[0]; //first initilizing byte
  887. pbOut[0] = EncryptByte(pszKey, pbOut[0], 0);
  888. for (int dwIdx=1; dwIdx<dwOutBufferLength; dwIdx++)
  889. {
  890. pbOut[dwIdx] = EncryptByte(pszKey, pbData[dwIdx-1]^pbOut[dwIdx-1], lastPlainText);
  891. lastPlainText = pbData[dwIdx-1];
  892. }
  893. return dwOutBufferLength;
  894. }
  895. //+---------------------------------------------------------------------------
  896. //
  897. // Function: CBCDecipherData
  898. //
  899. // Synopsis: Decipher a block of data, inplace deciper is supported
  900. //
  901. // Arguments: pszKey key string
  902. // pbData Data to be Deciphered
  903. // dwDataLength size of pbData
  904. // pbOut Buffer for decipher result
  905. // dwOutBufferLength size of pbOut, must be >= CBCDecipherBufferSize(dwDataLength)
  906. //
  907. // Returns: size of decipher byte in pbOut, 0 means failed
  908. //
  909. // History: fengsun Created 8/21/97
  910. //
  911. //----------------------------------------------------------------------------
  912. static int CBCDecipherData(const char* pszKey, const BYTE* pbData, int dwDataLength,
  913. BYTE* pbOut, int dwOutBufferLength)
  914. {
  915. MYDBGASSERT(pszKey != NULL);
  916. MYDBGASSERT(pbData != NULL);
  917. MYDBGASSERT(pbOut != NULL);
  918. MYDBGASSERT(dwDataLength > 1);
  919. if (dwDataLength <= 1)
  920. return 0;
  921. if (dwOutBufferLength < CBCDecipherBufferSize(dwDataLength))
  922. return 0;
  923. dwOutBufferLength = CBCDecipherBufferSize(dwDataLength);
  924. //
  925. // decipher data
  926. //
  927. // DeCipher: P[i] = C[i-1] XOR D[k](C[i]),
  928. //
  929. BYTE lastPlainText = DecryptByte(pszKey, pbData[0], 0); //first initilizing byte
  930. for (int dwIdx=0; dwIdx<dwOutBufferLength; dwIdx++)
  931. {
  932. pbOut[dwIdx] = pbData[dwIdx] ^ DecryptByte(pszKey, pbData[dwIdx+1], lastPlainText);
  933. lastPlainText = pbOut[dwIdx];
  934. }
  935. return dwOutBufferLength;
  936. }
  937. ////////////////////////////////////////////////////////////////////////////////
  938. // Helper functions
  939. ////////////////////////////////////////////////////////////////////////////////
  940. //+---------------------------------------------------------------------------
  941. //
  942. // Function: reverse
  943. //
  944. // Synopsis: reverse the given strings.
  945. //
  946. // Arguments: s the string.
  947. //
  948. // Returns: the reversed string
  949. //
  950. // History: henryt Created 5/20/97
  951. //
  952. //----------------------------------------------------------------------------
  953. static LPTSTR
  954. reverse(
  955. LPTSTR s
  956. )
  957. {
  958. int i = 0;
  959. int j = lstrlen(s) - 1;
  960. TCHAR ch;
  961. while (i < j)
  962. {
  963. ch = s[i];
  964. s[i++] = s[j];
  965. s[j--] = ch;
  966. }
  967. return s;
  968. }
  969. //+---------------------------------------------------------------------------
  970. //
  971. // Function: GenerateKeyString
  972. //
  973. // Synopsis: reverse the key str and use it as a password to generate a session key.
  974. //
  975. // Arguments: OUT LPTSTR pszBuf, The buffer
  976. // IN DWORD dwBufLen size of the buffer in # of chars.
  977. //
  978. //
  979. //
  980. // Returns: TRUE if success
  981. // FALSE if failure
  982. //
  983. // History: henryt Created 5/20/97
  984. //
  985. //----------------------------------------------------------------------------
  986. static void
  987. GenerateKeyString(
  988. IN OUT LPTSTR pszBuf,
  989. IN DWORD dwBufLen
  990. )
  991. {
  992. lstrcpyn(pszBuf, gc_szKeyStr, dwBufLen);
  993. pszBuf[dwBufLen - 1] = 0;
  994. reverse(pszBuf);
  995. }
  996. //+---------------------------------------------------------------------------
  997. //
  998. // Function: SetKeyString
  999. //
  1000. // Synopsis: Generates a random key that will be used to create the
  1001. // session key that is used to encrypt the password. Once the key
  1002. // created it is encrypted and stored in the registry so that we
  1003. // can use the key to decrypt the password again. The key used to
  1004. // encrypt and decrypt is generated in GetCurrentKey(). If
  1005. // anything fails we default to using a hardcoded key by calling
  1006. // GenerateKeyString.
  1007. //
  1008. // Arguments: pszBuf The buffer
  1009. // dwBufLen size of the buffer in # of chars.
  1010. // dwEncryptionType - selects which reg key to use
  1011. // pfnAlloc memory allocator(if NULL, then the default is used.
  1012. // Win32 - HeapAlloc(GetProcessHeap(), ...)
  1013. // pfnFree memory deallocator(if NULL, then the default is used.
  1014. // Win32 - HeapFree(GetProcessHeap(), ...)
  1015. // pszUserKey reg key used to store the encrypted key, if not
  1016. // provided (NULL), it will default to GenerateKeyString
  1017. // pfMoreSecure TRUE if we are using the randomly generated key
  1018. // FALSE if using the hardcoded key
  1019. //
  1020. // Returns: TRUE if success
  1021. // FALSE if failure
  1022. //
  1023. // History: 03/14/2001 tomkel Created
  1024. //
  1025. //----------------------------------------------------------------------------
  1026. static BOOL SetKeyString(IN OUT LPTSTR pszBuf,
  1027. IN DWORD dwBufLen,
  1028. IN DWORD dwEncryptionType,
  1029. IN PFN_CMSECUREALLOC pfnAlloc,
  1030. IN PFN_CMSECUREFREE pfnFree,
  1031. IN LPSTR pszUserKey,
  1032. OUT BOOL *pfMoreSecure)
  1033. {
  1034. BOOL fReturn = FALSE;
  1035. BOOL fFuncRet = FALSE;
  1036. BOOL fOk = FALSE;
  1037. TCHAR szTempKeyStr[MAX_KEY_STRING_LEN]={0};
  1038. DWORD cbEncryptedData = 0;
  1039. PBYTE pbEncryptedData = NULL;
  1040. //
  1041. // Don't check for pszUserKey here
  1042. //
  1043. if (NULL == pszBuf || NULL == pfMoreSecure)
  1044. {
  1045. return fReturn;
  1046. }
  1047. *pfMoreSecure = FALSE;
  1048. //
  1049. // Check to see if we should try to generate a random key and then store it
  1050. // into the reg key supplied by the caller. If not, then use the hardcoded key.
  1051. //
  1052. if (pszUserKey)
  1053. {
  1054. //
  1055. // Try to generate random key otherwise use the hardcoded string. GenerateRandomKey
  1056. // takes a PBYTE pointer and a count in bytes, thus we have to convert the character count
  1057. // to bytes by multiplying it by sizeof(TCHAR)
  1058. //
  1059. if (g_pCryptFnc->GenerateRandomKey((PBYTE)pszBuf, dwBufLen*sizeof(TCHAR)))
  1060. {
  1061. // Now that we have the randomkey, we need to store it in the registry so
  1062. // we can use it when decrypting. In order to store it, we have
  1063. // to encrypt it first.
  1064. //
  1065. // Generate a machine specific key that's used to encrypt the random number
  1066. // used for the session key
  1067. //
  1068. fFuncRet = GetCurrentKey(szTempKeyStr, MAX_KEY_STRING_LEN, pfnAlloc, pfnFree);
  1069. if (fFuncRet)
  1070. {
  1071. //
  1072. // If user want use CryptoApi and it is available
  1073. //
  1074. if (!g_pCryptFnc)
  1075. {
  1076. g_pCryptFnc = InitCryptoApi();
  1077. }
  1078. if (g_pCryptFnc)
  1079. {
  1080. //
  1081. // encrypt the data with the key string
  1082. //
  1083. fOk = g_pCryptFnc->EncryptDataWithKey(
  1084. szTempKeyStr, // Key
  1085. (PBYTE)pszBuf, // Secret key to encrypt
  1086. dwBufLen, // Length of secret key
  1087. &pbEncryptedData, // Encrypted data will be stored here
  1088. &cbEncryptedData, // Length of this buffer
  1089. pfnAlloc, // mem allocator
  1090. pfnFree, // mem deallocator
  1091. 0); // not specifying keylength
  1092. }
  1093. if (fOk)
  1094. {
  1095. //
  1096. // Store the encrypted key in the registry so we can use it later
  1097. // for decryption
  1098. //
  1099. HKEY hKeyCm;
  1100. //
  1101. // Try to open the key for writing
  1102. //
  1103. LONG lRes = RegOpenKeyEx(HKEY_CURRENT_USER,
  1104. pszUserKey,
  1105. 0,
  1106. KEY_SET_VALUE ,
  1107. &hKeyCm);
  1108. //
  1109. // If we can't open it the key may not be there, try to create it.
  1110. //
  1111. if (ERROR_SUCCESS != lRes)
  1112. {
  1113. DWORD dwDisposition;
  1114. lRes = RegCreateKeyEx(HKEY_CURRENT_USER,
  1115. pszUserKey,
  1116. 0,
  1117. TEXT(""),
  1118. REG_OPTION_NON_VOLATILE,
  1119. KEY_SET_VALUE,
  1120. NULL,
  1121. &hKeyCm,
  1122. &dwDisposition);
  1123. }
  1124. //
  1125. // On success, update the value, then close
  1126. //
  1127. if (ERROR_SUCCESS == lRes)
  1128. {
  1129. if (dwEncryptionType & CMSECURE_ET_USE_SECOND_RND_KEY)
  1130. {
  1131. lRes = RegSetValueEx(hKeyCm, c_pszCmRegKeyEncryptedInternetPasswordKey, NULL, REG_BINARY,
  1132. pbEncryptedData, cbEncryptedData);
  1133. }
  1134. else
  1135. {
  1136. lRes = RegSetValueEx(hKeyCm, c_pszCmRegKeyEncryptedPasswordKey, NULL, REG_BINARY,
  1137. pbEncryptedData, cbEncryptedData);
  1138. }
  1139. RegCloseKey(hKeyCm);
  1140. if (ERROR_SUCCESS == lRes)
  1141. {
  1142. fReturn = TRUE;
  1143. *pfMoreSecure = TRUE;
  1144. }
  1145. }
  1146. }
  1147. }
  1148. }
  1149. }
  1150. //
  1151. // Check if we need to default to the old key
  1152. //
  1153. if (FALSE == fReturn)
  1154. {
  1155. GenerateKeyString(pszBuf, dwBufLen);
  1156. fReturn = TRUE;
  1157. }
  1158. if (pfnFree)
  1159. {
  1160. pfnFree(pbEncryptedData);
  1161. }
  1162. else
  1163. {
  1164. HeapFree(GetProcessHeap(), 0, pbEncryptedData);
  1165. }
  1166. ZeroMemory((LPVOID)szTempKeyStr, sizeof(szTempKeyStr));
  1167. return fReturn;
  1168. }
  1169. //+---------------------------------------------------------------------------
  1170. //
  1171. // Function: GetKeyString
  1172. //
  1173. // Synopsis: Gets the key that is used to create a session key for
  1174. // decrypting the password. Reads the encrypted key from the
  1175. // registry. Get the key used for decrypting by calling GetCurrentKey.
  1176. // Decrypts the data and returns the key. If anything fails we
  1177. // default to using a hardcoded key by calling GenerateKeyString.
  1178. //
  1179. // Arguments: pszBuf The buffer
  1180. // pdwBufLen pointer to the size of the buffer in # of chars.
  1181. // dwEncryptionType - selects which reg key to use
  1182. // pfnAlloc memory allocator(if NULL, then the default is used.
  1183. // Win32 - HeapAlloc(GetProcessHeap(), ...)
  1184. // pfnFree memory deallocator(if NULL, then the default is used.
  1185. // Win32 - HeapFree(GetProcessHeap(), ...)
  1186. // pszUserKey reg key used to store the encrypted key, if not
  1187. // provided (NULL), it will default to GenerateKeyString
  1188. // pfMoreSecure TRUE if we are using the randomly generated key
  1189. // FALSE if using the hardcoded key
  1190. //
  1191. // Returns: TRUE if success
  1192. // FALSE if failure
  1193. //
  1194. // History: 03/14/2001 tomkel Created
  1195. //
  1196. //----------------------------------------------------------------------------
  1197. static BOOL GetKeyString(IN OUT LPTSTR pszBuf, IN DWORD *pdwBufLen, IN DWORD dwEncryptionType,
  1198. IN PFN_CMSECUREALLOC pfnAlloc,
  1199. IN PFN_CMSECUREFREE pfnFree,
  1200. IN LPSTR pszUserKey,
  1201. OUT BOOL *pfMoreSecure)
  1202. {
  1203. BOOL fReturn = FALSE;
  1204. BOOL fFuncRet = FALSE;
  1205. HKEY hKeyCm;
  1206. TCHAR szTempKeyStr[MAX_KEY_STRING_LEN]={0};
  1207. DWORD dwRet = 0;
  1208. DWORD cbEncryptedData = 0;
  1209. PBYTE pbEncryptedData = NULL;
  1210. PBYTE pbData = NULL;
  1211. DWORD dwDataBufferLength = 0;
  1212. //
  1213. // Don't Check for pszUserKey here
  1214. //
  1215. if (NULL == pszBuf || NULL == pdwBufLen || NULL == pfMoreSecure)
  1216. {
  1217. return fReturn;
  1218. }
  1219. *pfMoreSecure = FALSE;
  1220. //
  1221. // If we have the user key then we are using the randomly generated key.
  1222. // Try to get it from the reg.
  1223. //
  1224. if (pszUserKey)
  1225. {
  1226. //
  1227. // Try to open the key for writing
  1228. //
  1229. LONG lRes = RegOpenKeyEx(HKEY_CURRENT_USER,
  1230. pszUserKey,
  1231. 0,
  1232. KEY_READ ,
  1233. &hKeyCm);
  1234. //
  1235. // On success, read the value, then close
  1236. //
  1237. if (ERROR_SUCCESS == lRes)
  1238. {
  1239. DWORD dwType = REG_BINARY;
  1240. //
  1241. // Get the size first
  1242. //
  1243. if (dwEncryptionType & CMSECURE_ET_USE_SECOND_RND_KEY)
  1244. {
  1245. lRes = RegQueryValueEx(hKeyCm, c_pszCmRegKeyEncryptedInternetPasswordKey, NULL, &dwType,
  1246. NULL, &cbEncryptedData);
  1247. }
  1248. else
  1249. {
  1250. lRes = RegQueryValueEx(hKeyCm, c_pszCmRegKeyEncryptedPasswordKey, NULL, &dwType,
  1251. NULL, &cbEncryptedData);
  1252. }
  1253. //
  1254. // Alloc the appropriate sized buffer. Need to add a space for null,
  1255. // otherwise decrypt doesn't work.
  1256. //
  1257. if (pfnAlloc)
  1258. {
  1259. pbEncryptedData = (PBYTE)pfnAlloc(cbEncryptedData + sizeof(TCHAR));
  1260. }
  1261. else
  1262. {
  1263. pbEncryptedData = (PBYTE)HeapAlloc(GetProcessHeap(),
  1264. HEAP_ZERO_MEMORY,
  1265. cbEncryptedData + sizeof(TCHAR));
  1266. }
  1267. if (pbEncryptedData)
  1268. {
  1269. if (dwEncryptionType & CMSECURE_ET_USE_SECOND_RND_KEY)
  1270. {
  1271. lRes = RegQueryValueEx(hKeyCm, c_pszCmRegKeyEncryptedInternetPasswordKey, NULL, &dwType,
  1272. pbEncryptedData, &cbEncryptedData);
  1273. }
  1274. else
  1275. {
  1276. lRes = RegQueryValueEx(hKeyCm, c_pszCmRegKeyEncryptedPasswordKey, NULL, &dwType,
  1277. pbEncryptedData, &cbEncryptedData);
  1278. }
  1279. }
  1280. RegCloseKey(hKeyCm);
  1281. //
  1282. // If we find the value decrypt it, otherwise we fall through and use the default key
  1283. //
  1284. if (ERROR_SUCCESS == lRes && pbEncryptedData)
  1285. {
  1286. //
  1287. // Decrypt it using the machine specific key
  1288. //
  1289. fFuncRet = GetCurrentKey(szTempKeyStr, MAX_KEY_STRING_LEN, pfnAlloc, pfnFree);
  1290. if (fFuncRet)
  1291. {
  1292. if (!g_pCryptFnc)
  1293. {
  1294. g_pCryptFnc = InitCryptoApi();
  1295. }
  1296. if (g_pCryptFnc)
  1297. {
  1298. dwRet = g_pCryptFnc->DecryptDataWithKey(
  1299. szTempKeyStr, // Key
  1300. pbEncryptedData, // Encrypted data
  1301. cbEncryptedData, // Length of encrypted data
  1302. &pbData, // decrypted data
  1303. &dwDataBufferLength, // Length of decrypted data
  1304. pfnAlloc, // mem allocator
  1305. pfnFree, // mem deallocator
  1306. 0); // not specifying keylength
  1307. if (ERROR_SUCCESS == dwRet)
  1308. {
  1309. fReturn = TRUE;
  1310. *pfMoreSecure = TRUE; // Using the random key
  1311. }
  1312. }
  1313. }
  1314. }
  1315. }
  1316. }
  1317. if (fReturn)
  1318. {
  1319. DWORD dwLen = *pdwBufLen;
  1320. if (dwDataBufferLength < *pdwBufLen)
  1321. {
  1322. dwLen = dwDataBufferLength;
  1323. }
  1324. //
  1325. // Copy into out param
  1326. //
  1327. CopyMemory((LPVOID)pszBuf, pbData, dwLen);
  1328. }
  1329. else
  1330. {
  1331. GenerateKeyString(pszBuf, *pdwBufLen);
  1332. fReturn = TRUE;
  1333. }
  1334. if (pfnFree)
  1335. {
  1336. pfnFree(pbEncryptedData);
  1337. pfnFree(pbData);
  1338. }
  1339. else
  1340. {
  1341. HeapFree(GetProcessHeap(), 0, pbEncryptedData);
  1342. HeapFree(GetProcessHeap(), 0, pbData);
  1343. }
  1344. ZeroMemory((LPVOID)szTempKeyStr, sizeof(szTempKeyStr));
  1345. return fReturn;
  1346. }
  1347. //+---------------------------------------------------------------------------
  1348. //
  1349. // Function: GetCurrentKey
  1350. //
  1351. // Synopsis: Creates a machine dependent key by using the Hard Drive's
  1352. // serial number. This serial number is then used to fil lup the
  1353. // output buffer. If the hard drive is replaced then this of course
  1354. // will not generate the same serial number.
  1355. //
  1356. // Arguments: szTempKeyStr The buffer
  1357. // dwTempKeyStrMaxLen max length of the buffer in # of chars.
  1358. // pfnAlloc memory allocator(if NULL, then the default is used.
  1359. // Win32 - HeapAlloc(GetProcessHeap(), ...)
  1360. // pfnFree memory deallocator(if NULL, then the default is used.
  1361. // Win32 - HeapFree(GetProcessHeap(), ...)
  1362. //
  1363. // Returns: TRUE if success
  1364. // FALSE if failure
  1365. //
  1366. // History: 03/14/2001 tomkel Created
  1367. //
  1368. //----------------------------------------------------------------------------
  1369. static BOOL GetCurrentKey(PTCHAR szTempKeyStr, DWORD dwTempKeyStrMaxLen,
  1370. IN PFN_CMSECUREALLOC pfnAlloc,
  1371. IN PFN_CMSECUREFREE pfnFree)
  1372. {
  1373. BOOL fFuncRet = FALSE;
  1374. DWORD dwVolumeSerialNumber = 0;
  1375. DWORD dwMaxComponentLen = 0;
  1376. DWORD dwFileSysFlags = 0;
  1377. LPTSTR pszSerialNum = NULL;
  1378. if (NULL == szTempKeyStr)
  1379. {
  1380. return fFuncRet;
  1381. }
  1382. //
  1383. // Lets generate the key from the HD serial number. This means that encrypted
  1384. // passwords and keys will only be valid on this machine. If the user replaces
  1385. // the drive, then the decryption will fail.
  1386. //
  1387. fFuncRet = GetVolumeInformation(NULL, NULL, 0, &dwVolumeSerialNumber,
  1388. &dwMaxComponentLen, &dwFileSysFlags, NULL, 0);
  1389. if (fFuncRet)
  1390. {
  1391. DWORD dwLen = 0;
  1392. //
  1393. // Make sure we have a buffer large enough to hold the value.
  1394. // Allocate a string based on the number of bits, thus a decimal number
  1395. // will always fit. Maybe an exaggeration, but the length isn't hardcoded.
  1396. //
  1397. if (pfnAlloc)
  1398. {
  1399. pszSerialNum = (LPTSTR)pfnAlloc(sizeof(dwVolumeSerialNumber)*8*sizeof(TCHAR));
  1400. }
  1401. else
  1402. {
  1403. pszSerialNum = (LPTSTR)HeapAlloc(GetProcessHeap(),
  1404. HEAP_ZERO_MEMORY,
  1405. sizeof(dwVolumeSerialNumber)*8*sizeof(TCHAR));
  1406. }
  1407. if (pszSerialNum)
  1408. {
  1409. DWORD dwSNLen = 0;
  1410. wsprintf(pszSerialNum, TEXT("%u"), dwVolumeSerialNumber);
  1411. //
  1412. // See how many times the serial number string will fit into our buffer
  1413. // Need to check the length due to PREFIX. If the length is 0, just return.
  1414. //
  1415. dwSNLen = lstrlen(pszSerialNum);
  1416. if (dwSNLen)
  1417. {
  1418. dwLen = (dwTempKeyStrMaxLen - 1) / dwSNLen;
  1419. }
  1420. else
  1421. {
  1422. fFuncRet = FALSE;
  1423. goto done;
  1424. }
  1425. if (0 < dwLen)
  1426. {
  1427. DWORD i = 0;
  1428. lstrcpy(szTempKeyStr, pszSerialNum);
  1429. //
  1430. // Fill up the buffer. Start at 1 because we already copied the first
  1431. // serial number into the buffer
  1432. //
  1433. for (i = 1; i<dwLen; i++)
  1434. {
  1435. lstrcat(szTempKeyStr, pszSerialNum);
  1436. }
  1437. }
  1438. else
  1439. {
  1440. //
  1441. // the length is larger than the buffer so just copy what fits into the buffer
  1442. //
  1443. lstrcpyn(szTempKeyStr, pszSerialNum, dwTempKeyStrMaxLen-1);
  1444. }
  1445. }
  1446. else
  1447. {
  1448. fFuncRet = FALSE;
  1449. }
  1450. }
  1451. done:
  1452. if (pfnFree)
  1453. {
  1454. pfnFree(pszSerialNum);
  1455. }
  1456. else
  1457. {
  1458. HeapFree(GetProcessHeap(), 0, (LPVOID)pszSerialNum);
  1459. }
  1460. return fFuncRet;
  1461. }