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.

1482 lines
43 KiB

  1. /*
  2. File: crypt32.cpp
  3. Title: CryptProtect APIs
  4. Author: Matt Thomlinson
  5. Date: 8/2/97
  6. The CryptProtect API set allows an application to secure
  7. user data for online and offline storage. While the well-known problem
  8. of data storage is left to the calling application, this solves the
  9. relatively unsolved problem of how to cryptographically derive strong
  10. keys for storing the data. These APIs are initially available on NT5 only.
  11. Very little checking is done at this level to validate the caller. We
  12. believe that problem should be solved at a different level -- since all
  13. other system security is granular to the user, it is difficult to create a
  14. feature that provides something more granular. Instead, any process running
  15. under the logged-in user has the ability to decrypt any and all items it
  16. can retrieve. Callers should note that while items are being processed,
  17. UI may be spawned to notify the user.
  18. For user confirmation, the NT secure attention sequence is used to
  19. garner the wishes of the user. This behavior is set by the caller during protection.
  20. */
  21. #include <pch.cpp>
  22. #pragma hdrstop
  23. #include "msaudite.h"
  24. #include "crypt.h"
  25. #define ALGID_DERIVEKEY_HASH CALG_SHA1 // doesn't change
  26. // USEC: can be as long as we want, since we castrate generated key later
  27. #define KEY_DERIVATION_BUFSIZE (128/8)
  28. #define DEFAULT_BLOCKSIZE_OVERRUN (128/8) // allow block ciphers to process up to a 128 bits at a time
  29. #define MS_BASE_CRYPTPROTECT_VERSION 0x01
  30. DWORD
  31. WINAPI
  32. SPCryptProtect(
  33. PVOID pvContext, // server context
  34. PBYTE* ppbOut, // out encr data
  35. DWORD* pcbOut, // out encr cb
  36. PBYTE pbIn, // in ptxt data
  37. DWORD cbIn, // in ptxt cb
  38. LPCWSTR szDataDescr, // in
  39. PBYTE pbOptionalEntropy, // OPTIONAL
  40. DWORD cbOptionalEntropy,
  41. PSSCRYPTPROTECTDATA_PROMPTSTRUCT psPrompt, // OPTIONAL prompting struct
  42. DWORD dwFlags,
  43. BYTE* pbOptionalPassword,
  44. DWORD cbOptionalPassword
  45. )
  46. {
  47. DWORD dwRet;
  48. LPWSTR szUser = NULL;
  49. PBYTE pbWritePtr = NULL;
  50. GUID guidMK;
  51. WCHAR wszMKGuidString[MAX_GUID_SZ_CHARS];
  52. HCRYPTPROV hVerifyProv;
  53. HCRYPTHASH hHash = NULL;
  54. HCRYPTKEY hKey = NULL;
  55. PBYTE pbCrypt = NULL;
  56. DWORD cbCrypt = 0;
  57. DWORD cbEncrypted; // count of bytes to encrypt
  58. PBYTE pbEncrSalt = NULL;
  59. DWORD cbEncrSalt = 0;
  60. BYTE rgbPwdBuf[A_SHA_DIGEST_LEN];
  61. DWORD cbMACSize = A_SHA_DIGEST_LEN;
  62. BYTE rgbEncrKey[KEY_DERIVATION_BUFSIZE];
  63. BYTE rgbMACKey[KEY_DERIVATION_BUFSIZE];
  64. LPBYTE pbMasterKey = NULL;
  65. DWORD cbMasterKey = 0;
  66. PBYTE pStreamFlagPtr;
  67. DWORD dwProtectionFlags = 0;
  68. DWORD dwDefaultCryptProvType = 0;
  69. DWORD dwAlgID_Encr_Alg = 0;
  70. DWORD dwAlgID_Encr_Alg_KeySize = 0;
  71. DWORD dwAlgID_MAC_Alg = 0;
  72. DWORD dwAlgID_MAC_Alg_KeySize = 0;
  73. PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
  74. #if DBG
  75. D_DebugLog((DEB_TRACE_API,"SPCryptProtect 0x%x called\n", pServerContext));
  76. if(pServerContext)
  77. {
  78. if(pServerContext->cbSize == sizeof(CRYPT_SERVER_CONTEXT))
  79. {
  80. D_DebugLog((DEB_TRACE_API, " pServerContext->hBinding:%d\n", pServerContext->hBinding));
  81. D_DebugLog((DEB_TRACE_API, " pServerContext->fOverrideToLocalSystem:%d\n", pServerContext->fOverrideToLocalSystem));
  82. D_DebugLog((DEB_TRACE_API, " pServerContext->fImpersonating:%d\n", pServerContext->fImpersonating));
  83. D_DebugLog((DEB_TRACE_API, " pServerContext->hToken:%d\n", pServerContext->hToken));
  84. D_DebugLog((DEB_TRACE_API, " pServerContext->szUserStorageArea:%ls\n", pServerContext->szUserStorageArea));
  85. D_DebugLog((DEB_TRACE_API, " pServerContext->WellKnownAccount:%d\n", pServerContext->WellKnownAccount));
  86. }
  87. }
  88. D_DebugLog((DEB_TRACE_API, " pbInput:0x%x\n", pbIn));
  89. D_DebugLog((DEB_TRACE_API, " pszDataDescr:%ls\n", szDataDescr));
  90. D_DebugLog((DEB_TRACE_API, " pbOptionalEntropy:0x%x\n", pbOptionalEntropy));
  91. D_DPAPIDumpHexData(DEB_TRACE_BUFFERS, " ", pbOptionalEntropy, cbOptionalEntropy);
  92. D_DebugLog((DEB_TRACE_API, " dwFlags:0x%x\n", dwFlags));
  93. D_DebugLog((DEB_TRACE_API, " pbOptionalPassword:0x%x\n", pbOptionalPassword));
  94. D_DPAPIDumpHexData(DEB_TRACE_BUFFERS, " ", pbOptionalPassword, cbOptionalPassword);
  95. #endif
  96. ZeroMemory(&guidMK, sizeof(guidMK));
  97. wszMKGuidString[0] = 0;
  98. GetDefaultAlgInfo(&dwDefaultCryptProvType,
  99. &dwAlgID_Encr_Alg,
  100. &dwAlgID_Encr_Alg_KeySize,
  101. &dwAlgID_MAC_Alg,
  102. &dwAlgID_MAC_Alg_KeySize);
  103. if( dwFlags & CRYPTPROTECT_LOCAL_MACHINE ) {
  104. BOOL fOverrideToLocalSystem = TRUE;
  105. CPSOverrideToLocalSystem(
  106. pvContext,
  107. &fOverrideToLocalSystem,
  108. NULL // don't care what previous value was
  109. );
  110. dwProtectionFlags |= CRYPTPROTECT_LOCAL_MACHINE;
  111. }
  112. if( dwFlags & CRYPTPROTECT_CRED_SYNC )
  113. {
  114. if(dwFlags != CRYPTPROTECT_CRED_SYNC)
  115. {
  116. // If the user is reencrypting master keys, then no other flags
  117. // may be specified. Lets do one thing at a time, shall we?
  118. D_DebugLog((DEB_ERROR, "SPCryptProtect: Invalid flags 0x%x\n", dwFlags));
  119. return ERROR_INVALID_PARAMETER;
  120. }
  121. dwRet = CPSImpersonateClient( pvContext );
  122. if( dwRet == ERROR_SUCCESS )
  123. {
  124. dwRet = InitiateSynchronizeMasterKeys( pvContext );
  125. CPSRevertToSelf( pvContext );
  126. }
  127. return dwRet;
  128. }
  129. if( dwFlags & CRYPTPROTECT_CRED_REGENERATE )
  130. {
  131. if(dwFlags != CRYPTPROTECT_CRED_REGENERATE)
  132. {
  133. // If the user is reencrypting master keys, then no other flags
  134. // may be specified. Lets do one thing at a time, shall we?
  135. D_DebugLog((DEB_ERROR, "SPCryptProtect: Invalid flags 0x%x\n", dwFlags));
  136. return ERROR_INVALID_PARAMETER;
  137. }
  138. dwRet = DpapiUpdateLsaSecret( pvContext );
  139. return dwRet;
  140. }
  141. //
  142. // include additional flags
  143. //
  144. dwProtectionFlags |= (dwFlags & (CRYPTPROTECT_SYSTEM | CRYPTPROTECT_AUDIT));
  145. // else no override; get provider by algs alone
  146. if (NULL == (hVerifyProv =
  147. GetCryptProviderHandle(
  148. dwDefaultCryptProvType,
  149. dwAlgID_Encr_Alg, &dwAlgID_Encr_Alg_KeySize,
  150. dwAlgID_MAC_Alg, &dwAlgID_MAC_Alg_KeySize)) )
  151. {
  152. dwRet = GetLastError();
  153. goto Ret;
  154. }
  155. dwRet = GetSpecifiedMasterKey(
  156. pvContext,
  157. &guidMK,
  158. &pbMasterKey,
  159. &cbMasterKey,
  160. FALSE // we don't know what master key we want to use - use preferred
  161. );
  162. if(dwRet != ERROR_SUCCESS)
  163. goto Ret;
  164. MyGuidToStringW(&guidMK, wszMKGuidString);
  165. //
  166. // hash pbMasterKey to get rgbPwdBuf
  167. //
  168. FMyPrimitiveSHA( pbMasterKey, cbMasterKey, rgbPwdBuf );
  169. // derive encr key
  170. {
  171. if (!RtlGenRandom(
  172. rgbEncrKey,
  173. sizeof(rgbEncrKey)))
  174. {
  175. dwRet = GetLastError();
  176. goto Ret;
  177. }
  178. #if DBG
  179. // Leave here as regression check
  180. CheckMACInterop(rgbPwdBuf, sizeof(rgbPwdBuf), rgbEncrKey, sizeof(rgbEncrKey), hVerifyProv, ALGID_DERIVEKEY_HASH);
  181. #endif
  182. if (!FMyPrimitiveCryptHMAC(
  183. rgbPwdBuf,
  184. sizeof(rgbPwdBuf),
  185. rgbEncrKey,
  186. sizeof(rgbEncrKey),
  187. hVerifyProv,
  188. ALGID_DERIVEKEY_HASH,
  189. &hHash))
  190. {
  191. dwRet = GetLastError();
  192. goto Ret;
  193. }
  194. // add password if exists
  195. if (NULL != pbOptionalEntropy)
  196. {
  197. if (!CryptHashData(
  198. hHash,
  199. pbOptionalEntropy,
  200. cbOptionalEntropy,
  201. 0))
  202. {
  203. dwRet = GetLastError();
  204. goto Ret;
  205. }
  206. }
  207. // add prompted UI based password if exists.
  208. // will eventually come from SAS
  209. //
  210. if ( NULL != pbOptionalPassword && cbOptionalPassword )
  211. {
  212. if (!CryptHashData(
  213. hHash,
  214. pbOptionalPassword,
  215. cbOptionalPassword,
  216. 0))
  217. {
  218. dwRet = GetLastError();
  219. goto Ret;
  220. }
  221. }
  222. if (!CryptDeriveKey(
  223. hVerifyProv,
  224. dwAlgID_Encr_Alg,
  225. hHash,
  226. CRYPT_CREATE_SALT,
  227. &hKey))
  228. {
  229. dwRet = GetLastError();
  230. goto Ret;
  231. }
  232. CryptDestroyHash(hHash);
  233. hHash = 0;
  234. // USEC -- (US Export Controls)
  235. if (ERROR_SUCCESS != (dwRet =
  236. GetSaltForExportControl(
  237. hVerifyProv,
  238. hKey,
  239. &pbEncrSalt,
  240. &cbEncrSalt)) )
  241. goto Ret;
  242. }
  243. // derive MAC key
  244. {
  245. if (!RtlGenRandom(
  246. rgbMACKey,
  247. sizeof(rgbMACKey)))
  248. {
  249. dwRet = GetLastError();
  250. goto Ret;
  251. }
  252. if (!FMyPrimitiveCryptHMAC(
  253. rgbPwdBuf,
  254. sizeof(rgbPwdBuf),
  255. rgbMACKey,
  256. sizeof(rgbMACKey),
  257. hVerifyProv,
  258. dwAlgID_MAC_Alg,
  259. &hHash))
  260. {
  261. dwRet = GetLastError();
  262. goto Ret;
  263. }
  264. // add password if exists
  265. if (NULL != pbOptionalEntropy)
  266. {
  267. if (!CryptHashData(
  268. hHash,
  269. pbOptionalEntropy,
  270. cbOptionalEntropy,
  271. 0))
  272. {
  273. dwRet = GetLastError();
  274. goto Ret;
  275. }
  276. }
  277. // add prompted UI based password if exists.
  278. // will eventually come from SAS
  279. //
  280. if ( NULL != pbOptionalPassword && cbOptionalPassword )
  281. {
  282. if (!CryptHashData(
  283. hHash,
  284. pbOptionalPassword,
  285. cbOptionalPassword,
  286. 0))
  287. {
  288. dwRet = GetLastError();
  289. goto Ret;
  290. }
  291. }
  292. // USEC -- (US Export Controls)
  293. // Does not apply to MAC -- use strong key
  294. }
  295. // Decrypt the input buffer.
  296. if((dwFlags & CRYPTPROTECT_IN_PROCESS) == 0)
  297. {
  298. DWORD cbPadding;
  299. if((cbIn < RTL_ENCRYPT_MEMORY_SIZE) ||
  300. (cbIn % RTL_ENCRYPT_MEMORY_SIZE))
  301. {
  302. dwRet = ERROR_INVALID_DATA;
  303. goto Ret;
  304. }
  305. dwRet = RpcImpersonateClient(((PCRYPT_SERVER_CONTEXT)pvContext)->hBinding);
  306. if(dwRet == ERROR_SUCCESS)
  307. {
  308. NTSTATUS Status;
  309. Status = RtlDecryptMemory(pbIn,
  310. cbIn,
  311. RTL_ENCRYPT_OPTION_SAME_LOGON);
  312. if(!NT_SUCCESS(Status))
  313. {
  314. dwRet = ERROR_DECRYPTION_FAILED;
  315. }
  316. RevertToSelf();
  317. }
  318. // Remove padding
  319. if(dwRet == ERROR_SUCCESS)
  320. {
  321. cbPadding = pbIn[cbIn - 1];
  322. if((cbPadding > 0) &&
  323. (cbPadding <= cbIn) &&
  324. (cbPadding <= RTL_ENCRYPT_MEMORY_SIZE))
  325. {
  326. cbIn -= cbPadding;
  327. }
  328. else
  329. {
  330. dwRet = ERROR_INVALID_DATA;
  331. }
  332. }
  333. }
  334. // hash & encrypt the data
  335. cbCrypt = cbIn + DEFAULT_BLOCKSIZE_OVERRUN;
  336. if (NULL == (pbCrypt = (PBYTE)SSAlloc(cbCrypt)) )
  337. {
  338. dwRet = ERROR_OUTOFMEMORY;
  339. goto Ret;
  340. }
  341. CopyMemory(pbCrypt, pbIn, cbIn);
  342. // now write data out: size?
  343. *pcbOut = sizeof(GUID) + 2*sizeof(DWORD); // dwVer + guidMK + dwFlags
  344. *pcbOut += sizeof(DWORD) + WSZ_BYTECOUNT(szDataDescr); // data description
  345. *pcbOut += 3*sizeof(DWORD) + sizeof(rgbEncrKey); // EncrAlgID + AlgIDKeySize + cbEncrKey + EncrKey
  346. *pcbOut += sizeof(DWORD) + cbEncrSalt; // Encr salt
  347. *pcbOut += 3*sizeof(DWORD) + sizeof(rgbMACKey); // MACAlgID + AlgIDKeySize + cbMACKey + MACKey
  348. *pcbOut += sizeof(DWORD) + cbCrypt; // size + encrypted data (guess)
  349. *pcbOut += sizeof(DWORD) + A_SHA_DIGEST_LEN; // MAC + MACsize
  350. *ppbOut = (PBYTE)SSAlloc(*pcbOut);
  351. if( *ppbOut == NULL ) {
  352. dwRet = ERROR_OUTOFMEMORY;
  353. goto Ret;
  354. }
  355. ZeroMemory( *ppbOut, *pcbOut );
  356. pbWritePtr = *ppbOut;
  357. ////////////////////////////////////////////////////////////////////
  358. // FYI: Data format
  359. // ( Version | guidMKid | dwFlags |
  360. // cbDataDescr | szDataDescr |
  361. //
  362. // dwEncrAlgID | dwEncrAlgKeySize |
  363. // cbEncrKey | EncrKey |
  364. // cbEncrSalt | EncrSalt |
  365. //
  366. // dwMACAlgID | dwMACAlgKeySize |
  367. // cbMACKey | MACKey |
  368. //
  369. // cbEncrData | EncrData |
  370. // cbMAC | MAC )
  371. //
  372. // NOTE: entire buffer from Version through EncrData is included in MAC
  373. ////////////////////////////////////////////////////////////////////
  374. // dwVersion
  375. *(DWORD UNALIGNED *)pbWritePtr = MS_BASE_CRYPTPROTECT_VERSION;
  376. pbWritePtr += sizeof(DWORD);
  377. // guid MKid
  378. CopyMemory(pbWritePtr, &guidMK, sizeof(GUID));
  379. pbWritePtr += sizeof(GUID);
  380. // dwFlags -- written out later via pStreamFlagPtr
  381. pStreamFlagPtr = pbWritePtr;
  382. pbWritePtr += sizeof(DWORD);
  383. // cbDataDescr
  384. *(DWORD UNALIGNED *)pbWritePtr = WSZ_BYTECOUNT(szDataDescr);
  385. pbWritePtr += sizeof(DWORD);
  386. // szDataDescr
  387. CopyMemory(pbWritePtr, szDataDescr, WSZ_BYTECOUNT(szDataDescr));
  388. pbWritePtr += WSZ_BYTECOUNT(szDataDescr);
  389. // dwEncrAlgID
  390. *(DWORD UNALIGNED *)pbWritePtr = dwAlgID_Encr_Alg;
  391. pbWritePtr += sizeof(DWORD);
  392. // dwEncrAlgKeySize
  393. *(DWORD UNALIGNED *)pbWritePtr = dwAlgID_Encr_Alg_KeySize;
  394. pbWritePtr += sizeof(DWORD);
  395. // cb EncrKey
  396. *(DWORD UNALIGNED *)pbWritePtr = sizeof(rgbEncrKey);
  397. pbWritePtr += sizeof(DWORD);
  398. // Encr Key
  399. CopyMemory(pbWritePtr, rgbEncrKey, sizeof(rgbEncrKey));
  400. pbWritePtr += sizeof(rgbEncrKey);
  401. // cb Encr salt
  402. *(DWORD UNALIGNED *)pbWritePtr = cbEncrSalt;
  403. pbWritePtr += sizeof(DWORD);
  404. // Encr salt
  405. CopyMemory(pbWritePtr, pbEncrSalt, cbEncrSalt);
  406. pbWritePtr += cbEncrSalt;
  407. // dwMACAlgID
  408. *(DWORD UNALIGNED *)pbWritePtr = dwAlgID_MAC_Alg;
  409. pbWritePtr += sizeof(DWORD);
  410. // dwMACAlgKeySize
  411. *(DWORD UNALIGNED *)pbWritePtr = dwAlgID_MAC_Alg_KeySize;
  412. pbWritePtr += sizeof(DWORD);
  413. // cb MAC key
  414. *(DWORD UNALIGNED *)pbWritePtr = sizeof(rgbMACKey);
  415. pbWritePtr += sizeof(DWORD);
  416. // MAC key
  417. CopyMemory(pbWritePtr, rgbMACKey, sizeof(rgbMACKey));
  418. pbWritePtr += sizeof(rgbMACKey);
  419. // USER GATING: only consider if prompt structure specified
  420. if ( psPrompt )
  421. {
  422. if (psPrompt->cbSize != sizeof(SSCRYPTPROTECTDATA_PROMPTSTRUCT))
  423. {
  424. dwRet = ERROR_INVALID_PARAMETER;
  425. goto Ret;
  426. }
  427. if ((psPrompt->dwPromptFlags & ~(CRYPTPROTECT_PROMPT_ON_PROTECT |
  428. CRYPTPROTECT_PROMPT_ON_UNPROTECT |
  429. CRYPTPROTECT_PROMPT_STRONG |
  430. CRYPTPROTECT_PROMPT_REQUIRE_STRONG)) != 0)
  431. {
  432. dwRet = ERROR_INVALID_PARAMETER;
  433. goto Ret;
  434. }
  435. if ((psPrompt->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG) &&
  436. (pbOptionalPassword == NULL || cbOptionalPassword == 0)
  437. )
  438. {
  439. dwRet = ERROR_INVALID_PARAMETER;
  440. goto Ret;
  441. }
  442. // UI: only if requested by PROMPT_ON_PROTECT
  443. if ( psPrompt->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT )
  444. {
  445. if ( dwFlags & CRYPTPROTECT_UI_FORBIDDEN )
  446. {
  447. dwRet = ERROR_PASSWORD_RESTRICTION;
  448. goto Ret;
  449. }
  450. // UI handled outside service until SAS support added.
  451. dwProtectionFlags |= CRYPTPROTECT_PROMPT_ON_PROTECT;
  452. }
  453. if ( psPrompt->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT )
  454. dwProtectionFlags |= CRYPTPROTECT_PROMPT_ON_UNPROTECT;
  455. if ( psPrompt->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
  456. dwProtectionFlags |= CRYPTPROTECT_PROMPT_STRONG;
  457. if ( psPrompt->dwPromptFlags & CRYPTPROTECT_PROMPT_REQUIRE_STRONG )
  458. dwProtectionFlags |= CRYPTPROTECT_PROMPT_REQUIRE_STRONG;
  459. }
  460. // update stored protection flags in the stream
  461. *(DWORD UNALIGNED *)pStreamFlagPtr = dwProtectionFlags;
  462. // dansimon recommends that MAC be on encrypted data, such that the
  463. // MAC has no possibility of revealing info about the plaintext.
  464. cbEncrypted = cbIn;
  465. // then Encrypt pbIn
  466. if (!CryptEncrypt(
  467. hKey,
  468. NULL,
  469. TRUE,
  470. 0,
  471. pbCrypt,
  472. &cbEncrypted,
  473. cbCrypt))
  474. {
  475. dwRet = GetLastError();
  476. goto Ret;
  477. }
  478. // now cbCrypt is size of encrypted data
  479. cbCrypt = cbEncrypted;
  480. // Encrdata: len
  481. *(DWORD UNALIGNED *)pbWritePtr = cbCrypt;
  482. pbWritePtr += sizeof(DWORD);
  483. // Encrdata: val
  484. CopyMemory(pbWritePtr, pbCrypt, cbCrypt);
  485. pbWritePtr += cbCrypt;
  486. {
  487. // dansimon recommends that MAC be on encrypted data, such that the
  488. // MAC has no possibility of revealing info about the plaintext.
  489. // MAC from start to here
  490. if (!CryptHashData(
  491. hHash,
  492. *ppbOut,
  493. (DWORD)(pbWritePtr - *ppbOut),
  494. 0))
  495. {
  496. dwRet = GetLastError();
  497. goto Ret;
  498. }
  499. // cbMAC
  500. pbWritePtr += sizeof(DWORD); // skip cb write; retreive hash val first
  501. // MAC
  502. if (!CryptGetHashParam(
  503. hHash,
  504. HP_HASHVAL,
  505. pbWritePtr,
  506. &cbMACSize,
  507. 0))
  508. {
  509. dwRet = GetLastError();
  510. goto Ret;
  511. }
  512. // rewrite cbMAC before MAC
  513. *(DWORD UNALIGNED *)(pbWritePtr - sizeof(DWORD)) = cbMACSize;
  514. // make sure we didn't overstep
  515. SS_ASSERT(cbMACSize <= A_SHA_DIGEST_LEN);
  516. pbWritePtr += cbMACSize;
  517. }
  518. // assert allocation size was sufficient
  519. SS_ASSERT(*ppbOut + *pcbOut >= pbWritePtr);
  520. // reset output size
  521. *pcbOut = (DWORD)(pbWritePtr - *ppbOut);
  522. dwRet = ERROR_SUCCESS;
  523. Ret:
  524. if((dwProtectionFlags & CRYPTPROTECT_AUDIT) ||
  525. (ERROR_SUCCESS != dwRet))
  526. {
  527. WCHAR wszCryptoAlgs[2*MAX_STRING_ALGID_LENGTH + 2];
  528. DWORD i;
  529. i = AlgIDToString(wszCryptoAlgs, dwAlgID_Encr_Alg, dwAlgID_Encr_Alg_KeySize);
  530. wszCryptoAlgs[i++]= L',';
  531. wszCryptoAlgs[i++]= L' ';
  532. AlgIDToString(&wszCryptoAlgs[i], dwAlgID_MAC_Alg, dwAlgID_MAC_Alg_KeySize);
  533. CPSAudit(pServerContext->hToken,
  534. SE_AUDITID_DPAPI_PROTECT,
  535. wszMKGuidString, // Key Identifier
  536. szDataDescr, // Data Description
  537. dwProtectionFlags, // Protected Data Flags
  538. wszCryptoAlgs, // Protection Algorithms
  539. dwRet); // Failure Reason
  540. }
  541. RtlSecureZeroMemory(rgbPwdBuf, sizeof(rgbPwdBuf));
  542. RtlSecureZeroMemory(rgbEncrKey, sizeof(rgbEncrKey));
  543. if(pbMasterKey) {
  544. RtlSecureZeroMemory(pbMasterKey, cbMasterKey);
  545. SSFree(pbMasterKey);
  546. }
  547. if (hKey)
  548. CryptDestroyKey(hKey);
  549. if (hHash)
  550. CryptDestroyHash(hHash);
  551. if (pbCrypt)
  552. SSFree(pbCrypt);
  553. if (pbEncrSalt)
  554. SSFree(pbEncrSalt);
  555. D_DebugLog((DEB_TRACE_API, "SPCryptProtect returned 0x%x\n", dwRet));
  556. return dwRet;
  557. }
  558. DWORD
  559. WINAPI
  560. SPCryptUnprotect(
  561. PVOID pvContext, // server context
  562. PBYTE* ppbOut, // out ptxt data
  563. DWORD* pcbOut, // out ptxt cb
  564. PBYTE pbIn, // in encr data
  565. DWORD cbIn, // in encr cb
  566. LPWSTR* ppszDataDescr, // OPTIONAL
  567. PBYTE pbOptionalEntropy, // OPTIONAL
  568. DWORD cbOptionalEntropy,
  569. PSSCRYPTPROTECTDATA_PROMPTSTRUCT psPrompt, // OPTIONAL, prompting struct
  570. DWORD dwFlags,
  571. BYTE* pbOptionalPassword,
  572. DWORD cbOptionalPassword
  573. )
  574. {
  575. DWORD dwRet;
  576. PBYTE pbReadPtr = pbIn;
  577. LPWSTR szUser = NULL;
  578. GUID guidMK;
  579. WCHAR wszMKGuidString[MAX_GUID_SZ_CHARS];
  580. HCRYPTPROV hVerifyProv;
  581. HCRYPTKEY hKey = NULL;
  582. HCRYPTHASH hHash = NULL;
  583. BYTE rgbEncrKey[KEY_DERIVATION_BUFSIZE];
  584. BYTE rgbMACKey[KEY_DERIVATION_BUFSIZE];
  585. DWORD cbEncr;
  586. PBYTE pbEncrSalt = NULL;
  587. DWORD cbEncrSalt = 0;
  588. DWORD dwEncrAlgID = 0;
  589. DWORD dwEncrAlgKeySize = 0;
  590. DWORD dwMACAlgID = 0;
  591. DWORD dwMACAlgKeySize =0;
  592. DWORD cbEncrKeysize, cbMACKeysize;
  593. DWORD dwProtectionFlags = 0;
  594. BYTE rgbPwdBuf[A_SHA_DIGEST_LEN];
  595. DWORD cbDataDescr;
  596. LPWSTR szDataDescr = NULL;
  597. LPBYTE pbMasterKey = NULL;
  598. DWORD cbMasterKey = 0;
  599. DWORD cbPlaintext;
  600. #if DBG
  601. D_DebugLog((DEB_TRACE_API,"SPCryptUnprotect 0x%x called\n", pvContext));
  602. if(pvContext)
  603. {
  604. PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
  605. if(pServerContext->cbSize == sizeof(CRYPT_SERVER_CONTEXT))
  606. {
  607. D_DebugLog((DEB_TRACE_API, " pServerContext->hBinding:%d\n", pServerContext->hBinding));
  608. D_DebugLog((DEB_TRACE_API, " pServerContext->fOverrideToLocalSystem:%d\n", pServerContext->fOverrideToLocalSystem));
  609. D_DebugLog((DEB_TRACE_API, " pServerContext->fImpersonating:%d\n", pServerContext->fImpersonating));
  610. D_DebugLog((DEB_TRACE_API, " pServerContext->hToken:%d\n", pServerContext->hToken));
  611. D_DebugLog((DEB_TRACE_API, " pServerContext->szUserStorageArea:%ls\n", pServerContext->szUserStorageArea));
  612. D_DebugLog((DEB_TRACE_API, " pServerContext->WellKnownAccount:%d\n", pServerContext->WellKnownAccount));
  613. }
  614. }
  615. D_DebugLog((DEB_TRACE_API, " pbOptionalEntropy:0x%x\n", pbOptionalEntropy));
  616. D_DPAPIDumpHexData(DEB_TRACE_BUFFERS, " ", pbOptionalEntropy, cbOptionalEntropy);
  617. D_DebugLog((DEB_TRACE_API, " dwFlags:0x%x\n", dwFlags));
  618. D_DebugLog((DEB_TRACE_API, " pbOptionalPassword:0x%x\n", pbOptionalPassword));
  619. D_DPAPIDumpHexData(DEB_TRACE_BUFFERS, " ", pbOptionalPassword, cbOptionalPassword);
  620. #endif
  621. *ppbOut = NULL;
  622. *pcbOut = 0;
  623. ZeroMemory(&guidMK, sizeof(guidMK));
  624. ZeroMemory(rgbPwdBuf, sizeof(rgbPwdBuf));
  625. DWORD dwDefaultCryptProvType = 0;
  626. DWORD dwAlgID_Encr_Alg = 0;
  627. DWORD dwAlgID_Encr_Alg_KeySize = 0;
  628. DWORD dwAlgID_MAC_Alg = 0;
  629. DWORD dwAlgID_MAC_Alg_KeySize = 0;
  630. //
  631. // If audit is turned on and the following vars are not set with the values
  632. // passed in, then the following would appear in the audit,
  633. // "Unknown 0x0 - 0"
  634. //
  635. dwEncrAlgID = 0;
  636. dwEncrAlgKeySize = 0;
  637. dwMACAlgID = 0;
  638. dwMACAlgKeySize = 0;
  639. wszMKGuidString[0] = 0;
  640. GetDefaultAlgInfo(&dwDefaultCryptProvType,
  641. &dwAlgID_Encr_Alg,
  642. &dwAlgID_Encr_Alg_KeySize,
  643. &dwAlgID_MAC_Alg,
  644. &dwAlgID_MAC_Alg_KeySize);
  645. ////////////////////////////////////////////////////////////////////
  646. // FYI: Data format
  647. // ( Version | guidMKid | dwFlags |
  648. // cbDataDescr | szDataDescr |
  649. //
  650. // dwEncrAlgID | dwEncrAlgKeySize |
  651. // cbEncrKey | EncrKey |
  652. // cbEncrSalt | EncrSalt |
  653. //
  654. // dwMACAlgID | dwMACAlgKeySize |
  655. // cbMACKey | MACKey |
  656. //
  657. // cbEncrData | EncrData |
  658. // cbMAC | MAC )
  659. //
  660. // NOTE: entire buffer from ProvHeader through EncrData is included in MAC
  661. ////////////////////////////////////////////////////////////////////
  662. // Check for minimum input buffer size.
  663. if(cbIn < sizeof(DWORD) + // Version
  664. sizeof(GUID) + // guidMKid
  665. sizeof(DWORD) + // dwFlags
  666. sizeof(DWORD)) // cbDataDescr
  667. {
  668. dwRet = ERROR_INVALID_DATA;
  669. goto Ret;
  670. }
  671. // version check
  672. if (*(DWORD UNALIGNED *)pbReadPtr != MS_BASE_CRYPTPROTECT_VERSION)
  673. {
  674. dwRet = ERROR_INVALID_DATA;
  675. goto Ret;
  676. }
  677. pbReadPtr += sizeof(DWORD);
  678. cbIn -= sizeof(DWORD);
  679. // guidMKid
  680. CopyMemory(&guidMK, pbReadPtr, sizeof(GUID));
  681. pbReadPtr += sizeof(GUID);
  682. cbIn -= sizeof(GUID);
  683. MyGuidToStringW(&guidMK, wszMKGuidString);
  684. D_DebugLog((DEB_TRACE, "Master key GUID:%ls\n", wszMKGuidString));
  685. // dwFlags during protection
  686. dwProtectionFlags = *(DWORD UNALIGNED *)pbReadPtr;
  687. pbReadPtr += sizeof(DWORD);
  688. cbIn -= sizeof(DWORD);
  689. D_DebugLog((DEB_TRACE, "Protection flags:0x%x\n", dwProtectionFlags));
  690. //
  691. // evaluate original CryptProtectData dwFlags to determine if
  692. // CRYPT_LOCAL_MACHINE set.
  693. //
  694. if( dwProtectionFlags & CRYPTPROTECT_LOCAL_MACHINE ) {
  695. BOOL fOverrideToLocalSystem = TRUE;
  696. CPSOverrideToLocalSystem(
  697. pvContext,
  698. &fOverrideToLocalSystem,
  699. NULL // don't care what previous value was
  700. );
  701. }
  702. if((dwProtectionFlags ^ dwFlags) & CRYPTPROTECT_SYSTEM)
  703. {
  704. //
  705. // Attempted to use decrypt system data as a user, or user data
  706. // with the system flag
  707. dwRet = ERROR_INVALID_DATA;
  708. goto Ret;
  709. }
  710. // cbDataDescr
  711. cbDataDescr = *(DWORD UNALIGNED *)pbReadPtr;
  712. pbReadPtr += sizeof(DWORD);
  713. cbIn -= sizeof(DWORD);
  714. // Check for minimum input buffer size.
  715. if(cbIn < cbDataDescr + // szDataDescr
  716. sizeof(DWORD) + // dwEncrAlgID
  717. sizeof(DWORD) + // dwEncrAlgKeySize
  718. sizeof(DWORD)) // cbEncrKey
  719. {
  720. dwRet = ERROR_INVALID_DATA;
  721. goto Ret;
  722. }
  723. // szDataDescr
  724. szDataDescr = (LPWSTR)pbReadPtr;
  725. pbReadPtr += cbDataDescr;
  726. cbIn -= cbDataDescr;
  727. D_DebugLog((DEB_TRACE, "Description:%ls\n", szDataDescr));
  728. // dwEncrAlgID
  729. dwEncrAlgID = *(DWORD UNALIGNED *)pbReadPtr;
  730. pbReadPtr += sizeof(DWORD);
  731. cbIn -= sizeof(DWORD);
  732. // dwEncrAlgKeySize
  733. dwEncrAlgKeySize = *(DWORD UNALIGNED *)pbReadPtr;
  734. pbReadPtr += sizeof(DWORD);
  735. cbIn -= sizeof(DWORD);
  736. D_DebugLog((DEB_TRACE, "Encrypt alg:0x%x, Size:%d bits\n", dwEncrAlgID, dwEncrAlgKeySize));
  737. // cb Encr key
  738. cbEncrKeysize = *(DWORD UNALIGNED *)pbReadPtr;
  739. pbReadPtr += sizeof(DWORD);
  740. cbIn -= sizeof(DWORD);
  741. if (cbEncrKeysize > sizeof(rgbEncrKey))
  742. {
  743. dwRet = ERROR_INVALID_DATA;
  744. goto Ret;
  745. }
  746. // Check for minimum input buffer size.
  747. if(cbIn < cbEncrKeysize + // EncrKey
  748. sizeof(DWORD)) // cbEncrSalt
  749. {
  750. dwRet = ERROR_INVALID_DATA;
  751. goto Ret;
  752. }
  753. // Encr key
  754. CopyMemory(rgbEncrKey, pbReadPtr, cbEncrKeysize);
  755. pbReadPtr += cbEncrKeysize;
  756. cbIn -= cbEncrKeysize;
  757. // cb Encr salt
  758. cbEncrSalt = *(DWORD UNALIGNED *)pbReadPtr;
  759. pbReadPtr += sizeof(DWORD);
  760. cbIn -= sizeof(DWORD);
  761. // Check for minimum input buffer size.
  762. if(cbIn < cbEncrSalt + // EncrSalt
  763. sizeof(DWORD) + // dwMACAlgID
  764. sizeof(DWORD) + // dwMACAlgKeySize
  765. sizeof(DWORD)) // cbMACKey
  766. {
  767. dwRet = ERROR_INVALID_DATA;
  768. goto Ret;
  769. }
  770. // Encr salt
  771. pbEncrSalt = (PBYTE)SSAlloc(cbEncrSalt);
  772. if( pbEncrSalt == NULL ) {
  773. dwRet = ERROR_OUTOFMEMORY;
  774. goto Ret;
  775. }
  776. CopyMemory(pbEncrSalt, pbReadPtr, cbEncrSalt);
  777. pbReadPtr += cbEncrSalt;
  778. cbIn -= cbEncrSalt;
  779. // dwMACAlgID
  780. dwMACAlgID = *(DWORD UNALIGNED *)pbReadPtr;
  781. pbReadPtr += sizeof(DWORD);
  782. cbIn -= sizeof(DWORD);
  783. // dwMACAlgKeySize
  784. dwMACAlgKeySize = *(DWORD UNALIGNED *)pbReadPtr;
  785. pbReadPtr += sizeof(DWORD);
  786. cbIn -= sizeof(DWORD);
  787. D_DebugLog((DEB_TRACE, "MAC alg:0x%x, Size:%d bits\n", dwMACAlgID, dwMACAlgKeySize));
  788. // MAC key size
  789. cbMACKeysize = *(DWORD UNALIGNED *)pbReadPtr;
  790. pbReadPtr += sizeof(DWORD);
  791. cbIn -= sizeof(DWORD);
  792. if (cbMACKeysize > sizeof(rgbMACKey))
  793. {
  794. dwRet = ERROR_INVALID_DATA;
  795. goto Ret;
  796. }
  797. // Check for minimum input buffer size.
  798. if(cbIn < cbMACKeysize) // cbMACKey
  799. {
  800. dwRet = ERROR_INVALID_DATA;
  801. goto Ret;
  802. }
  803. // MAC key
  804. CopyMemory(rgbMACKey, pbReadPtr, cbMACKeysize);
  805. pbReadPtr += cbMACKeysize;
  806. cbIn -= cbMACKeysize;
  807. if (NULL == (hVerifyProv =
  808. GetCryptProviderHandle(
  809. dwDefaultCryptProvType,
  810. dwEncrAlgID, &dwEncrAlgKeySize,
  811. dwMACAlgID, &dwMACAlgKeySize)) )
  812. {
  813. dwRet = (DWORD)GetLastError();
  814. goto Ret;
  815. }
  816. // USER GATING: when PROMPT_ON_UNPROTECT specified during CryptProtectData
  817. if ( CRYPTPROTECT_PROMPT_ON_UNPROTECT & dwProtectionFlags )
  818. {
  819. if (dwFlags & CRYPTPROTECT_UI_FORBIDDEN)
  820. {
  821. dwRet = ERROR_PASSWORD_RESTRICTION;
  822. goto Ret;
  823. }
  824. if (psPrompt == NULL)
  825. {
  826. dwRet = ERROR_INVALID_PARAMETER;
  827. goto Ret;
  828. }
  829. if (psPrompt->cbSize != sizeof(SSCRYPTPROTECTDATA_PROMPTSTRUCT))
  830. {
  831. dwRet = ERROR_INVALID_PARAMETER;
  832. goto Ret;
  833. }
  834. if ((psPrompt->dwPromptFlags & ~(CRYPTPROTECT_PROMPT_ON_PROTECT |
  835. CRYPTPROTECT_PROMPT_ON_UNPROTECT |
  836. CRYPTPROTECT_PROMPT_STRONG |
  837. CRYPTPROTECT_PROMPT_REQUIRE_STRONG) ) != 0)
  838. {
  839. dwRet = ERROR_INVALID_PARAMETER;
  840. goto Ret;
  841. }
  842. // UI handled outside service until SAS support added.
  843. }
  844. dwRet = GetSpecifiedMasterKey(
  845. pvContext,
  846. &guidMK,
  847. &pbMasterKey,
  848. &cbMasterKey,
  849. TRUE // we do know what master key we want to use
  850. );
  851. if(dwRet != ERROR_SUCCESS)
  852. {
  853. DWORD dwAccount = 0;
  854. DebugLog((DEB_ERROR, "Unable to get specified master key:%ls, error 0x%x\n",
  855. wszMKGuidString, dwRet));
  856. //
  857. // Is this call from one of the service accounts? If so, then attempt to
  858. // obtain the master key using the legacy method.
  859. //
  860. CPSQueryWellKnownAccount(pvContext, &dwAccount);
  861. if((dwAccount == DP_ACCOUNT_LOCAL_SERVICE) ||
  862. (dwAccount == DP_ACCOUNT_NETWORK_SERVICE))
  863. {
  864. DebugLog((DEB_ERROR, "Attempt service account legacy method.\n"));
  865. CPSSetWellKnownAccount(pvContext, 0);
  866. dwRet = GetSpecifiedMasterKey(
  867. pvContext,
  868. &guidMK,
  869. &pbMasterKey,
  870. &cbMasterKey,
  871. TRUE // we do know what master key we want to use
  872. );
  873. CPSSetWellKnownAccount(pvContext, dwAccount);
  874. if(dwRet != ERROR_SUCCESS)
  875. {
  876. DebugLog((DEB_ERROR, "Still unable to get specified master key:%ls, error 0x%x\n",
  877. wszMKGuidString, dwRet));
  878. goto Ret;
  879. }
  880. else
  881. {
  882. DebugLog((DEB_ERROR, "Master key successfully obtained using legacy method.\n"));
  883. }
  884. }
  885. else
  886. {
  887. goto Ret;
  888. }
  889. }
  890. //
  891. // hash pbMasterKey to get rgbPwdBuf
  892. //
  893. FMyPrimitiveSHA( pbMasterKey, cbMasterKey, rgbPwdBuf);
  894. // derive encr key
  895. {
  896. if (!FMyPrimitiveCryptHMAC(
  897. rgbPwdBuf,
  898. sizeof(rgbPwdBuf),
  899. rgbEncrKey,
  900. cbEncrKeysize,
  901. hVerifyProv,
  902. ALGID_DERIVEKEY_HASH,
  903. &hHash))
  904. {
  905. dwRet = GetLastError();
  906. goto Ret;
  907. }
  908. // add password if exists
  909. if (NULL != pbOptionalEntropy)
  910. {
  911. if (!CryptHashData(
  912. hHash,
  913. pbOptionalEntropy,
  914. cbOptionalEntropy,
  915. 0))
  916. {
  917. dwRet = GetLastError();
  918. goto Ret;
  919. }
  920. }
  921. // add prompted UI based password if exists.
  922. // will eventually come from SAS
  923. //
  924. if ( NULL != pbOptionalPassword && cbOptionalPassword )
  925. {
  926. if (!CryptHashData(
  927. hHash,
  928. pbOptionalPassword,
  929. cbOptionalPassword,
  930. 0))
  931. {
  932. dwRet = GetLastError();
  933. goto Ret;
  934. }
  935. }
  936. if (!CryptDeriveKey(
  937. hVerifyProv,
  938. dwEncrAlgID,
  939. hHash,
  940. ((dwEncrAlgKeySize << 16) | CRYPT_CREATE_SALT),
  941. &hKey))
  942. {
  943. dwRet = GetLastError();
  944. goto Ret;
  945. }
  946. CryptDestroyHash(hHash);
  947. hHash = 0;
  948. // USEC -- (US Export Controls)
  949. if (ERROR_SUCCESS != (dwRet =
  950. SetSaltForExportControl(
  951. hKey,
  952. pbEncrSalt,
  953. cbEncrSalt)) )
  954. goto Ret;
  955. }
  956. // derive MAC key
  957. {
  958. if (!FMyPrimitiveCryptHMAC(
  959. rgbPwdBuf,
  960. sizeof(rgbPwdBuf),
  961. rgbMACKey,
  962. cbMACKeysize,
  963. hVerifyProv,
  964. dwMACAlgID,
  965. &hHash))
  966. {
  967. dwRet = GetLastError();
  968. goto Ret;
  969. }
  970. // add password if exists
  971. if (NULL != pbOptionalEntropy)
  972. {
  973. if (!CryptHashData(
  974. hHash,
  975. pbOptionalEntropy,
  976. cbOptionalEntropy,
  977. 0))
  978. {
  979. dwRet = GetLastError();
  980. goto Ret;
  981. }
  982. }
  983. // add prompted UI based password if exists.
  984. // will eventually come from SAS
  985. //
  986. if ( NULL != pbOptionalPassword && cbOptionalPassword )
  987. {
  988. if (!CryptHashData(
  989. hHash,
  990. pbOptionalPassword,
  991. cbOptionalPassword,
  992. 0))
  993. {
  994. dwRet = GetLastError();
  995. goto Ret;
  996. }
  997. }
  998. // USEC -- (US Export Controls)
  999. // does not apply -- use strong key
  1000. }
  1001. // Check for minimum input buffer size.
  1002. if(cbIn < sizeof(DWORD)) // cbEncrData
  1003. {
  1004. dwRet = ERROR_INVALID_DATA;
  1005. goto Ret;
  1006. }
  1007. // get encr size
  1008. cbEncr = *(DWORD UNALIGNED *)pbReadPtr;
  1009. pbReadPtr += sizeof(DWORD);
  1010. cbIn -= sizeof(DWORD);
  1011. // Check for minimum input buffer size.
  1012. if(cbIn < cbEncr + // EncrData
  1013. sizeof(DWORD) + // cbMAC
  1014. A_SHA_DIGEST_LEN) // MAC
  1015. {
  1016. dwRet = ERROR_INVALID_DATA;
  1017. goto Ret;
  1018. }
  1019. // dansimon recommends that MAC be on encrypted data, such that the
  1020. // MAC has no possibility of revealing info about the plaintext.
  1021. // MAC is from start thru encrypted data
  1022. if (!CryptHashData(
  1023. hHash,
  1024. pbIn,
  1025. (DWORD) ((pbReadPtr - pbIn) + cbEncr),
  1026. 0))
  1027. {
  1028. dwRet = GetLastError();
  1029. goto Ret;
  1030. }
  1031. cbPlaintext = cbEncr;
  1032. if ((dwProtectionFlags & CRYPTPROTECT_NO_ENCRYPTION) == 0)
  1033. {
  1034. if (!CryptDecrypt(
  1035. hKey,
  1036. NULL, // hHash mattt 9/12/97
  1037. TRUE,
  1038. 0,
  1039. pbReadPtr,
  1040. &cbPlaintext))
  1041. {
  1042. dwRet = GetLastError();
  1043. if(NTE_BAD_DATA == dwRet)
  1044. {
  1045. dwRet = ERROR_INVALID_DATA;
  1046. }
  1047. goto Ret;
  1048. }
  1049. }
  1050. {
  1051. BYTE rgbComputedMAC[A_SHA_DIGEST_LEN];
  1052. // use MACPtr to skip past decr data,
  1053. PBYTE pbMACPtr = pbReadPtr + cbEncr;
  1054. DWORD cbMACsize = A_SHA_DIGEST_LEN;
  1055. if (!CryptGetHashParam(
  1056. hHash,
  1057. HP_HASHVAL,
  1058. rgbComputedMAC,
  1059. &cbMACsize,
  1060. 0))
  1061. {
  1062. dwRet = GetLastError();
  1063. goto Ret;
  1064. }
  1065. // chk MAC size
  1066. if (*(DWORD UNALIGNED *)pbMACPtr != cbMACsize)
  1067. {
  1068. dwRet = ERROR_INVALID_DATA;
  1069. goto Ret;
  1070. }
  1071. pbMACPtr += sizeof(DWORD);
  1072. // chk MAC
  1073. if (0 != memcmp(pbMACPtr, rgbComputedMAC, cbMACsize) )
  1074. {
  1075. dwRet = ERROR_INVALID_DATA;
  1076. goto Ret;
  1077. }
  1078. }
  1079. //
  1080. // Write data out, encrypted so that rpc doesn't leave copies
  1081. // laying around in plaintext.
  1082. //
  1083. *pcbOut = cbPlaintext;
  1084. if((dwFlags & CRYPTPROTECT_IN_PROCESS) == 0)
  1085. {
  1086. DWORD cbPadding;
  1087. NTSTATUS Status;
  1088. cbPadding = RTL_ENCRYPT_MEMORY_SIZE - (*pcbOut) % RTL_ENCRYPT_MEMORY_SIZE;
  1089. if(cbPadding == 0)
  1090. {
  1091. cbPadding += RTL_ENCRYPT_MEMORY_SIZE;
  1092. }
  1093. *ppbOut = (PBYTE)SSAlloc(*pcbOut + cbPadding);
  1094. if(*ppbOut == NULL)
  1095. {
  1096. *pcbOut = 0;
  1097. dwRet = ERROR_OUTOFMEMORY;
  1098. goto Ret;
  1099. }
  1100. CopyMemory(*ppbOut, pbReadPtr, *pcbOut);
  1101. FillMemory((*ppbOut) + (*pcbOut), cbPadding, (BYTE)cbPadding);
  1102. *pcbOut += cbPadding;
  1103. dwRet = RpcImpersonateClient(((PCRYPT_SERVER_CONTEXT)pvContext)->hBinding);
  1104. if( dwRet != ERROR_SUCCESS )
  1105. {
  1106. SSFree(*ppbOut);
  1107. *ppbOut = NULL;
  1108. *pcbOut = 0;
  1109. goto Ret;
  1110. }
  1111. Status = RtlEncryptMemory(*ppbOut,
  1112. *pcbOut,
  1113. RTL_ENCRYPT_OPTION_SAME_LOGON);
  1114. RevertToSelf();
  1115. if(!NT_SUCCESS(Status))
  1116. {
  1117. SSFree(*ppbOut);
  1118. *ppbOut = NULL;
  1119. *pcbOut = 0;
  1120. dwRet = RtlNtStatusToDosError(Status);
  1121. goto Ret;
  1122. }
  1123. }
  1124. else
  1125. {
  1126. // We're in-process, so don't bother encrypting output buffer.
  1127. *ppbOut = (PBYTE)SSAlloc(*pcbOut);
  1128. if(*ppbOut == NULL)
  1129. {
  1130. *pcbOut = 0;
  1131. dwRet = ERROR_OUTOFMEMORY;
  1132. goto Ret;
  1133. }
  1134. CopyMemory(*ppbOut, pbReadPtr, *pcbOut);
  1135. }
  1136. // optional: caller may want data descr
  1137. if (ppszDataDescr)
  1138. {
  1139. *ppszDataDescr = (LPWSTR)SSAlloc(cbDataDescr);
  1140. if(*ppszDataDescr == NULL)
  1141. {
  1142. SSFree(*ppbOut);
  1143. *ppbOut = NULL;
  1144. *pcbOut = 0;
  1145. dwRet = ERROR_OUTOFMEMORY;
  1146. goto Ret;
  1147. }
  1148. CopyMemory(*ppszDataDescr, szDataDescr, cbDataDescr);
  1149. }
  1150. dwRet = ERROR_SUCCESS;
  1151. if(dwFlags & CRYPTPROTECT_VERIFY_PROTECTION )
  1152. {
  1153. HCRYPTPROV hTestProv = GetCryptProviderHandle( dwDefaultCryptProvType,
  1154. dwAlgID_Encr_Alg, &dwAlgID_Encr_Alg_KeySize,
  1155. dwAlgID_MAC_Alg, &dwAlgID_MAC_Alg_KeySize);
  1156. if(hTestProv)
  1157. {
  1158. // Verify encryption strengths
  1159. // Never downgrade encryption strength, just check if we need
  1160. // to upgrade
  1161. if((dwAlgID_Encr_Alg_KeySize > dwEncrAlgKeySize) ||
  1162. (dwAlgID_MAC_Alg_KeySize > dwMACAlgKeySize))
  1163. {
  1164. dwRet = CRYPT_I_NEW_PROTECTION_REQUIRED;
  1165. }
  1166. }
  1167. }
  1168. Ret:
  1169. if((dwProtectionFlags & CRYPTPROTECT_AUDIT) ||
  1170. (ERROR_SUCCESS != dwRet))
  1171. {
  1172. DWORD dwAuditRet = dwRet;
  1173. WCHAR wszCryptoAlgs[2*MAX_STRING_ALGID_LENGTH + 2];
  1174. DWORD i;
  1175. PCRYPT_SERVER_CONTEXT pServerContext = (PCRYPT_SERVER_CONTEXT)pvContext;
  1176. i = AlgIDToString(wszCryptoAlgs, dwEncrAlgID, dwEncrAlgKeySize);
  1177. wszCryptoAlgs[i++]= L',';
  1178. wszCryptoAlgs[i++]= L' ';
  1179. AlgIDToString(&wszCryptoAlgs[i], dwMACAlgID, dwMACAlgKeySize);
  1180. if(CRYPT_I_NEW_PROTECTION_REQUIRED == dwAuditRet)
  1181. {
  1182. dwAuditRet = ERROR_SUCCESS;
  1183. }
  1184. CPSAudit(pServerContext->hToken,
  1185. SE_AUDITID_DPAPI_UNPROTECT,
  1186. wszMKGuidString, // Key Identifier
  1187. szDataDescr, // Data Description
  1188. 0, // Protected Data Flags
  1189. wszCryptoAlgs, // Protection Algorithms
  1190. dwAuditRet); // Failure Reason
  1191. }
  1192. RtlSecureZeroMemory(rgbPwdBuf, sizeof(rgbPwdBuf));
  1193. RtlSecureZeroMemory(rgbEncrKey, sizeof(rgbEncrKey));
  1194. if(pbMasterKey) {
  1195. RtlSecureZeroMemory(pbMasterKey, cbMasterKey);
  1196. SSFree(pbMasterKey);
  1197. }
  1198. if (hKey)
  1199. CryptDestroyKey(hKey);
  1200. if (hHash)
  1201. CryptDestroyHash(hHash);
  1202. if (pbEncrSalt)
  1203. SSFree(pbEncrSalt);
  1204. D_DebugLog((DEB_TRACE_API, "SPCryptUnprotect returned 0x%x\n", dwRet));
  1205. return dwRet;
  1206. }