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.

1268 lines
33 KiB

  1. /*
  2. File: Secure.cpp
  3. Title: Cryptographic Funcs for Protected Storage
  4. Author: Matt Thomlinson
  5. Date: 11/18/96
  6. Builds up usable cryptographic functionality and exports for
  7. usage by storage module. Since CryptoAPI base provider may call
  8. us, we can't use CryptXXX primitives (circular dependencies
  9. may result). Instead, we build up functions from SHA-1
  10. hash and DES-CBC primitives to Encrypt/Decrypt key blocks, MAC
  11. items, and check password confirmation blocks.
  12. **Master Key Usage**
  13. Encryption is done in a strange way to ease password management
  14. headaches.
  15. // derive a key from the user password, and the password-unique salt
  16. // Salt foils certain (dictionary) attacks on the password
  17. // PWSalt is PASSWORD_SALT_LEN
  18. // UserPW is SHA-1 hash of password excluding zt
  19. // DerivedKey1 is 56-bit DES key
  20. DerivedKey1 = DeriveKey(UserPW | PWSalt);
  21. // using the derived key, decrypt the encrypted master keys
  22. // encrypted master keys are E(master key bits | pwd confirm bits)
  23. MasterBits | PwdConfirmBits = Decrypt( (MasterKey|PwdConfirmKey), DerivedKey1);
  24. // Now we have recovered keys
  25. // MasterKey, PwdConfirmKey are 56-bit DES keys
  26. MasterKey
  27. PwdConfirmKey
  28. // check to make sure this is correct MasterKey by MACing
  29. // the global confirmation string and checking against stored MAC
  30. PwdConfirmMAC = HMAC(g_ConfirmBuf, PwdConfirmKey)
  31. if (0 != memcmp(PwdConfirmMac, rgbStoredMAC, 20)
  32. // wrong pwd!!
  33. We've derived a master key that we can create reproducibly and
  34. be changed without touching every item encrypted by it. That is,
  35. If the user changes the password, we simply need to keep the
  36. MasterBits constant and Encrypt with the new DerivedKey1 to find
  37. the EncryptedMasterBits to write to disk. In this way, we can change
  38. the password without changing the (exceedingly long) master key.
  39. We also have an immediate indication of whether or not the password
  40. used to decrypt the master key is correct.
  41. **Encrypting/MACing a single item**
  42. // assume we have 56-bit DES MasterKey from above
  43. // use master key to decrypt the encrypted item keyblock
  44. // key block holds two keys: Item key and MAC key
  45. ItemKeyBits | MACKeyBits = Decrypt( (ItemKey|MACKey), MasterKey);
  46. // Recovered two DES keys
  47. // ItemKey is 56 bits
  48. // MACKey is 56 bits
  49. ItemKey
  50. MACKey
  51. // MAC the item
  52. ItemMAC = HMAC(pbItemData, MACKey);
  53. // Tack the items' MAC onto the item, and encrypt
  54. EncryptedItem = ENCRYPTED_DATA_VER | Encrypt(pbItemData | ItemMAC, ItemKey);
  55. We've succeeded in encrypting and MACing an item using the single DES
  56. MasterKey from above. The item is both privacy and integrity protected.
  57. **Derive Key**
  58. **HMAC**
  59. Above we've skimmed over the definition of key derivation and HMAC.
  60. See primitiv.cpp for a description of how this primitive
  61. functionality is implemented.
  62. // Format of the encrypted item data stream:
  63. // version | size(keyblk) | keyblk | size(encryptedblk) | Encrypted{ size(data) | data | size(MAC) | MAC}
  64. */
  65. #include <pch.cpp>
  66. #pragma hdrstop
  67. #include "storage.h"
  68. // from des.h
  69. #define DES_KEYLEN 8
  70. // MAC buffer we use to check correct decryption
  71. static BYTE g_rgbConfirmBuf[] = "(c) 1996 Microsoft, All Rights Reserved";
  72. // Data Version
  73. //
  74. // #define ENCRYPTED_DATA_VER 0x01
  75. // 6-12-97: version incremented. Previous versions
  76. // should use MyOldPrimitiveHMAC -- different MAC attached to items
  77. #define ENCRYPTED_DATA_VER 0x02
  78. // MK Version
  79. //
  80. // #define ENCRYPTED_MASTERKEY_VER 0x01
  81. // 6-12-97: version incremented. Previous versions
  82. // should use MyOldPrimitiveHMAC -- different MAC attached to items
  83. // #define ENCRYPTED_MASTERKEY_VER 0x02
  84. // 5-3-99: version incremented. Previous versions
  85. // should use sizeof(rgbpwd)
  86. #define ENCRYPTED_MASTERKEY_VER 0x03
  87. // given pwd, salt, and ptr to master key buffer,
  88. // decrypts and checks MAC on master key
  89. BOOL FMyDecryptMK(
  90. BYTE rgbSalt[],
  91. DWORD cbSalt,
  92. BYTE rgbPwd[A_SHA_DIGEST_LEN],
  93. BYTE rgbConfirm[A_SHA_DIGEST_LEN],
  94. PBYTE* ppbMK,
  95. DWORD* pcbMK)
  96. {
  97. BOOL fResetSecurityState;
  98. return FMyDecryptMKEx(
  99. rgbSalt,
  100. cbSalt,
  101. rgbPwd,
  102. rgbConfirm,
  103. ppbMK,
  104. pcbMK,
  105. &fResetSecurityState
  106. );
  107. }
  108. BOOL
  109. FMyDecryptMKEx(
  110. BYTE rgbSalt[],
  111. DWORD cbSalt,
  112. BYTE rgbPwd[A_SHA_DIGEST_LEN],
  113. BYTE rgbConfirm[A_SHA_DIGEST_LEN],
  114. PBYTE* ppbMK,
  115. DWORD* pcbMK,
  116. BOOL *pfResetSecurityState
  117. )
  118. {
  119. BOOL fRet = FALSE;
  120. DESKEY sDerivedKey1;
  121. DESKEY sConfirmKey;
  122. DWORD dwMKVersion;
  123. PBYTE pTemp;
  124. BYTE rgbHMACResult[A_SHA_DIGEST_LEN];
  125. // version check!!
  126. dwMKVersion = *(DWORD*)*ppbMK;
  127. if (ENCRYPTED_MASTERKEY_VER < dwMKVersion)
  128. goto Ret;
  129. if( dwMKVersion < 0x03 ) {
  130. *pfResetSecurityState = TRUE;
  131. // DK1 = DeriveKey(SHA(pw), Salt)
  132. if (!FMyPrimitiveDeriveKey(
  133. rgbSalt,
  134. cbSalt,
  135. rgbPwd,
  136. sizeof(rgbPwd),
  137. &sDerivedKey1))
  138. goto Ret;
  139. } else {
  140. *pfResetSecurityState = FALSE;
  141. // DK1 = DeriveKey(SHA(pw), Salt)
  142. if (!FMyPrimitiveDeriveKey(
  143. rgbSalt,
  144. cbSalt,
  145. rgbPwd,
  146. A_SHA_DIGEST_LEN,
  147. &sDerivedKey1))
  148. goto Ret;
  149. }
  150. *pcbMK -= sizeof(DWORD);
  151. if (!(*pcbMK)) {
  152. // Paranoid
  153. goto Ret;
  154. }
  155. MoveMemory(*ppbMK, *ppbMK + sizeof(DWORD), *pcbMK); // shift data left 1 dw, splat version
  156. pTemp = (PBYTE)SSReAlloc(*ppbMK, *pcbMK);
  157. if (pTemp == NULL) { // check allocation
  158. goto Ret;
  159. }
  160. *ppbMK = pTemp;
  161. // Decrypt MK bits
  162. if (!FMyPrimitiveDESDecrypt(
  163. *ppbMK,
  164. pcbMK,
  165. sDerivedKey1))
  166. goto Ret;
  167. // assumes is at least 2*DES_KEYLEN bytes
  168. if (*pcbMK != 2*DES_KEYLEN)
  169. goto Ret;
  170. if (!FMyMakeDESKey(
  171. &sConfirmKey, // out
  172. *ppbMK + DES_KEYLEN)) // in
  173. goto Ret;
  174. if (dwMKVersion == 0x01)
  175. {
  176. // items created with tag 0x01 used different HMACing algorithm
  177. if (!FMyOldPrimitiveHMAC(
  178. sConfirmKey,
  179. g_rgbConfirmBuf,
  180. sizeof(g_rgbConfirmBuf),
  181. rgbHMACResult))
  182. goto Ret;
  183. }
  184. else
  185. {
  186. if (!FMyPrimitiveHMAC(
  187. sConfirmKey,
  188. g_rgbConfirmBuf,
  189. sizeof(g_rgbConfirmBuf),
  190. rgbHMACResult))
  191. goto Ret;
  192. }
  193. if (0 != memcmp(rgbHMACResult, rgbConfirm, A_SHA_DIGEST_LEN))
  194. goto Ret;
  195. fRet = TRUE;
  196. Ret:
  197. return fRet;
  198. }
  199. // retrieve key block and derive Item/MAC keys using MK
  200. BOOL FMyDecryptKeyBlock(
  201. LPCWSTR szUser,
  202. LPCWSTR szMasterKey,
  203. BYTE rgbPwd[A_SHA_DIGEST_LEN],
  204. PBYTE pbKeyBlock,
  205. DWORD cbKeyBlock,
  206. DESKEY* psItemKey,
  207. DESKEY* psMacKey)
  208. {
  209. BOOL fRet = FALSE;
  210. DESKEY sMK;
  211. BYTE rgbSalt[PASSWORD_SALT_LEN];
  212. BYTE rgbConfirm[A_SHA_DIGEST_LEN];
  213. PBYTE pbMK = NULL;
  214. DWORD cbMK;
  215. if (!FBPGetSecurityState(
  216. szUser,
  217. szMasterKey,
  218. rgbSalt,
  219. sizeof(rgbSalt),
  220. rgbConfirm,
  221. sizeof(rgbConfirm),
  222. &pbMK,
  223. &cbMK))
  224. return FALSE;
  225. // unwrap master key
  226. if (!FMyDecryptMK(
  227. rgbSalt,
  228. sizeof(rgbSalt),
  229. rgbPwd,
  230. rgbConfirm,
  231. &pbMK,
  232. &cbMK
  233. ))
  234. goto Ret;
  235. // assumes pbMK is at least 2*DES_KEYLEN bytes
  236. if (cbMK != 2*DES_KEYLEN)
  237. goto Ret;
  238. if (!FMyMakeDESKey(
  239. &sMK, // out
  240. pbMK)) // in
  241. goto Ret;
  242. // use MK to decrypt key block
  243. if (!FMyPrimitiveDESDecrypt(
  244. pbKeyBlock,
  245. &cbKeyBlock,
  246. sMK))
  247. goto Ret;
  248. // fill in ItemKey, MacKey from decrypted key block
  249. if (cbKeyBlock != 2*DES_KEYLEN)
  250. goto Ret;
  251. // assumes pbKeyBlock is at least 2*DES_KEYLEN bytes
  252. if (!FMyMakeDESKey(
  253. psItemKey, // out
  254. pbKeyBlock)) // in
  255. goto Ret;
  256. if (!FMyMakeDESKey(
  257. psMacKey, // out
  258. pbKeyBlock + DES_KEYLEN)) // in
  259. goto Ret;
  260. fRet = TRUE;
  261. Ret:
  262. if(pbMK != NULL) {
  263. RtlSecureZeroMemory(pbMK, cbMK); // sfield: zero it
  264. SSFree(pbMK); // sfield: fix illusive memory leak
  265. }
  266. return fRet;
  267. }
  268. // given encrypted data and password, decrypt and check MAC on data
  269. BOOL FProvDecryptData(
  270. LPCWSTR szUser, // in
  271. LPCWSTR szMasterKey, // in
  272. BYTE rgbPwd[A_SHA_DIGEST_LEN], // in
  273. PBYTE* ppbMyData, // in out
  274. DWORD* pcbMyData) // in out
  275. {
  276. BOOL fRet = FALSE;
  277. DESKEY sItemKey;
  278. DESKEY sMacKey;
  279. BYTE rgbHMAC[A_SHA_DIGEST_LEN];
  280. DWORD dwDataVer;
  281. PBYTE pTemp;
  282. // pointers to teardown stream
  283. PBYTE pbCurPtr = *ppbMyData;
  284. PBYTE pbSecureData;
  285. DWORD cbSecureData;
  286. PBYTE pbInlineKeyBlock;
  287. DWORD cbInlineKeyBlock;
  288. PBYTE pbDecrypted;
  289. DWORD cbDecrypted;
  290. PBYTE pbMAC;
  291. DWORD cbMAC;
  292. // ENCRYPTED ITEM DATA FORMAT:
  293. // version | size(keyblk) | keyblk | size(encryptedblk) | Encrypted{ size(data) | data | size(MAC) | MAC}
  294. // version check -- only handle V1 data for now
  295. dwDataVer = *(DWORD*)pbCurPtr;
  296. if (ENCRYPTED_DATA_VER < dwDataVer)
  297. goto Ret;
  298. pbCurPtr += sizeof(DWORD);
  299. // pointers to key block
  300. cbInlineKeyBlock = *(DWORD UNALIGNED *)pbCurPtr; // keyblock size
  301. pbCurPtr += sizeof(DWORD); // fwd past size
  302. pbInlineKeyBlock = pbCurPtr; // points to key block
  303. pbCurPtr += cbInlineKeyBlock; // fwd past data
  304. // pointers to secure data
  305. cbSecureData = *(DWORD UNALIGNED *)pbCurPtr; // secure data size member
  306. pbCurPtr += sizeof(DWORD); // fwd past size
  307. pbSecureData = pbCurPtr; // points to secure data
  308. // retrieve key block using MK, etc
  309. if (!FMyDecryptKeyBlock(
  310. szUser,
  311. szMasterKey,
  312. rgbPwd,
  313. pbInlineKeyBlock,
  314. cbInlineKeyBlock,
  315. &sItemKey,
  316. &sMacKey))
  317. goto Ret;
  318. // keys derived, now recover data inplace
  319. if (!FMyPrimitiveDESDecrypt(
  320. pbSecureData,
  321. &cbSecureData,
  322. sItemKey))
  323. goto Ret;
  324. cbDecrypted = *(DWORD UNALIGNED *)pbCurPtr; // plaintext size
  325. pbCurPtr += sizeof(DWORD); // fwd past size
  326. pbDecrypted = pbCurPtr; // points to plaintext
  327. pbCurPtr += cbDecrypted; // fwd past data
  328. // pointers to HMAC
  329. cbMAC = *(DWORD UNALIGNED *)pbCurPtr; // MAC size member
  330. pbCurPtr += sizeof(DWORD); // fwd past size
  331. pbMAC = pbCurPtr; // points to MAC
  332. pbCurPtr += cbMAC; // fwd past data
  333. if (A_SHA_DIGEST_LEN != cbMAC) // verify HMAC size member
  334. goto Ret;
  335. // chk MAC
  336. // Compute HMAC over plaintext data
  337. if (dwDataVer == 0x01)
  338. {
  339. // version 0x1 used different HMAC code
  340. if (!FMyOldPrimitiveHMAC(
  341. sMacKey,
  342. pbDecrypted,
  343. cbDecrypted,
  344. rgbHMAC))
  345. goto Ret;
  346. }
  347. else
  348. {
  349. if (!FMyPrimitiveHMAC(
  350. sMacKey,
  351. pbDecrypted,
  352. cbDecrypted,
  353. rgbHMAC))
  354. goto Ret;
  355. }
  356. // now compare against HMAC in tail of msg
  357. if (0 != memcmp(pbMAC, rgbHMAC, A_SHA_DIGEST_LEN))
  358. goto Ret;
  359. // if everything went well, return secure data (shift to far left, realloc)
  360. MoveMemory(*ppbMyData, pbDecrypted, cbDecrypted);
  361. pTemp = (PBYTE)SSReAlloc(*ppbMyData, cbDecrypted);
  362. if (pTemp == NULL) // check allocation, Caller will free *ppbMyData
  363. goto Ret;
  364. *ppbMyData = pTemp;
  365. *pcbMyData = cbDecrypted;
  366. fRet = TRUE;
  367. Ret:
  368. // TODO free ppbMyData on failure?
  369. return fRet;
  370. }
  371. // given pwd, salt, and Master Key buffer, MACs and Encrypts Master Key buffer
  372. BOOL FMyEncryptMK(
  373. BYTE rgbSalt[],
  374. DWORD cbSalt,
  375. BYTE rgbPwd[A_SHA_DIGEST_LEN],
  376. BYTE rgbConfirm[A_SHA_DIGEST_LEN],
  377. PBYTE* ppbMK,
  378. DWORD* pcbMK)
  379. {
  380. BOOL fRet = FALSE;
  381. DESKEY sDerivedKey1;
  382. DESKEY sConfirmKey;
  383. PBYTE pTemp;
  384. // assumes pbKeyBlock is at least 2*DES_KEYLEN bytes
  385. if (*pcbMK != 2*DES_KEYLEN)
  386. goto Ret;
  387. // confirmation key is 2nd in buffer
  388. if (!FMyMakeDESKey(
  389. &sConfirmKey, // out
  390. *ppbMK + DES_KEYLEN)) // in
  391. goto Ret;
  392. if (!FMyPrimitiveHMAC(
  393. sConfirmKey,
  394. g_rgbConfirmBuf,
  395. sizeof(g_rgbConfirmBuf),
  396. rgbConfirm))
  397. goto Ret;
  398. // DK1 = DeriveKey(SHA(pw), Salt)
  399. if (!FMyPrimitiveDeriveKey(
  400. rgbSalt,
  401. cbSalt,
  402. rgbPwd,
  403. A_SHA_DIGEST_LEN, ///sizeof(rgbPwd),
  404. &sDerivedKey1))
  405. goto Ret;
  406. // Encrypt MK w/ DK1, return
  407. if (!FMyPrimitiveDESEncrypt(
  408. ppbMK,
  409. pcbMK,
  410. sDerivedKey1))
  411. goto Ret;
  412. // Mash version onto front!!
  413. pTemp = (PBYTE)SSReAlloc(*ppbMK, *pcbMK+sizeof(DWORD)); // realloc bigger for ver
  414. if (pTemp == NULL) // check allocation
  415. goto Ret;
  416. *ppbMK = pTemp;
  417. MoveMemory(*ppbMK+sizeof(DWORD), *ppbMK, *pcbMK); // move data 1 dw right
  418. *pcbMK += sizeof(DWORD); // inc size
  419. *(DWORD*)(*ppbMK) = (DWORD)ENCRYPTED_MASTERKEY_VER; // whack version in there!
  420. fRet = TRUE;
  421. Ret:
  422. return fRet;
  423. }
  424. // returns a new key block encrypted with master key
  425. // creates and stores master key state if none exists
  426. BOOL FMyEncryptKeyBlock(
  427. LPCWSTR szUser,
  428. LPCWSTR szMasterKey,
  429. BYTE rgbPwd[A_SHA_DIGEST_LEN],
  430. PBYTE* ppbKeyBlock,
  431. DWORD* pcbKeyBlock,
  432. DESKEY* psItemKey,
  433. DESKEY* psMacKey)
  434. {
  435. BOOL fRet = FALSE;
  436. *ppbKeyBlock = NULL;
  437. BYTE rgbSalt[PASSWORD_SALT_LEN];
  438. BYTE rgbConfirm[A_SHA_DIGEST_LEN];
  439. PBYTE pbMK = NULL;
  440. DWORD cbMK;
  441. PBYTE pbTmp = NULL;
  442. DWORD cbTmp;
  443. DESKEY sMK;
  444. // gen a random key block: 2 keys
  445. *pcbKeyBlock = 2*DES_KEYLEN;
  446. *ppbKeyBlock = (PBYTE) SSAlloc(*pcbKeyBlock + DES_BLOCKLEN); // performance fudge factor (realloc)
  447. if (*ppbKeyBlock == NULL) // check allocation
  448. goto Ret;
  449. if (!RtlGenRandom(*ppbKeyBlock, *pcbKeyBlock))
  450. goto Ret;
  451. // INSERT: FRENCH GOVT. THOUGHT CONTROL CODE
  452. if (! FIsEncryptionPermitted())
  453. {
  454. // Protected Storage addition, 5/27/97
  455. // If encryption is not allowed, pretend faulty
  456. // RNG generated encryption key { 6d 8a 88 6a 4e aa 37 a8 }
  457. SS_ASSERT(DES_KEYLEN == sizeof(DWORD)*2);
  458. *(DWORD*)(*ppbKeyBlock) = 0x6d8a886a;
  459. *(DWORD*)(*ppbKeyBlock + sizeof(DWORD)) = 0x4eaa37a8;
  460. // PS: Remind me not to move to FRANCE
  461. }
  462. // assumes pbKeyBlock is at least 2*DES_KEYLEN bytes
  463. SS_ASSERT(*pcbKeyBlock == 2*DES_KEYLEN);
  464. if (!FMyMakeDESKey(
  465. psItemKey, // out
  466. *ppbKeyBlock)) // in
  467. goto Ret;
  468. if (!FMyMakeDESKey(
  469. psMacKey, // out
  470. *ppbKeyBlock + DES_KEYLEN)) // in
  471. goto Ret;
  472. // first derive a key from PW
  473. if (FBPGetSecurityState(
  474. szUser,
  475. szMasterKey,
  476. rgbSalt,
  477. sizeof(rgbSalt),
  478. rgbConfirm,
  479. sizeof(rgbConfirm),
  480. &pbMK,
  481. &cbMK))
  482. {
  483. // unwrap master key
  484. if (!FMyDecryptMK(
  485. rgbSalt,
  486. sizeof(rgbSalt),
  487. rgbPwd,
  488. rgbConfirm,
  489. &pbMK,
  490. &cbMK))
  491. goto Ret;
  492. // done, have MK unwrapped.
  493. }
  494. else
  495. {
  496. // if we couldn't retrieve state, assume we must generate it
  497. if (!RtlGenRandom(rgbSalt, PASSWORD_SALT_LEN))
  498. goto Ret;
  499. cbMK = 2*DES_KEYSIZE;
  500. pbMK = (PBYTE)SSAlloc(cbMK + DES_BLOCKLEN); // performance fudge factor (realloc)
  501. if (pbMK == NULL) // check allocation
  502. goto Ret;
  503. if (!RtlGenRandom(pbMK, cbMK))
  504. goto Ret;
  505. // this is final MK: encrypt a copy
  506. cbTmp = cbMK;
  507. pbTmp = (PBYTE)SSAlloc(cbTmp);
  508. if (pbTmp == NULL) // check allocation
  509. goto Ret;
  510. CopyMemory(pbTmp, pbMK, cbMK);
  511. // now wrap MK up and stuff in registry
  512. if (!FMyEncryptMK(
  513. rgbSalt,
  514. sizeof(rgbSalt),
  515. rgbPwd,
  516. rgbConfirm,
  517. &pbTmp,
  518. &cbTmp))
  519. goto Ret;
  520. if (!FBPSetSecurityState(
  521. szUser,
  522. szMasterKey,
  523. rgbSalt,
  524. PASSWORD_SALT_LEN,
  525. rgbConfirm,
  526. sizeof(rgbConfirm),
  527. pbTmp,
  528. cbTmp))
  529. goto Ret;
  530. }
  531. if (cbMK != 2*DES_KEYSIZE)
  532. goto Ret;
  533. if (!FMyMakeDESKey(
  534. &sMK, // out
  535. pbMK)) // in
  536. goto Ret;
  537. if (*pcbKeyBlock != 2*DES_KEYLEN)
  538. goto Ret;
  539. if (!FMyPrimitiveDESEncrypt(
  540. ppbKeyBlock,
  541. pcbKeyBlock,
  542. sMK))
  543. goto Ret;
  544. fRet = TRUE;
  545. Ret:
  546. if (!fRet)
  547. {
  548. if (*ppbKeyBlock) {
  549. SSFree(*ppbKeyBlock);
  550. *ppbKeyBlock = NULL;
  551. }
  552. }
  553. if (pbMK) {
  554. RtlSecureZeroMemory(pbMK, cbMK);
  555. SSFree(pbMK);
  556. }
  557. if (pbTmp) {
  558. RtlSecureZeroMemory(pbTmp, cbTmp); // sfield: zero memory
  559. SSFree(pbTmp);
  560. }
  561. return fRet;
  562. }
  563. // given data, will generate a key block and
  564. // return encrypt/mac'd data
  565. BOOL FProvEncryptData(
  566. LPCWSTR szUser, // in
  567. LPCWSTR szMasterKey, // in
  568. BYTE rgbPwd[A_SHA_DIGEST_LEN], // in
  569. PBYTE* ppbMyData, // in out
  570. DWORD* pcbMyData) // in out
  571. {
  572. BOOL fRet = FALSE;
  573. DESKEY sItemKey;
  574. DESKEY sMacKey;
  575. BYTE rgbHMAC[A_SHA_DIGEST_LEN];
  576. // helpful pointers
  577. PBYTE pbCurPtr = *ppbMyData;
  578. PBYTE pbKeyBlock = NULL;
  579. DWORD cbKeyBlock = 0;
  580. DWORD cbDataSize;
  581. // return an item key, mac key
  582. // store in an encrypted key block using MK, etc.
  583. if (!FMyEncryptKeyBlock(
  584. szUser,
  585. szMasterKey,
  586. rgbPwd,
  587. &pbKeyBlock,
  588. &cbKeyBlock,
  589. &sItemKey,
  590. &sMacKey))
  591. goto Ret;
  592. // now secure data
  593. // Compute HMAC
  594. if (!FMyPrimitiveHMAC(sMacKey, *ppbMyData, *pcbMyData, rgbHMAC))
  595. goto Ret;
  596. // DATA FORMAT:
  597. // version | size(keyblk) | keyblk | size(encryptedblk) | Encrypted{ size(data) | data | size(MAC) | MAC}
  598. // lengthen data seg by data size member, MAC and MAC size member
  599. cbDataSize = *pcbMyData; // save current size
  600. *pcbMyData += A_SHA_DIGEST_LEN + 2*sizeof(DWORD); // sizeof(data), MAC, sizeof(MAC)
  601. pbCurPtr = (PBYTE)SSReAlloc(*ppbMyData, *pcbMyData);
  602. if (pbCurPtr == NULL) // check allocation
  603. goto Ret;
  604. *ppbMyData = pbCurPtr;
  605. // size, data
  606. MoveMemory(pbCurPtr+sizeof(DWORD), pbCurPtr, cbDataSize); // shift right data for size insertion
  607. *(DWORD UNALIGNED *)pbCurPtr = cbDataSize; // size of data
  608. pbCurPtr += sizeof(DWORD); // fwd past size
  609. pbCurPtr += cbDataSize; // fwd past data
  610. // size, MAC
  611. *(DWORD UNALIGNED *)pbCurPtr = A_SHA_DIGEST_LEN; // size of MAC
  612. pbCurPtr += sizeof(DWORD); // fwd past size
  613. CopyMemory(pbCurPtr, rgbHMAC, A_SHA_DIGEST_LEN); // MAC
  614. pbCurPtr += A_SHA_DIGEST_LEN; // fwd past MAC
  615. if (!FMyPrimitiveDESEncrypt(
  616. ppbMyData, // in out
  617. pcbMyData, // in out
  618. sItemKey))
  619. goto Ret;
  620. cbDataSize = *pcbMyData; // save current size
  621. *pcbMyData += 3*sizeof(DWORD) + cbKeyBlock; // ver, sizeof(keyblk), keyblk, sizeof(encrdata)
  622. pbCurPtr = (PBYTE)SSReAlloc(*ppbMyData, *pcbMyData);
  623. if (pbCurPtr == NULL) // check allocation
  624. goto Ret;
  625. *ppbMyData = pbCurPtr;
  626. // shift right data for size, keyblk insertions
  627. MoveMemory(pbCurPtr + 3*sizeof(DWORD) + cbKeyBlock, pbCurPtr, cbDataSize);
  628. // throw version tag in front
  629. *(DWORD UNALIGNED *)pbCurPtr = (DWORD)ENCRYPTED_DATA_VER;
  630. pbCurPtr += sizeof(DWORD);
  631. // insert keyblock
  632. *(DWORD UNALIGNED *)pbCurPtr = cbKeyBlock; // size of data
  633. pbCurPtr += sizeof(DWORD); // fwd past size
  634. CopyMemory(pbCurPtr, pbKeyBlock, cbKeyBlock); // data
  635. pbCurPtr += cbKeyBlock; // fwd past data
  636. // insert sizeof encrypted blob
  637. *(DWORD UNALIGNED *)pbCurPtr = cbDataSize; // size of data
  638. fRet = TRUE;
  639. Ret:
  640. RtlSecureZeroMemory(&sItemKey, sizeof(DESKEY));
  641. RtlSecureZeroMemory(&sMacKey, sizeof(DESKEY));
  642. if (pbKeyBlock)
  643. SSFree(pbKeyBlock);
  644. return fRet;
  645. }
  646. // given password, and master key, will decrypt and
  647. // verify MAC on master key
  648. BOOL FCheckPWConfirm(
  649. LPCWSTR szUser, // in
  650. LPCWSTR szMasterKey, // in
  651. BYTE rgbPwd[A_SHA_DIGEST_LEN]) // in
  652. {
  653. BOOL fRet = FALSE;
  654. BYTE rgbSalt[PASSWORD_SALT_LEN];
  655. BYTE rgbConfirm[A_SHA_DIGEST_LEN];
  656. PBYTE pbMK = NULL;
  657. DWORD cbMK;
  658. // confirm is just get state and attempt MK decrypt
  659. if (FBPGetSecurityState(
  660. szUser,
  661. szMasterKey,
  662. rgbSalt,
  663. sizeof(rgbSalt),
  664. rgbConfirm,
  665. sizeof(rgbConfirm),
  666. &pbMK,
  667. &cbMK))
  668. {
  669. BOOL fResetSecurityState;
  670. // found state; is pwd correct?
  671. if (!FMyDecryptMKEx(
  672. rgbSalt,
  673. sizeof(rgbSalt),
  674. rgbPwd,
  675. rgbConfirm,
  676. &pbMK,
  677. &cbMK,
  678. &fResetSecurityState
  679. ))
  680. goto Ret;
  681. if( fResetSecurityState )
  682. {
  683. // now wrap MK up and stuff in registry
  684. if(FMyEncryptMK(
  685. rgbSalt,
  686. sizeof(rgbSalt),
  687. rgbPwd,
  688. rgbConfirm,
  689. &pbMK,
  690. &cbMK
  691. )) {
  692. if (FBPSetSecurityState(
  693. szUser,
  694. szMasterKey,
  695. rgbSalt,
  696. sizeof(rgbSalt),
  697. rgbConfirm,
  698. sizeof(rgbConfirm),
  699. pbMK,
  700. cbMK
  701. ))
  702. {
  703. // found state; is pwd correct?
  704. if (!FMyDecryptMKEx(
  705. rgbSalt,
  706. sizeof(rgbSalt),
  707. rgbPwd,
  708. rgbConfirm,
  709. &pbMK,
  710. &cbMK,
  711. &fResetSecurityState
  712. )) {
  713. OutputDebugString(TEXT("fail to dec\n"));
  714. goto Ret;
  715. }
  716. }
  717. }
  718. } // reset security state.
  719. }
  720. else
  721. {
  722. // didn't find state; create it
  723. // if we couldn't retrieve state, assume we must generate it
  724. if (!RtlGenRandom(rgbSalt, PASSWORD_SALT_LEN))
  725. goto Ret;
  726. cbMK = 2*DES_KEYLEN;
  727. pbMK = (PBYTE)SSAlloc(cbMK);
  728. if (pbMK == NULL) // check allocation
  729. goto Ret;
  730. if (!RtlGenRandom(pbMK, cbMK))
  731. goto Ret;
  732. // now wrap MK up and stuff in registry
  733. if (!FMyEncryptMK(
  734. rgbSalt,
  735. sizeof(rgbSalt),
  736. rgbPwd,
  737. rgbConfirm,
  738. &pbMK,
  739. &cbMK))
  740. goto Ret;
  741. if (!FBPSetSecurityState(
  742. szUser,
  743. szMasterKey,
  744. rgbSalt,
  745. PASSWORD_SALT_LEN,
  746. rgbConfirm,
  747. sizeof(rgbConfirm),
  748. pbMK,
  749. cbMK))
  750. goto Ret;
  751. }
  752. fRet = TRUE;
  753. Ret:
  754. if (pbMK) {
  755. RtlSecureZeroMemory(pbMK, cbMK); // sfield: zero memory
  756. SSFree(pbMK);
  757. }
  758. return fRet;
  759. }
  760. // callback for changing a password. On password change,
  761. // MasterKey is decrypted and re-encrypted
  762. BOOL FPasswordChangeNotify(
  763. LPCWSTR szUser, // in
  764. LPCWSTR szPasswordName, // in
  765. BYTE rgbOldPwd[A_SHA_DIGEST_LEN], // in
  766. DWORD cbOldPwd, // in
  767. BYTE rgbNewPwd[A_SHA_DIGEST_LEN], // in
  768. DWORD cbNewPwd) // in
  769. {
  770. // allows unattended pw change (callback from svr)
  771. BOOL fRet = FALSE;
  772. BYTE rgbSalt[PASSWORD_SALT_LEN];
  773. BYTE rgbConfirm[A_SHA_DIGEST_LEN];
  774. PBYTE pbMK = NULL;
  775. DWORD cbMK;
  776. BOOL fNewPassword = (cbOldPwd == 0);
  777. // can't modify a non-user changable pw
  778. // if (!FIsUserMasterKey(szPasswordName))
  779. // goto Ret;
  780. if (cbNewPwd != A_SHA_DIGEST_LEN)
  781. goto Ret;
  782. // ensure old pwd exists
  783. if (!FBPGetSecurityState(
  784. szUser,
  785. szPasswordName,
  786. rgbSalt,
  787. sizeof(rgbSalt),
  788. rgbConfirm,
  789. sizeof(rgbConfirm),
  790. &pbMK,
  791. &cbMK))
  792. {
  793. // couldn't retreive old PW, create a new one
  794. if (!FCheckPWConfirm(
  795. szUser,
  796. szPasswordName,
  797. rgbNewPwd))
  798. goto Ret;
  799. fRet = TRUE;
  800. goto Ret;
  801. }
  802. else
  803. {
  804. // state was retrieved
  805. if (fNewPassword)
  806. {
  807. SetLastError((DWORD)PST_E_ITEM_EXISTS);
  808. goto Ret;
  809. }
  810. }
  811. // old pwd retrieved -- time to update
  812. if (!FMyDecryptMK(
  813. rgbSalt,
  814. sizeof(rgbSalt),
  815. rgbOldPwd,
  816. rgbConfirm,
  817. &pbMK,
  818. &cbMK))
  819. {
  820. SetLastError((DWORD)PST_E_WRONG_PASSWORD);
  821. goto Ret;
  822. }
  823. // MK is naked here
  824. // rewrap and save state
  825. if (!FMyEncryptMK(
  826. rgbSalt,
  827. sizeof(rgbSalt),
  828. rgbNewPwd,
  829. rgbConfirm,
  830. &pbMK,
  831. &cbMK))
  832. goto Ret;
  833. if (!FBPSetSecurityState(
  834. szUser,
  835. szPasswordName,
  836. rgbSalt,
  837. sizeof(rgbSalt),
  838. rgbConfirm,
  839. sizeof(rgbConfirm),
  840. pbMK,
  841. cbMK))
  842. goto Ret;
  843. fRet = TRUE;
  844. Ret:
  845. if (pbMK) {
  846. RtlSecureZeroMemory(pbMK, cbMK);
  847. SSFree(pbMK);
  848. }
  849. return fRet;
  850. }
  851. BOOL FHMACGeographicallySensitiveData(
  852. LPCWSTR szUser, // in
  853. LPCWSTR szPasswordName, // in
  854. DWORD dwHMACVersion, // in
  855. BYTE rgbPwd[A_SHA_DIGEST_LEN], // in
  856. const GUID* pguidType, // in
  857. const GUID* pguidSubtype, // in
  858. LPCWSTR szItem, // in: may be NULL
  859. PBYTE pbBuf, // in
  860. DWORD cbBuf, // in
  861. BYTE rgbHMAC[A_SHA_DIGEST_LEN]) // out
  862. {
  863. BOOL fRet = FALSE;
  864. // helpful pointer
  865. PBYTE pbCurrent;
  866. PBYTE pbKeyBlock = NULL;
  867. DWORD cbKeyBlock;
  868. DESKEY sBogusKey;
  869. DESKEY sMacKey;
  870. DWORD cbTmp = (DWORD)(cbBuf + 2*sizeof(GUID) + WSZ_BYTECOUNT(szItem));
  871. PBYTE pbTmp = (PBYTE)SSAlloc(cbTmp);
  872. if (pbTmp == NULL) // check allocation
  873. goto Ret;
  874. // helpful pointer
  875. pbCurrent = pbTmp;
  876. // snag the MAC key
  877. if (!FGetInternalMACKey(szUser, &pbKeyBlock, &cbKeyBlock))
  878. {
  879. // create a key block
  880. if (!FMyEncryptKeyBlock(
  881. szUser,
  882. szPasswordName,
  883. rgbPwd,
  884. &pbKeyBlock,
  885. &cbKeyBlock,
  886. &sBogusKey,
  887. &sMacKey))
  888. goto Ret;
  889. if (!FSetInternalMACKey(szUser, pbKeyBlock, cbKeyBlock))
  890. goto Ret;
  891. }
  892. else
  893. {
  894. // key already exists; get it
  895. if (!FMyDecryptKeyBlock(
  896. szUser,
  897. szPasswordName,
  898. rgbPwd,
  899. pbKeyBlock,
  900. cbKeyBlock,
  901. &sBogusKey,
  902. &sMacKey))
  903. goto Ret;
  904. }
  905. // HMAC format:
  906. // HMAC( guidType | guidSubtype | szItemName | pbData )
  907. // copy type
  908. CopyMemory(pbCurrent, pguidType, sizeof(GUID));
  909. pbCurrent += sizeof(GUID);
  910. // copy subtype
  911. CopyMemory(pbCurrent, pguidSubtype, sizeof(GUID));
  912. pbCurrent += sizeof(GUID);
  913. // copy item name
  914. CopyMemory(pbCurrent, szItem, WSZ_BYTECOUNT(szItem));
  915. pbCurrent += WSZ_BYTECOUNT(szItem);
  916. // copy actual data
  917. CopyMemory(pbCurrent, pbBuf, cbBuf);
  918. if (dwHMACVersion == OLD_HMAC_VERSION)
  919. {
  920. // now do HMAC on this
  921. if (!FMyOldPrimitiveHMAC(
  922. sMacKey,
  923. pbTmp,
  924. cbTmp,
  925. rgbHMAC))
  926. goto Ret;
  927. }
  928. else
  929. {
  930. // now do HMAC on this
  931. if (!FMyPrimitiveHMAC(
  932. sMacKey,
  933. pbTmp,
  934. cbTmp,
  935. rgbHMAC))
  936. goto Ret;
  937. }
  938. fRet = TRUE;
  939. Ret:
  940. if (pbTmp)
  941. SSFree(pbTmp);
  942. if (pbKeyBlock)
  943. SSFree(pbKeyBlock);
  944. return fRet;
  945. }
  946. // lifted (nearly) directly from RSABase ntagum.c
  947. // do locale check once
  948. static BOOL g_fEncryptionIsPermitted;
  949. static BOOL g_fIKnowEncryptionPermitted = FALSE;
  950. BOOL FIsEncryptionPermitted()
  951. /*++
  952. Routine Description:
  953. This routine checks whether encryption is getting the system default
  954. LCID and checking whether the country code is CTRY_FRANCE.
  955. Arguments:
  956. none
  957. Return Value:
  958. TRUE - encryption is permitted
  959. FALSE - encryption is not permitted
  960. --*/
  961. {
  962. LCID DefaultLcid;
  963. CHAR CountryCode[10];
  964. ULONG CountryValue;
  965. if (!g_fIKnowEncryptionPermitted)
  966. {
  967. // assume okay (unless found otherwise)
  968. g_fEncryptionIsPermitted = TRUE;
  969. DefaultLcid = GetSystemDefaultLCID();
  970. //
  971. // Check if the default language is Standard French
  972. //
  973. if (LANGIDFROMLCID(DefaultLcid) == 0x40c)
  974. g_fEncryptionIsPermitted = FALSE;
  975. //
  976. // Check if the users's country is set to FRANCE
  977. //
  978. if (GetLocaleInfoA(DefaultLcid,LOCALE_ICOUNTRY,CountryCode,10) == 0)
  979. g_fEncryptionIsPermitted = FALSE;
  980. /*
  981. CountryValue = (ULONG) atol(CountryCode);
  982. if (CountryValue == CTRY_FRANCE)
  983. return(FALSE);
  984. */
  985. //
  986. // begin remove dependency on atol and msvcrt
  987. //
  988. // from winnls.h:
  989. // #define CTRY_FRANCE 33 // France
  990. SS_ASSERT(CTRY_FRANCE == 33);
  991. if (0 == lstrcmpA(CountryCode, "33"))
  992. g_fEncryptionIsPermitted = FALSE;
  993. //
  994. // end remove dependency on atol and msvcrt
  995. //
  996. g_fIKnowEncryptionPermitted = TRUE;
  997. }
  998. return g_fEncryptionIsPermitted;
  999. }