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.

932 lines
26 KiB

  1. /****************************************************************************
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name: crypt.c
  4. Abstract: Encryption/Decryption routines
  5. Author: radus - 11/05/98
  6. Notes: Used for encrypting/decrypting of the PIN numbers.
  7. Rev History:
  8. ****************************************************************************/
  9. #define STRICT
  10. #include <windows.h>
  11. #include <windowsx.h>
  12. #include <tchar.h>
  13. #include <stdlib.h>
  14. #include <wincrypt.h>
  15. #include <shlwapi.h>
  16. #include <shlwapip.h>
  17. #include "tregupr2.h"
  18. #include "debug.h"
  19. // Context
  20. static LONG gdwNrOfClients = 0;
  21. static PTSTR gpszSidText = NULL;
  22. static HCRYPTPROV ghCryptProvider = 0;
  23. static BOOL gbUseOnlyTheOldAlgorithm = TRUE;
  24. static BOOL gbCryptAvailChecked = FALSE;
  25. static BOOL gbCryptAvailable = TRUE;
  26. static BOOL gbInitOk = FALSE;
  27. // Critical section
  28. static CRITICAL_SECTION gCryptCritsec;
  29. static const CHAR MAGIC_1 = 'B';
  30. static const CHAR MAGIC_5 = 'L';
  31. static const CHAR MAGIC_2 = 'U';
  32. static const CHAR MAGIC_4 = 'U';
  33. static const CHAR MAGIC_3 = 'B';
  34. #define ENCRYPTED_MARKER L'X'
  35. // prototypes
  36. static BOOL GetUserSidText(LPTSTR *);
  37. static BOOL GetUserTokenUser(TOKEN_USER **);
  38. static BOOL ConvertSidToText(PSID, LPTSTR, LPDWORD);
  39. static BOOL CreateSessionKey(HCRYPTPROV, LPTSTR, DWORD, HCRYPTKEY *);
  40. static void DestroySessionKey(HCRYPTKEY );
  41. static void Unscrambler( DWORD, LPWSTR, LPWSTR );
  42. static void CopyScrambled( LPWSTR, LPWSTR, DWORD);
  43. DWORD TapiCryptInit()
  44. {
  45. __try
  46. {
  47. InitializeCriticalSection(&gCryptCritsec);
  48. }
  49. __except (EXCEPTION_EXECUTE_HANDLER)
  50. {
  51. return GetExceptionCode();
  52. }
  53. gbInitOk = TRUE;
  54. return ERROR_SUCCESS;
  55. }
  56. void TapiCryptShutdown()
  57. {
  58. if (gbInitOk)
  59. {
  60. DeleteCriticalSection(&gCryptCritsec);
  61. }
  62. }
  63. DWORD TapiCryptInitialize(void)
  64. {
  65. DWORD dwNew;
  66. DWORD dwError;
  67. HCRYPTKEY hKey;
  68. PBYTE bTestData = "Testing";
  69. DWORD dwTestSize = strlen(bTestData);
  70. // Only one initialization
  71. EnterCriticalSection(&gCryptCritsec);
  72. gdwNrOfClients++;
  73. if(gdwNrOfClients>1)
  74. {
  75. LeaveCriticalSection(&gCryptCritsec);
  76. return ERROR_SUCCESS;
  77. }
  78. // By default
  79. gbUseOnlyTheOldAlgorithm = TRUE;
  80. dwError = ERROR_SUCCESS;
  81. #ifdef WINNT
  82. // New encryption only for Windows NT
  83. if(gbCryptAvailable || !gbCryptAvailChecked)
  84. {
  85. // Acquire CryptoAPI context
  86. if(CryptAcquireContext( &ghCryptProvider,
  87. NULL,
  88. MS_DEF_PROV,
  89. PROV_RSA_FULL,
  90. CRYPT_VERIFYCONTEXT // No need of private/public keys
  91. ))
  92. {
  93. // Get the user SID
  94. if(GetUserSidText(&gpszSidText))
  95. {
  96. if (gbCryptAvailChecked == FALSE)
  97. {
  98. if(CreateSessionKey(ghCryptProvider, gpszSidText, 0, &hKey))
  99. {
  100. // try to use the test key and check for the NTE_PERM error meaning that we are not
  101. // going to be able to use crypt
  102. if (CryptEncrypt(hKey, 0, TRUE, 0, (BYTE *)bTestData, &dwTestSize, 0) == FALSE)
  103. {
  104. if (GetLastError() == NTE_PERM)
  105. {
  106. DBGOUT((5, "Encryption unavailable"));
  107. gbCryptAvailable = FALSE;
  108. }
  109. }
  110. // FOR TEST
  111. // DBGOUT((5, "Encryption unavailable")); // Test Only
  112. // gbCryptAvailable = FALSE; // Test Only
  113. gbCryptAvailChecked = TRUE;
  114. DestroySessionKey(hKey);
  115. }
  116. else
  117. dwError = GetLastError();
  118. }
  119. gbUseOnlyTheOldAlgorithm = !gbCryptAvailable;
  120. }
  121. else
  122. dwError = GetLastError();
  123. }
  124. else
  125. {
  126. dwError = GetLastError();
  127. DBGOUT((5, "CryptAcquireContext failed"));
  128. }
  129. }
  130. #endif // WINNT
  131. LeaveCriticalSection(&gCryptCritsec);
  132. return dwError;
  133. }
  134. void TapiCryptUninitialize(void)
  135. {
  136. EnterCriticalSection(&gCryptCritsec);
  137. assert(gdwNrOfClients > 0);
  138. gdwNrOfClients--;
  139. if(gdwNrOfClients>0)
  140. {
  141. LeaveCriticalSection(&gCryptCritsec);
  142. return;
  143. }
  144. #ifdef WINNT
  145. if(ghCryptProvider)
  146. {
  147. CryptReleaseContext(ghCryptProvider, 0);
  148. ghCryptProvider = 0;
  149. }
  150. if(gpszSidText)
  151. {
  152. GlobalFree(gpszSidText);
  153. gpszSidText = NULL;
  154. }
  155. #endif
  156. gbUseOnlyTheOldAlgorithm = TRUE;
  157. LeaveCriticalSection(&gCryptCritsec);
  158. return;
  159. }
  160. /////////////////////////////////
  161. // TapiEncrypt
  162. //
  163. // Encrypts the text specified in pszSource.
  164. // Uses the old scrambling algorithm or a cryptographic one.
  165. // The result buffer should be a little bit larger than the source - for pads, etc.
  166. //
  167. DWORD TapiEncrypt(PWSTR pszSource, DWORD dwKey, PWSTR pszDest, DWORD *pdwLengthNeeded)
  168. {
  169. DWORD dwError;
  170. DWORD dwDataLength,
  171. dwLength,
  172. dwLengthDwords,
  173. dwLengthAlpha;
  174. // for speed
  175. BYTE bBuffer1[0x20];
  176. PBYTE pBuffer1 = NULL;
  177. HCRYPTKEY hKey = 0;
  178. DWORD *pdwCrt1;
  179. WCHAR *pwcCrt2;
  180. DWORD dwShift;
  181. DWORD dwCount, dwCount2;
  182. EnterCriticalSection(&gCryptCritsec);
  183. #ifdef WINNT
  184. if(!gbUseOnlyTheOldAlgorithm)
  185. {
  186. // A null PIN is not encrypted
  187. if(*pszSource==L'\0')
  188. {
  189. if(pszDest)
  190. *pszDest = L'\0';
  191. if(pdwLengthNeeded)
  192. *pdwLengthNeeded = 1;
  193. LeaveCriticalSection(&gCryptCritsec);
  194. return ERROR_SUCCESS;
  195. }
  196. dwDataLength = (wcslen(pszSource) + 1)*sizeof(WCHAR); // in bytes
  197. dwLength = dwDataLength + 16; // space for pads, a marker etc.
  198. dwLengthAlpha = dwLength*3; // due to the binary->alphabetic conversion
  199. if(pszDest==NULL && pdwLengthNeeded != NULL)
  200. {
  201. *pdwLengthNeeded = dwLengthAlpha/sizeof(WCHAR); // length in characters
  202. dwError = ERROR_SUCCESS;
  203. }
  204. else
  205. {
  206. ZeroMemory(bBuffer1, sizeof(bBuffer1));
  207. pBuffer1 = dwLength>sizeof(bBuffer1) ? (PBYTE)GlobalAlloc(GPTR, dwLength) : bBuffer1;
  208. if(pBuffer1!=NULL)
  209. {
  210. // Copy the source
  211. wcscpy((PWSTR)pBuffer1, pszSource);
  212. // create session key
  213. if(CreateSessionKey(ghCryptProvider, gpszSidText, dwKey, &hKey))
  214. {
  215. // Encrypt inplace
  216. if(CryptEncrypt(hKey,
  217. 0,
  218. TRUE,
  219. 0,
  220. pBuffer1,
  221. &dwDataLength,
  222. dwLength))
  223. {
  224. // Convert to UNICODE between 0030 - 006f
  225. // I hope !
  226. assert((dwDataLength % sizeof(DWORD))==0);
  227. assert(sizeof(DWORD)==4);
  228. assert(sizeof(DWORD) == 2*sizeof(WCHAR));
  229. pdwCrt1 = (DWORD *)pBuffer1;
  230. pwcCrt2 = (WCHAR *)pszDest;
  231. // Place a marker
  232. *pwcCrt2++ = ENCRYPTED_MARKER;
  233. // dwDataLength has the length in bytes of the ciphered data
  234. dwLengthAlpha = dwDataLength*3;
  235. dwLengthDwords = dwDataLength / sizeof(DWORD);
  236. for(dwCount=0; dwCount<dwLengthDwords; dwCount++)
  237. {
  238. dwShift = *pdwCrt1++;
  239. for(dwCount2=0; dwCount2<6; dwCount2++)
  240. {
  241. *pwcCrt2++ = (WCHAR)((dwShift & 0x3f) + 0x30);
  242. dwShift >>= 6;
  243. }
  244. }
  245. // Put a NULL terminator
  246. *pwcCrt2++ = L'\0';
  247. if(pdwLengthNeeded)
  248. *pdwLengthNeeded = (dwLengthAlpha/sizeof(WCHAR))+2; // including the NULL and the marker
  249. dwError = ERROR_SUCCESS;
  250. }
  251. else
  252. dwError = GetLastError();
  253. }
  254. else
  255. dwError = GetLastError();
  256. }
  257. else
  258. dwError = GetLastError();
  259. }
  260. if(pBuffer1 && pBuffer1!=bBuffer1)
  261. GlobalFree(pBuffer1);
  262. if(hKey!=0)
  263. DestroySessionKey(hKey);
  264. }
  265. else
  266. {
  267. #endif
  268. if(pdwLengthNeeded != NULL)
  269. {
  270. *pdwLengthNeeded = wcslen(pszSource) + 1; // dim in characters
  271. }
  272. if(pszDest!=NULL)
  273. {
  274. CopyScrambled(pszSource, pszDest, dwKey);
  275. }
  276. dwError = ERROR_SUCCESS;
  277. #ifdef WINNT
  278. }
  279. #endif
  280. LeaveCriticalSection(&gCryptCritsec);
  281. return dwError;
  282. }
  283. DWORD TapiDecrypt(PWSTR pszSource, DWORD dwKey, PWSTR pszDest, DWORD *pdwLengthNeeded)
  284. {
  285. DWORD dwError;
  286. DWORD dwLengthCrypted;
  287. DWORD dwDataLength;
  288. DWORD dwLengthDwords;
  289. HCRYPTKEY hKey = 0;
  290. WCHAR *pwcCrt1;
  291. DWORD *pdwCrt2;
  292. DWORD dwCount;
  293. DWORD dwCount2;
  294. DWORD dwShift;
  295. // A null PIN is not encrypted
  296. if(*pszSource==L'\0')
  297. {
  298. if(pszDest)
  299. *pszDest = L'\0';
  300. if(pdwLengthNeeded)
  301. *pdwLengthNeeded = 1;
  302. return ERROR_SUCCESS;
  303. }
  304. dwError = ERROR_SUCCESS;
  305. EnterCriticalSection(&gCryptCritsec);
  306. // If the first char is a 'X', we have encrypted data
  307. if(*pszSource == ENCRYPTED_MARKER)
  308. {
  309. #ifdef WINNT
  310. if(gbCryptAvailable && gdwNrOfClients>0)
  311. {
  312. dwLengthCrypted = wcslen(pszSource) +1 -2; // In characters, without the marker and the NULL
  313. assert(dwLengthCrypted % 6 == 0);
  314. dwLengthDwords = dwLengthCrypted / 6;
  315. if(pszDest==NULL && pdwLengthNeeded)
  316. {
  317. *pdwLengthNeeded = dwLengthDwords*(sizeof(DWORD)/sizeof(WCHAR));
  318. dwError = ERROR_SUCCESS;
  319. }
  320. else
  321. {
  322. // Convert to binary
  323. pwcCrt1 = pszSource + dwLengthCrypted; // end of the string, before the NULL
  324. pdwCrt2 = ((DWORD *)pszDest) + dwLengthDwords -1; // Last DWORD
  325. for(dwCount=0; dwCount<dwLengthDwords; dwCount++)
  326. {
  327. dwShift=0;
  328. for(dwCount2=0; dwCount2<6; dwCount2++)
  329. {
  330. dwShift <<= 6;
  331. dwShift |= ((*pwcCrt1-- - 0x30) & 0x3f);
  332. }
  333. *pdwCrt2-- = dwShift;
  334. }
  335. if(CreateSessionKey(ghCryptProvider, gpszSidText, dwKey, &hKey))
  336. {
  337. dwDataLength = dwLengthDwords * sizeof(DWORD);
  338. // Decrypt in place
  339. if(CryptDecrypt(hKey,
  340. 0,
  341. TRUE,
  342. 0,
  343. (PBYTE)pszDest,
  344. &dwDataLength))
  345. {
  346. dwDataLength /= sizeof(WCHAR);
  347. if(*(pszDest+dwDataLength-1)==L'\0') // The ending NULL was encrypted too
  348. {
  349. if(pdwLengthNeeded)
  350. *pdwLengthNeeded = dwDataLength;
  351. dwError = ERROR_SUCCESS;
  352. }
  353. else
  354. {
  355. *pszDest = L'\0';
  356. dwError = ERROR_INVALID_DATA;
  357. }
  358. }
  359. else
  360. dwError = GetLastError();
  361. DestroySessionKey(hKey);
  362. }
  363. else
  364. dwError = GetLastError();
  365. }
  366. }
  367. else
  368. dwError = ERROR_INVALID_DATA;
  369. #else
  370. dwError = ERROR_INVALID_DATA;
  371. #endif
  372. }
  373. else
  374. {
  375. if(pdwLengthNeeded != NULL)
  376. {
  377. *pdwLengthNeeded = wcslen(pszSource) + 1; // dim in characters
  378. }
  379. if(pszDest!=NULL)
  380. {
  381. Unscrambler(dwKey, pszSource, pszDest);
  382. }
  383. dwError = ERROR_SUCCESS;
  384. }
  385. LeaveCriticalSection(&gCryptCritsec);
  386. return dwError;
  387. }
  388. /////////////////////////////////
  389. // TapiIsSafeToDisplaySensitiveData
  390. //
  391. // Detects if the current process is running in the "LocalSystem" security context.
  392. // Returns FALSE if it is, TRUE if it is not.
  393. // Returns also FALSE if an error occurs.
  394. BOOL TapiIsSafeToDisplaySensitiveData(void)
  395. {
  396. #ifdef WINNT
  397. DWORD dwError = ERROR_SUCCESS;
  398. TOKEN_USER *User = NULL;
  399. SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY;
  400. PSID SystemSid = NULL;
  401. BOOL bIsSafe = FALSE;
  402. // Get the User info
  403. if(GetUserTokenUser(&User))
  404. {
  405. // Create a system SID
  406. if(AllocateAndInitializeSid(&SidAuth,
  407. 1,
  408. SECURITY_LOCAL_SYSTEM_RID,
  409. 0, 0, 0, 0, 0, 0, 0,
  410. &SystemSid
  411. ))
  412. {
  413. // Compare the two sids
  414. bIsSafe = !EqualSid(SystemSid, User->User.Sid);
  415. FreeSid(SystemSid);
  416. }
  417. else
  418. {
  419. dwError = GetLastError();
  420. }
  421. GlobalFree(User);
  422. }
  423. else
  424. {
  425. dwError = GetLastError();
  426. }
  427. DBGOUT((5, "TapiIsSafeToDisplaySensitiveData - dwError=0x%x, Safe=%d", dwError, bIsSafe));
  428. return bIsSafe;
  429. #else // WINNT
  430. return TRUE; // always safe
  431. #endif
  432. }
  433. #ifdef WINNT
  434. /////////////////////////////////
  435. // GetUserSidText
  436. //
  437. // Retrieves the SID from the token of the current process in text format
  438. BOOL GetUserSidText(LPTSTR *ppszResultSid)
  439. {
  440. TOKEN_USER *User = NULL;
  441. DWORD dwLength;
  442. LPTSTR pszSidText = NULL;
  443. // Get the SID
  444. if(!GetUserTokenUser(&User))
  445. {
  446. DBGOUT((5, "GetMagic (0) failed, 0x%x", GetLastError()));
  447. return FALSE;
  448. }
  449. // Query the space needed for the string format of the SID
  450. dwLength=0;
  451. if(!ConvertSidToText(User->User.Sid, NULL, &dwLength)
  452. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  453. {
  454. DBGOUT((5, "GetMagic (1) failed, 0x%x", GetLastError()));
  455. GlobalFree(User);
  456. return FALSE;
  457. }
  458. // Alloc the space
  459. pszSidText = (LPTSTR)GlobalAlloc(GMEM_FIXED, dwLength);
  460. if(pszSidText==NULL)
  461. {
  462. GlobalFree(User);
  463. return FALSE;
  464. }
  465. // Convert the SID in string format
  466. if(!ConvertSidToText(User->User.Sid, pszSidText, &dwLength))
  467. {
  468. DBGOUT((5, "GetMagic (2) failed, 0x%x", GetLastError()));
  469. GlobalFree(User);
  470. GlobalFree(pszSidText);
  471. return FALSE;
  472. }
  473. GlobalFree(User);
  474. // The caller should free the buffer
  475. *ppszResultSid = pszSidText;
  476. return TRUE;
  477. }
  478. /////////////////////////////////
  479. // GetUserTokenUser
  480. //
  481. // Retrieves the TOKEN_USER structure from the token of the current process
  482. BOOL GetUserTokenUser(TOKEN_USER **ppszResultTokenUser)
  483. {
  484. HANDLE hToken = NULL;
  485. DWORD dwLength;
  486. TOKEN_USER *User = NULL;
  487. // Open the current process token (for read)
  488. if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
  489. {
  490. if( GetLastError() == ERROR_NO_TOKEN)
  491. {
  492. // try with the process token
  493. if (! OpenProcessToken ( GetCurrentProcess(), TOKEN_QUERY, &hToken))
  494. {
  495. DBGOUT((5, "OpenProcessToken failed, 0x%x", GetLastError()));
  496. return FALSE;
  497. }
  498. }
  499. else
  500. {
  501. DBGOUT((5, "OpenThreadToken failed, 0x%x", GetLastError()));
  502. return FALSE;
  503. }
  504. }
  505. // Find the space needed for the SID
  506. if(!GetTokenInformation(hToken, TokenUser, NULL, 0, &dwLength)
  507. && (GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  508. {
  509. DBGOUT((5, "GetTokenInformation (1) failed, 0x%x", GetLastError()));
  510. CloseHandle(hToken);
  511. return FALSE;
  512. }
  513. // Alloc the space
  514. User = (TOKEN_USER *)GlobalAlloc(GMEM_FIXED, dwLength);
  515. if(User==NULL)
  516. {
  517. CloseHandle(hToken);
  518. return FALSE;
  519. }
  520. // Retrieve the SID
  521. if(!GetTokenInformation(hToken, TokenUser, User, dwLength, &dwLength))
  522. {
  523. DBGOUT((5, "GetTokenInformation (2) failed, 0x%x", GetLastError()));
  524. CloseHandle(hToken);
  525. GlobalFree(User);
  526. return FALSE;
  527. }
  528. CloseHandle(hToken);
  529. // The caller should free the buffer
  530. *ppszResultTokenUser = User;
  531. return TRUE;
  532. }
  533. /////////////////////////////////
  534. // ConvertSidToText
  535. //
  536. // Transforms a binary SID in string format
  537. // Author Jeff Spelman
  538. BOOL ConvertSidToText(
  539. PSID pSid, // binary Sid
  540. LPTSTR TextualSid, // buffer for Textual representation of Sid
  541. LPDWORD lpdwBufferLen // required/provided TextualSid buffersize
  542. )
  543. {
  544. PSID_IDENTIFIER_AUTHORITY psia;
  545. DWORD dwSubAuthorities;
  546. DWORD dwSidRev=SID_REVISION;
  547. DWORD dwCounter;
  548. DWORD dwSidSize;
  549. // Validate the binary SID.
  550. if(!IsValidSid(pSid)) return FALSE;
  551. // Get the identifier authority value from the SID.
  552. psia = GetSidIdentifierAuthority(pSid);
  553. // Get the number of subauthorities in the SID.
  554. dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
  555. // Compute the buffer length.
  556. // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL
  557. dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);
  558. // Check input buffer length.
  559. // If too small, indicate the proper size and set last error.
  560. if (*lpdwBufferLen < dwSidSize)
  561. {
  562. *lpdwBufferLen = dwSidSize;
  563. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  564. return FALSE;
  565. }
  566. // Add 'S' prefix and revision number to the string.
  567. dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );
  568. // Add SID identifier authority to the string.
  569. if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
  570. {
  571. dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  572. TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
  573. (USHORT)psia->Value[0],
  574. (USHORT)psia->Value[1],
  575. (USHORT)psia->Value[2],
  576. (USHORT)psia->Value[3],
  577. (USHORT)psia->Value[4],
  578. (USHORT)psia->Value[5]);
  579. }
  580. else
  581. {
  582. dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
  583. TEXT("%lu"),
  584. (ULONG)(psia->Value[5] ) +
  585. (ULONG)(psia->Value[4] << 8) +
  586. (ULONG)(psia->Value[3] << 16) +
  587. (ULONG)(psia->Value[2] << 24) );
  588. }
  589. // Add SID subauthorities to the string.
  590. //
  591. for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
  592. {
  593. dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
  594. *GetSidSubAuthority(pSid, dwCounter) );
  595. }
  596. return TRUE;
  597. }
  598. /////////////////////////////////
  599. // CreateSessionKey
  600. //
  601. // Creates a session key derived from the user SID and a hint (currently the calling card ID)
  602. //
  603. //
  604. BOOL CreateSessionKey(HCRYPTPROV hProv, LPTSTR pszSidText, DWORD dwHint, HCRYPTKEY *phKey)
  605. {
  606. HCRYPTHASH hHash = 0;
  607. CHAR szTmpBuff[0x20];
  608. DWORD dwSize;
  609. LPSTR pszBuf;
  610. // Create a hash object
  611. if(!CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))
  612. {
  613. DBGOUT((5, "CryptCreateHash failed, 0x%x, Prov=0x%x", GetLastError(), hProv));
  614. return FALSE;
  615. }
  616. // the Sid is of type TCHAR but, for back compat reasons, we want to encrypt the ANSI
  617. // version of this string. We can either:
  618. // 1.) Convert the creation path for pszSid to ANSI (more correct solution)
  619. // 2.) thunk pszSid to ansi before converting (lazy solution)
  620. // I'm lazy so I'm choosing option #2. It should be safe to thunk to ANSI because the
  621. // Sid should correctly round trip back to unicode.
  622. dwSize = lstrlen(pszSidText)+1;
  623. pszBuf = (LPSTR)GlobalAlloc( GPTR, dwSize*sizeof(CHAR) );
  624. if ( !pszBuf )
  625. {
  626. // out of memory
  627. CryptDestroyHash(hHash);
  628. return FALSE;
  629. }
  630. SHTCharToAnsi( pszSidText, pszBuf, dwSize );
  631. #ifdef DEBUG
  632. #ifdef UNICODE
  633. {
  634. // ensure that the SID round trips. If it doesn't round trip then the validity of this
  635. // encription scheme is questionable on NT. The solution would be to encrypt using Unicode,
  636. // but that would break back compat.
  637. LPTSTR pszDebug;
  638. pszDebug = (LPTSTR)GlobalAlloc( GPTR, dwSize*sizeof(TCHAR) );
  639. if ( pszDebug )
  640. {
  641. SHAnsiToTChar(pszBuf, pszDebug, dwSize);
  642. if ( 0 != StrCmp( pszDebug, pszSidText ) )
  643. {
  644. DBGOUT((1,"CRYPT ERROR! Sid doesn't round trip! FIX THIS!!!"));
  645. }
  646. GlobalFree(pszDebug);
  647. }
  648. }
  649. #endif
  650. #endif
  651. // hash the SID
  652. if(!CryptHashData(hHash, (PBYTE)pszBuf, (dwSize)*sizeof(CHAR), 0))
  653. {
  654. CryptDestroyHash(hHash);
  655. return FALSE;
  656. }
  657. GlobalFree(pszBuf);
  658. // hash a "magic" and the hint
  659. ZeroMemory(szTmpBuff, sizeof(szTmpBuff));
  660. wsprintfA(szTmpBuff, "-%c%c%c%c%c%x", MAGIC_1, MAGIC_2, MAGIC_3, MAGIC_4, MAGIC_5, dwHint);
  661. if(!CryptHashData(hHash, (PBYTE)szTmpBuff, sizeof(szTmpBuff), 0))
  662. {
  663. CryptDestroyHash(hHash);
  664. return FALSE;
  665. }
  666. // Generate the key, use block alg
  667. if(!CryptDeriveKey(hProv, CALG_RC2, hHash, 0, phKey))
  668. {
  669. DBGOUT((5, "CryptDeriveKey failed, 0x%x", GetLastError()));
  670. CryptDestroyHash(hHash);
  671. return FALSE;
  672. }
  673. CryptDestroyHash(hHash);
  674. return TRUE;
  675. }
  676. /////////////////////////////////
  677. // DestroySessionKey
  678. //
  679. // Destroys a session key
  680. //
  681. //
  682. void DestroySessionKey(HCRYPTKEY hKey)
  683. {
  684. CryptDestroyKey(hKey);
  685. }
  686. #endif //WINNT
  687. // Old routines
  688. #define IsWDigit(c) (((WCHAR)(c)) >= (WCHAR)'0' && ((WCHAR)(c)) <= (WCHAR)'9')
  689. void Unscrambler( DWORD dwKey,
  690. LPWSTR lpszSrc,
  691. LPWSTR lpszDst )
  692. {
  693. UINT uIndex;
  694. UINT uSubKey;
  695. UINT uNewKey;
  696. // InternalDebugOut((101, "Entering Unscrambler"));
  697. if ( !lpszSrc || !lpszDst )
  698. {
  699. goto done;
  700. }
  701. uNewKey = (UINT)dwKey & 0x7FFF;
  702. uSubKey = (UINT)dwKey % 10;
  703. for ( uIndex = 1; *lpszSrc ; lpszSrc++, lpszDst++, uIndex++ )
  704. {
  705. if ( IsWDigit( *lpszSrc ))
  706. {
  707. // do the unscramble thang
  708. //------------------------
  709. uSubKey = ((*lpszSrc - (WCHAR)'0') - ((uSubKey + uIndex + uNewKey) % 10) + 10) % 10;
  710. *lpszDst = (WCHAR)(uSubKey + (WCHAR)'0');
  711. }
  712. else
  713. *lpszDst = *lpszSrc; // just save the byte
  714. }
  715. done:
  716. *lpszDst = (WCHAR)'\0';
  717. //InternalDebugOut((101, "Leaving Unscrambler"));
  718. return;
  719. }
  720. void CopyScrambled( LPWSTR lpszSrc,
  721. LPWSTR lpszDst,
  722. DWORD dwKey
  723. )
  724. {
  725. UINT uIndex;
  726. UINT uSubKey;
  727. UINT uNewKey;
  728. //nternalDebugOut((50, "Entering IniScrambler"));
  729. if ( !lpszSrc || !lpszDst )
  730. {
  731. goto done;
  732. } // end if
  733. uNewKey = (UINT)dwKey & 0x7FFF;
  734. uSubKey = (UINT)dwKey % 10;
  735. for ( uIndex = 1; *lpszSrc ; lpszSrc++, lpszDst++, uIndex++ )
  736. {
  737. if ( IsWDigit( *lpszSrc ))
  738. {
  739. // do the scramble thang
  740. //----------------------
  741. *lpszDst = (WCHAR)(((uSubKey + (*lpszSrc - (WCHAR)'0') + uIndex + uNewKey) % 10) + (WCHAR)'0');
  742. uSubKey = (UINT)(*lpszSrc - (WCHAR)'0');
  743. }
  744. else
  745. *lpszDst = *lpszSrc; // just save the byte
  746. } // end for
  747. done:
  748. *lpszDst = (WCHAR)'\0';
  749. // InternalDebugOut((60, "Leaving IniScrambler"));
  750. return;
  751. }