Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1067 lines
28 KiB

  1. #include "global.hxx"
  2. // crypto defs
  3. #include <wincrypt.h>
  4. #include "randlib.h"
  5. #include "pfxhelp.h"
  6. #include "pfxcmn.h"
  7. #include "pfxcrypt.h"
  8. #include "sha.h"
  9. #include "shacomm.h"
  10. #include "rc2.h"
  11. #include "modes.h"
  12. #include "des.h"
  13. #include "tripldes.h"
  14. // constants used in PKCS5-like key derivation
  15. #define DERIVE_ENCRYPT_DECRYPT 0x1
  16. #define DERIVE_INITIAL_VECTOR 0x2
  17. #define DERIVE_INTEGRITY_KEY 0x3
  18. #define HMAC_K_PADSIZE 64
  19. BOOL FMyPrimitiveSHA(
  20. PBYTE pbData,
  21. DWORD cbData,
  22. BYTE rgbHash[A_SHA_DIGEST_LEN])
  23. {
  24. BOOL fRet = FALSE;
  25. A_SHA_CTX sSHAHash;
  26. A_SHAInit(&sSHAHash);
  27. A_SHAUpdate(&sSHAHash, (BYTE *) pbData, cbData);
  28. A_SHAFinal(&sSHAHash, rgbHash);
  29. fRet = TRUE;
  30. //Ret:
  31. return fRet;
  32. }
  33. BOOL FMyPrimitiveHMACParam(
  34. PBYTE pbKeyMaterial,
  35. DWORD cbKeyMaterial,
  36. PBYTE pbData,
  37. DWORD cbData,
  38. BYTE rgbHMAC[A_SHA_DIGEST_LEN])
  39. {
  40. BOOL fRet = FALSE;
  41. BYTE rgbKipad[HMAC_K_PADSIZE];
  42. BYTE rgbKopad[HMAC_K_PADSIZE];
  43. // truncate
  44. if (cbKeyMaterial > HMAC_K_PADSIZE)
  45. cbKeyMaterial = HMAC_K_PADSIZE;
  46. ZeroMemory(rgbKipad, HMAC_K_PADSIZE);
  47. CopyMemory(rgbKipad, pbKeyMaterial, cbKeyMaterial);
  48. ZeroMemory(rgbKopad, HMAC_K_PADSIZE);
  49. CopyMemory(rgbKopad, pbKeyMaterial, cbKeyMaterial);
  50. BYTE rgbHMACTmp[HMAC_K_PADSIZE+A_SHA_DIGEST_LEN];
  51. // assert we're a multiple
  52. assert( (HMAC_K_PADSIZE % sizeof(DWORD)) == 0);
  53. // Kipad, Kopad are padded sMacKey. Now XOR across...
  54. for(DWORD dwBlock=0; dwBlock<HMAC_K_PADSIZE/sizeof(DWORD); dwBlock++)
  55. {
  56. ((DWORD*)rgbKipad)[dwBlock] ^= 0x36363636;
  57. ((DWORD*)rgbKopad)[dwBlock] ^= 0x5C5C5C5C;
  58. }
  59. // prepend Kipad to data, Hash to get H1
  60. {
  61. // do this inline, don't call MyPrimitiveSHA since it would require data copy
  62. A_SHA_CTX sSHAHash;
  63. A_SHAInit(&sSHAHash);
  64. A_SHAUpdate(&sSHAHash, rgbKipad, HMAC_K_PADSIZE);
  65. A_SHAUpdate(&sSHAHash, pbData, cbData);
  66. // Finish off the hash
  67. A_SHAFinal(&sSHAHash, sSHAHash.HashVal);
  68. // prepend Kopad to H1, hash to get HMAC
  69. CopyMemory(rgbHMACTmp, rgbKopad, HMAC_K_PADSIZE);
  70. CopyMemory(rgbHMACTmp+HMAC_K_PADSIZE, sSHAHash.HashVal, A_SHA_DIGEST_LEN);
  71. }
  72. if (!FMyPrimitiveSHA(
  73. rgbHMACTmp,
  74. sizeof(rgbHMACTmp),
  75. rgbHMAC))
  76. goto Ret;
  77. fRet = TRUE;
  78. Ret:
  79. return fRet;
  80. }
  81. static
  82. BOOL
  83. CopyPassword(
  84. BYTE *pbLocation,
  85. LPCWSTR szPassword,
  86. DWORD dwMaxBytes
  87. )
  88. {
  89. DWORD i = 0;
  90. DWORD cbWideChars = WSZ_BYTECOUNT(szPassword);
  91. BYTE *pbWideChars = (BYTE *) szPassword;
  92. while ((i<cbWideChars) && (i<dwMaxBytes))
  93. {
  94. pbLocation[i] = pbWideChars[i+1];
  95. pbLocation[i+1] = pbWideChars[i];
  96. i+=2;
  97. }
  98. return TRUE;
  99. }
  100. //+ --------------------------------------------------------------
  101. // in NSCP's initial implementation of PFX020, this
  102. // is the algorithm they used to derive a key from a password.
  103. // We include it so we can interoperate.
  104. BOOL NSCPDeriveKey(
  105. LPCWSTR szPassword,
  106. PBYTE pbPrivacySalt,
  107. DWORD cbPrivacySalt,
  108. int iPKCS5Iterations,
  109. PBYTE pbPKCS5Salt,
  110. DWORD cbPKCS5Salt,
  111. PBYTE pbDerivedMaterial,
  112. DWORD cbDerivedMaterial)
  113. {
  114. BOOL fRet = FALSE;
  115. BYTE rgbPKCS5Key[A_SHA_DIGEST_LEN];
  116. DWORD cbVirtualPW = cbPrivacySalt + WSZ_BYTECOUNT(szPassword);
  117. PBYTE pbVirtualPW = (PBYTE)SSAlloc(cbVirtualPW);
  118. if (pbVirtualPW == NULL)
  119. goto Ret;
  120. // Virtual PW = (salt | szPW)
  121. CopyMemory(pbVirtualPW, pbPrivacySalt, cbPrivacySalt);
  122. CopyPassword(&pbVirtualPW[cbPrivacySalt], szPassword, WSZ_BYTECOUNT(szPassword));
  123. // use PKCS#5 to generate initial bit stream (seed)
  124. if (!PKCS5_GenKey(
  125. iPKCS5Iterations,
  126. pbVirtualPW, cbVirtualPW,
  127. pbPKCS5Salt, cbPKCS5Salt,
  128. rgbPKCS5Key))
  129. goto Ret;
  130. if (cbDerivedMaterial > sizeof(rgbPKCS5Key))
  131. {
  132. // P_hash (secret, seed) = HMAC_hash (secret, A(0) + seed),
  133. // HMAC_hash (secret, A(1) + seed),
  134. // HMAC_hash (secret, A(2) + seed),
  135. // HMAC_hash (secret, A(3) + seed) ...
  136. // where
  137. // A(0) = seed
  138. // A(i) = HMAC_hash(secret, A(i-1))
  139. // seed = PKCS5 salt for PKCS5 PBE param
  140. // secret = normal PKCS5 hashed key
  141. if (!P_Hash (
  142. rgbPKCS5Key,
  143. sizeof(rgbPKCS5Key),
  144. pbPKCS5Salt,
  145. cbPKCS5Salt,
  146. pbDerivedMaterial, // output
  147. cbDerivedMaterial, // # of output bytes requested
  148. TRUE) ) // NSCP compat mode?
  149. goto Ret;
  150. }
  151. else
  152. {
  153. // we already have enough bits to satisfy the request
  154. CopyMemory(pbDerivedMaterial, rgbPKCS5Key, cbDerivedMaterial);
  155. }
  156. fRet = TRUE;
  157. Ret:
  158. if (pbVirtualPW)
  159. SSFree(pbVirtualPW);
  160. return fRet;
  161. }
  162. static
  163. BYTE
  164. AddWithCarry(
  165. BYTE byte1,
  166. BYTE byte2,
  167. BYTE *carry // IN and OUT
  168. )
  169. {
  170. BYTE tempCarry = *carry;
  171. if (((DWORD)byte1 + (DWORD)byte2 + (DWORD)tempCarry) >= 256) {
  172. *carry = 1;
  173. }
  174. else {
  175. *carry = 0;
  176. }
  177. return (byte1 + byte2 + tempCarry);
  178. }
  179. // 512 bits = ? bytes
  180. #define SHA_INTERNAL_BLOCKLEN (512/8)
  181. #define SHA_V_LENGTH (512/8)
  182. //+ --------------------------------------------------------------
  183. // In PKCS12 v1.0 Draft, this is the way they describe to
  184. // derive a key from a password.
  185. BOOL
  186. PKCS12DeriveKey(
  187. LPCWSTR szPassword,
  188. BYTE bID,
  189. int iIterations,
  190. PBYTE pbSalt,
  191. DWORD cbSalt,
  192. PBYTE pbDerivedMaterial,
  193. DWORD cbDerivedMaterial)
  194. {
  195. #if DBG
  196. if (iIterations>1)
  197. OutputDebugString("Perf hit: iterating key derivation! (pfxcrypt:PKCS12DeriveKey())\n");
  198. #endif
  199. BOOL fRet = FALSE;
  200. BYTE rgSaltPwd[2*SHA_INTERNAL_BLOCKLEN];
  201. DWORD cbSaltPwd;
  202. BYTE rgDiversifier[SHA_INTERNAL_BLOCKLEN];
  203. BYTE B[SHA_V_LENGTH];
  204. DWORD i;
  205. DWORD cbPassword = WSZ_BYTECOUNT(szPassword);
  206. BYTE bCarry;
  207. DWORD vBlocks;
  208. A_SHA_CTX sSHAHash;
  209. // construct D
  210. FillMemory(rgDiversifier, sizeof(rgDiversifier), bID);
  211. // concat salt to create string of length 64*(cb/64) bytes
  212. // copy salt (multiple) times, don't copy the last time
  213. for (i=0; i<(SHA_INTERNAL_BLOCKLEN-cbSalt); i+=cbSalt)
  214. {
  215. CopyMemory(&rgSaltPwd[i], pbSalt, cbSalt);
  216. }
  217. // do final copy (assert we have less than cbSalt bytes left to copy)
  218. assert(cbSalt >= (SHA_INTERNAL_BLOCKLEN - (i%SHA_INTERNAL_BLOCKLEN)) );
  219. CopyMemory(&rgSaltPwd[i], pbSalt, (SHA_INTERNAL_BLOCKLEN-(i%SHA_INTERNAL_BLOCKLEN)));
  220. // if the password is not NULL, concat pwd to create string of length 64*(cbPwd/64) bytes
  221. // copy pwd (multiple) times, don't copy the last time
  222. if (szPassword)
  223. {
  224. // truncate if necessary
  225. if (cbPassword > SHA_INTERNAL_BLOCKLEN)
  226. cbPassword = SHA_INTERNAL_BLOCKLEN;
  227. for (i=SHA_INTERNAL_BLOCKLEN; i<( (2*SHA_INTERNAL_BLOCKLEN)-cbPassword); i+=cbPassword)
  228. {
  229. // use CopyPassword because bytes need to be swapped
  230. CopyPassword(&rgSaltPwd[i], szPassword, cbPassword);
  231. }
  232. // do final copy (assert we have less than cbSalt bytes left to copy)
  233. assert(cbPassword >= (SHA_INTERNAL_BLOCKLEN - (i%SHA_INTERNAL_BLOCKLEN)) );
  234. CopyPassword(&rgSaltPwd[i], szPassword, (SHA_INTERNAL_BLOCKLEN-(i%SHA_INTERNAL_BLOCKLEN)));
  235. cbSaltPwd = sizeof(rgSaltPwd);
  236. }
  237. else
  238. {
  239. cbSaltPwd = sizeof(rgSaltPwd) / 2;
  240. }
  241. // concat S|P
  242. // done, available in rgSaltPwd
  243. // set c = cbDerivedMaterial/A_SHA_DIGEST_LEN
  244. //assert(0 == cbDerivedMaterial%A_SHA_DIGEST_LEN);
  245. // compute working size >= output size
  246. DWORD cBlocks = (DWORD)((cbDerivedMaterial/A_SHA_DIGEST_LEN) +1);
  247. DWORD cbTmpBuf = cBlocks * A_SHA_DIGEST_LEN;
  248. PBYTE pbTmpBuf = (PBYTE)LocalAlloc(LPTR, cbTmpBuf);
  249. if (pbTmpBuf == NULL)
  250. goto Ret;
  251. // now do only full blocks
  252. for (i=0; i< cBlocks; i++)
  253. {
  254. int iIter;
  255. int iCount;
  256. A_SHAInit(&sSHAHash);
  257. for (iIter=0; iIter<iIterations; iIter++)
  258. {
  259. // Tmp = Hash(D | I);
  260. if (iIter==0)
  261. {
  262. A_SHAUpdate(&sSHAHash, rgDiversifier, sizeof(rgDiversifier));
  263. A_SHAUpdate(&sSHAHash, rgSaltPwd, cbSaltPwd);
  264. }
  265. else
  266. {
  267. // rehash last output
  268. A_SHAUpdate(&sSHAHash, &pbTmpBuf[i*A_SHA_DIGEST_LEN], A_SHA_DIGEST_LEN);
  269. }
  270. // spit iteration output to final buffer
  271. A_SHAFinal(&sSHAHash, &pbTmpBuf[i*A_SHA_DIGEST_LEN]);
  272. }
  273. // concat A[x] | A[x] | ... and truncate to get 64 bytes
  274. iCount = 0;
  275. while (iCount+A_SHA_DIGEST_LEN <= sizeof(B)) {
  276. CopyMemory(&B[iCount], &pbTmpBuf[i*A_SHA_DIGEST_LEN], A_SHA_DIGEST_LEN);
  277. iCount += A_SHA_DIGEST_LEN;
  278. }
  279. CopyMemory(&B[iCount], &pbTmpBuf[i*A_SHA_DIGEST_LEN], sizeof(B) % A_SHA_DIGEST_LEN);
  280. // modify I by setting Ij += (B + 1) (mod 2^512)
  281. for (vBlocks = 0; vBlocks < cbSaltPwd; vBlocks += SHA_V_LENGTH) {
  282. bCarry = 1;
  283. for (iCount = SHA_V_LENGTH-1; iCount >= 0; iCount--)
  284. {
  285. rgSaltPwd[iCount+vBlocks] = AddWithCarry(rgSaltPwd[iCount+vBlocks], B[iCount], &bCarry);
  286. }
  287. }
  288. }
  289. // copy from (larger) working buffer to output buffer
  290. CopyMemory(pbDerivedMaterial, pbTmpBuf, cbDerivedMaterial);
  291. fRet = TRUE;
  292. Ret:
  293. if (pbTmpBuf)
  294. LocalFree(pbTmpBuf);
  295. return fRet;
  296. }
  297. //+ --------------------------------------------------------------
  298. // in NSCP's initial implementation of PFX020, this
  299. // is the algorithm they used to decrypt data. This uses the
  300. // key derivation code above.
  301. // We include it so we can interoperate.
  302. BOOL NSCPPasswordDecryptData(
  303. int iEncrType,
  304. LPCWSTR szPassword,
  305. PBYTE pbPrivacySalt, // privacy salt
  306. DWORD cbPrivacySalt,
  307. int iPKCS5Iterations, // pkcs5 data
  308. PBYTE pbPKCS5Salt,
  309. DWORD cbPKCS5Salt,
  310. PBYTE* ppbData, // in/out
  311. DWORD* pcbData)
  312. {
  313. BOOL fRet = FALSE;
  314. BYTE rgbDerivedKeyMatl[40]; // 320 bits is enough for 128 bit key, 64 bit IV
  315. DWORD cbNeeded;
  316. if (iEncrType == RC2_40)
  317. cbNeeded = (40/8)+RC2_BLOCKLEN; // key + IV
  318. else
  319. cbNeeded = 0;
  320. // make next muliple of SHA dig len
  321. if (cbNeeded % A_SHA_DIGEST_LEN)
  322. {
  323. cbNeeded += (A_SHA_DIGEST_LEN - (cbNeeded % A_SHA_DIGEST_LEN));
  324. }
  325. assert(0 == (cbNeeded % A_SHA_DIGEST_LEN));
  326. assert(cbNeeded <= sizeof(rgbDerivedKeyMatl));
  327. if (!NSCPDeriveKey(
  328. szPassword,
  329. pbPrivacySalt,
  330. cbPrivacySalt,
  331. iPKCS5Iterations,
  332. pbPKCS5Salt,
  333. cbPKCS5Salt,
  334. rgbDerivedKeyMatl,
  335. cbNeeded) )
  336. goto Ret;
  337. // NOW decrypt data
  338. if (iEncrType == RC2_40)
  339. {
  340. DWORD dwDataPos;
  341. DWORD cbToBeDec = *pcbData;
  342. WORD rc2Table[RC2_TABLESIZE];
  343. BYTE rc2Fdbk [RC2_BLOCKLEN];
  344. assert( (40/8) <= sizeof(rgbDerivedKeyMatl));
  345. assert( 0 == cbToBeDec % RC2_BLOCKLEN ); // must be even multiple
  346. // key setup
  347. RC2Key(rc2Table, rgbDerivedKeyMatl, (40/8)); // take first 40 bits of keying material
  348. CopyMemory(rc2Fdbk, &rgbDerivedKeyMatl[cbNeeded - sizeof(rc2Fdbk)], sizeof(rc2Fdbk)); // fdbk is last chunk
  349. // decryption
  350. for (dwDataPos=0; cbToBeDec > 0; dwDataPos+=RC2_BLOCKLEN, cbToBeDec -= RC2_BLOCKLEN)
  351. {
  352. BYTE rgbDec[RC2_BLOCKLEN];
  353. CBC(
  354. RC2,
  355. RC2_BLOCKLEN,
  356. rgbDec,
  357. &(*ppbData)[dwDataPos],
  358. rc2Table,
  359. DECRYPT,
  360. rc2Fdbk);
  361. CopyMemory(&(*ppbData)[dwDataPos], rgbDec, RC2_BLOCKLEN);
  362. }
  363. }
  364. else
  365. goto Ret;
  366. fRet = TRUE;
  367. Ret:
  368. return fRet;
  369. }
  370. //+ --------------------------------------------------------------
  371. // in the PKCS12 v1.0 Draft, this is how they describe how to
  372. // encrypt data.
  373. BOOL PFXPasswordEncryptData(
  374. int iEncrType,
  375. LPCWSTR szPassword,
  376. int iPKCS5Iterations, // pkcs5 data
  377. PBYTE pbPKCS5Salt,
  378. DWORD cbPKCS5Salt,
  379. PBYTE* ppbData,
  380. DWORD* pcbData)
  381. {
  382. BOOL fRet = FALSE;
  383. BOOL fIsBlockCipher = FALSE;
  384. DWORD cbToBeEnc;
  385. BYTE rgbDerivedKey[A_SHA_DIGEST_LEN*2]; // 320 bits is enough for 256 bit key
  386. BYTE rgbDerivedIV[A_SHA_DIGEST_LEN*2]; // 320 bits is enough for 256 bit IV
  387. DWORD cbKeyNeeded, cbIVNeeded, cbBlockLen;
  388. if (iEncrType == RC2_40)
  389. {
  390. cbKeyNeeded = (40/8); // key
  391. cbIVNeeded = RC2_BLOCKLEN; // IV
  392. cbBlockLen = RC2_BLOCKLEN;
  393. fIsBlockCipher = TRUE;
  394. }
  395. else if (iEncrType == TripleDES)
  396. {
  397. cbKeyNeeded = (64/8) * 3;
  398. cbIVNeeded = DES_BLOCKLEN;
  399. cbBlockLen = DES_BLOCKLEN;
  400. fIsBlockCipher = TRUE;
  401. }
  402. else
  403. {
  404. cbKeyNeeded = 0;
  405. cbIVNeeded = 0;
  406. cbBlockLen = 0;
  407. }
  408. // make next muliple of SHA dig len
  409. if (cbKeyNeeded % A_SHA_DIGEST_LEN)
  410. cbKeyNeeded += (A_SHA_DIGEST_LEN - (cbKeyNeeded % A_SHA_DIGEST_LEN));
  411. if (cbIVNeeded % A_SHA_DIGEST_LEN)
  412. cbIVNeeded += (A_SHA_DIGEST_LEN - (cbIVNeeded % A_SHA_DIGEST_LEN));
  413. assert(0 == (cbKeyNeeded % A_SHA_DIGEST_LEN));
  414. assert(0 == (cbIVNeeded % A_SHA_DIGEST_LEN));
  415. assert(cbKeyNeeded <= sizeof(rgbDerivedKey));
  416. assert(cbIVNeeded <= sizeof(rgbDerivedIV));
  417. if (!PKCS12DeriveKey(
  418. szPassword,
  419. DERIVE_ENCRYPT_DECRYPT,
  420. iPKCS5Iterations,
  421. pbPKCS5Salt,
  422. cbPKCS5Salt,
  423. rgbDerivedKey,
  424. cbKeyNeeded) )
  425. goto Ret;
  426. if (!PKCS12DeriveKey(
  427. szPassword,
  428. DERIVE_INITIAL_VECTOR,
  429. iPKCS5Iterations,
  430. pbPKCS5Salt,
  431. cbPKCS5Salt,
  432. rgbDerivedIV,
  433. cbIVNeeded) )
  434. goto Ret;
  435. if (fIsBlockCipher)
  436. {
  437. // extend buffer to multiple of blocklen
  438. cbToBeEnc = *pcbData;
  439. cbToBeEnc += cbBlockLen - (cbToBeEnc%cbBlockLen); // {1..BLOCKLEN}
  440. *ppbData = (PBYTE)SSReAlloc(*ppbData, cbToBeEnc);
  441. if (NULL == *ppbData)
  442. goto Ret;
  443. // pad remaining bytes with length
  444. FillMemory(&((*ppbData)[*pcbData]), cbToBeEnc-(*pcbData), (BYTE)(cbToBeEnc-(*pcbData)));
  445. *pcbData = cbToBeEnc;
  446. assert( cbBlockLen <= sizeof(rgbDerivedKey));
  447. assert( 0 == cbToBeEnc % cbBlockLen ); // must be even multiple
  448. }
  449. // NOW encrypt data
  450. if (iEncrType == RC2_40)
  451. {
  452. DWORD dwDataPos;
  453. WORD rc2Table[RC2_TABLESIZE];
  454. BYTE rc2Fdbk [RC2_BLOCKLEN];
  455. // already done: extend buffer, add PKCS byte padding
  456. // key setup
  457. RC2Key(rc2Table, rgbDerivedKey, (40/8)); // take first 40 bits of keying material
  458. CopyMemory(rc2Fdbk, rgbDerivedIV, sizeof(rc2Fdbk));
  459. // decryption
  460. for (dwDataPos=0; cbToBeEnc > 0; dwDataPos+=RC2_BLOCKLEN, cbToBeEnc -= RC2_BLOCKLEN)
  461. {
  462. BYTE rgbEnc[RC2_BLOCKLEN];
  463. CBC(
  464. RC2,
  465. RC2_BLOCKLEN,
  466. rgbEnc,
  467. &(*ppbData)[dwDataPos],
  468. rc2Table,
  469. ENCRYPT,
  470. rc2Fdbk);
  471. CopyMemory(&(*ppbData)[dwDataPos], rgbEnc, sizeof(rgbEnc));
  472. }
  473. }
  474. else if (iEncrType == TripleDES)
  475. {
  476. DWORD dwDataPos;
  477. DES3TABLE des3Table;
  478. BYTE des3Fdbk [DES_BLOCKLEN];
  479. // already done: extend buffer, add PKCS byte padding
  480. // key setup
  481. tripledes3key(&des3Table, rgbDerivedKey);
  482. CopyMemory(des3Fdbk, rgbDerivedIV, sizeof(des3Fdbk)); // fdbk is last chunk
  483. for (dwDataPos=0; cbToBeEnc > 0; dwDataPos+=DES_BLOCKLEN, cbToBeEnc -= DES_BLOCKLEN)
  484. {
  485. BYTE rgbEnc[DES_BLOCKLEN];
  486. CBC(
  487. tripledes,
  488. DES_BLOCKLEN,
  489. rgbEnc,
  490. &(*ppbData)[dwDataPos],
  491. (void *) &des3Table,
  492. ENCRYPT,
  493. des3Fdbk);
  494. CopyMemory(&(*ppbData)[dwDataPos], rgbEnc, DES_BLOCKLEN);
  495. }
  496. }
  497. else
  498. goto Ret;
  499. fRet = TRUE;
  500. Ret:
  501. return fRet;
  502. }
  503. //+ --------------------------------------------------------------
  504. // in the PKCS12 v1.0 Draft, this is how they describe how to
  505. // decrypt data.
  506. BOOL PFXPasswordDecryptData(
  507. int iEncrType,
  508. LPCWSTR szPassword,
  509. int iPKCS5Iterations, // pkcs5 data
  510. PBYTE pbPKCS5Salt,
  511. DWORD cbPKCS5Salt,
  512. PBYTE* ppbData,
  513. DWORD* pcbData)
  514. {
  515. BOOL fRet = FALSE;
  516. BOOL fIsBlockCipher = FALSE;
  517. BYTE rgbDerivedKey[A_SHA_DIGEST_LEN*2]; // 320 bits is enough for 256 bit key
  518. BYTE rgbDerivedIV[A_SHA_DIGEST_LEN*2]; // 320 bits is enough for 256 bit IV
  519. DWORD cbKeyNeeded, cbIVNeeded, cbBlockLen;
  520. if (iEncrType == RC2_40)
  521. {
  522. cbKeyNeeded = (40/8); // key
  523. cbIVNeeded = RC2_BLOCKLEN; // IV
  524. cbBlockLen = RC2_BLOCKLEN;
  525. fIsBlockCipher = TRUE;
  526. }
  527. else if (iEncrType == TripleDES)
  528. {
  529. cbKeyNeeded = (64/8) * 3;
  530. cbIVNeeded = DES_BLOCKLEN;
  531. cbBlockLen = DES_BLOCKLEN;
  532. fIsBlockCipher = TRUE;
  533. }
  534. else
  535. {
  536. cbKeyNeeded = 0;
  537. cbIVNeeded = 0;
  538. cbBlockLen = 0;
  539. }
  540. // make next muliple of SHA dig len
  541. if (cbKeyNeeded % A_SHA_DIGEST_LEN)
  542. cbKeyNeeded += (A_SHA_DIGEST_LEN - (cbKeyNeeded % A_SHA_DIGEST_LEN));
  543. if (cbIVNeeded % A_SHA_DIGEST_LEN)
  544. cbIVNeeded += (A_SHA_DIGEST_LEN - (cbIVNeeded % A_SHA_DIGEST_LEN));
  545. assert(0 == (cbKeyNeeded % A_SHA_DIGEST_LEN));
  546. assert(0 == (cbIVNeeded % A_SHA_DIGEST_LEN));
  547. assert(cbKeyNeeded <= sizeof(rgbDerivedKey));
  548. assert(cbIVNeeded <= sizeof(rgbDerivedIV));
  549. if (!PKCS12DeriveKey(
  550. szPassword,
  551. DERIVE_ENCRYPT_DECRYPT,
  552. iPKCS5Iterations,
  553. pbPKCS5Salt,
  554. cbPKCS5Salt,
  555. rgbDerivedKey,
  556. cbKeyNeeded) )
  557. goto Ret;
  558. if (!PKCS12DeriveKey(
  559. szPassword,
  560. DERIVE_INITIAL_VECTOR,
  561. iPKCS5Iterations,
  562. pbPKCS5Salt,
  563. cbPKCS5Salt,
  564. rgbDerivedIV,
  565. cbIVNeeded) )
  566. goto Ret;
  567. // NOW decrypt data
  568. if (iEncrType == RC2_40)
  569. {
  570. BYTE rgbDec[RC2_BLOCKLEN];
  571. DWORD dwDataPos;
  572. DWORD cbToBeDec = *pcbData;
  573. WORD rc2Table[RC2_TABLESIZE];
  574. BYTE rc2Fdbk [RC2_BLOCKLEN];
  575. assert( (40/8) <= sizeof(rgbDerivedKey));
  576. assert( 0 == cbToBeDec % RC2_BLOCKLEN ); // must be even multiple
  577. // key setup
  578. RC2Key(rc2Table, rgbDerivedKey, (40/8)); // take first 40 bits of keying material
  579. CopyMemory(rc2Fdbk, rgbDerivedIV, sizeof(rc2Fdbk));
  580. // decryption
  581. for (dwDataPos=0; cbToBeDec > 0; dwDataPos+=RC2_BLOCKLEN, cbToBeDec -= RC2_BLOCKLEN)
  582. {
  583. CBC(
  584. RC2,
  585. RC2_BLOCKLEN,
  586. rgbDec,
  587. &(*ppbData)[dwDataPos],
  588. rc2Table,
  589. DECRYPT,
  590. rc2Fdbk);
  591. CopyMemory(&(*ppbData)[dwDataPos], rgbDec, sizeof(rgbDec));
  592. }
  593. }
  594. else if (iEncrType == TripleDES) {
  595. DWORD dwDataPos;
  596. DWORD cbToBeDec = *pcbData;
  597. DES3TABLE des3Table;
  598. BYTE des3Fdbk [DES_BLOCKLEN];
  599. // key setup
  600. tripledes3key(&des3Table, rgbDerivedKey);
  601. CopyMemory(des3Fdbk, rgbDerivedIV, sizeof(des3Fdbk)); // fdbk is last chunk
  602. for (dwDataPos=0; cbToBeDec > 0; dwDataPos += DES_BLOCKLEN, cbToBeDec -= DES_BLOCKLEN)
  603. {
  604. BYTE rgbDec[DES_BLOCKLEN];
  605. CBC(
  606. tripledes,
  607. DES_BLOCKLEN,
  608. rgbDec,
  609. &(*ppbData)[dwDataPos],
  610. (void *) &des3Table,
  611. DECRYPT,
  612. des3Fdbk);
  613. CopyMemory(&(*ppbData)[dwDataPos], rgbDec, DES_BLOCKLEN);
  614. }
  615. }
  616. else
  617. goto Ret;
  618. // Remove padding
  619. if (fIsBlockCipher)
  620. {
  621. // last byte of decr is pad byte
  622. BYTE iPadBytes;
  623. iPadBytes = (*ppbData)[*pcbData-1];
  624. if (iPadBytes > cbBlockLen)
  625. goto Ret;
  626. *ppbData = (PBYTE)SSReAlloc( (*ppbData), *pcbData - iPadBytes);
  627. if (NULL == *ppbData)
  628. goto Ret;
  629. *pcbData -= iPadBytes;
  630. }
  631. fRet = TRUE;
  632. Ret:
  633. return fRet;
  634. }
  635. //+ --------------------------------------------------------------
  636. // in the PKCS12 v1.0 Draft, this is how they describe how to
  637. // generate a checksum that will prove data integrid.
  638. BOOL FGenerateMAC(
  639. LPCWSTR szPassword,
  640. PBYTE pbPKCS5Salt,
  641. DWORD cbPKCS5Salt,
  642. DWORD iterationCount,
  643. PBYTE pbData, // pb data
  644. DWORD cbData, // cb data
  645. BYTE rgbMAC[]) // output
  646. {
  647. // UNDONE UNDONE: Use RSABase
  648. BOOL fRet = FALSE;
  649. BYTE rgbDerivedKey[A_SHA_DIGEST_LEN]; // 160 bits is enough for a MAC key
  650. DWORD cbKeyNeeded = A_SHA_DIGEST_LEN;
  651. assert(0 == (cbKeyNeeded % A_SHA_DIGEST_LEN));
  652. assert(cbKeyNeeded <= sizeof(rgbDerivedKey));
  653. if (!PKCS12DeriveKey(
  654. szPassword,
  655. DERIVE_INTEGRITY_KEY,
  656. iterationCount, // no other way to determine iterations: HARDCODE
  657. pbPKCS5Salt,
  658. cbPKCS5Salt,
  659. rgbDerivedKey,
  660. cbKeyNeeded) )
  661. goto Ret;
  662. if (!FMyPrimitiveHMACParam(
  663. rgbDerivedKey,
  664. cbKeyNeeded,
  665. pbData,
  666. cbData,
  667. rgbMAC))
  668. goto Ret;
  669. fRet = TRUE;
  670. Ret:
  671. return fRet;
  672. }
  673. /////////////////////////////////////////////////////////////////
  674. // begin tls1key.cpp
  675. /*-----------------------------------------------------------------------------
  676. * Copyright (C) Microsoft Corporation, 1995 - 1999
  677. * All rights reserved.
  678. *----------------------------------------------------------------------------*/
  679. // the original PKCS5 algorithm for generating a key from a password
  680. BOOL PKCS5_GenKey
  681. (
  682. int iIterations,
  683. PBYTE pbPW,
  684. DWORD cbPW,
  685. PBYTE pbSalt,
  686. DWORD cbSalt,
  687. BYTE rgbPKCS5Key[A_SHA_DIGEST_LEN]
  688. )
  689. {
  690. BOOL fRet = FALSE;
  691. int i;
  692. DWORD cbTmp = cbSalt + cbPW;
  693. PBYTE pbTmp = (PBYTE) SSAlloc(cbTmp);
  694. if (pbTmp == NULL)
  695. goto Ret;
  696. // pbTmp is ( PW | Salt )
  697. CopyMemory(pbTmp, pbPW, cbPW);
  698. CopyMemory(&pbTmp[cbPW], pbSalt, cbSalt);
  699. for (i=0; i<iIterations; i++)
  700. {
  701. if (i == 0) {
  702. if (!FMyPrimitiveSHA(
  703. pbTmp, // in
  704. cbTmp, // in
  705. rgbPKCS5Key))
  706. goto Ret;
  707. }
  708. else {
  709. if (!FMyPrimitiveSHA(
  710. rgbPKCS5Key, // in
  711. A_SHA_DIGEST_LEN, // in
  712. rgbPKCS5Key))
  713. goto Ret;
  714. }
  715. }
  716. fRet = TRUE;
  717. Ret:
  718. SSFree(pbTmp);
  719. return fRet;
  720. }
  721. //+ ---------------------------------------------------------------------
  722. // the P_Hash algorithm from TLS that was used in NSCP's PFX020 version
  723. // to derive a key from a password. It is included here for completeness.
  724. // NSCP made some implementation errors when they coded this up; to interop,
  725. // use the fNSCPInteropMode parameter. The real P_Hash algorithm is used
  726. // when fNSCPInteropMode is FALSE.
  727. BOOL P_Hash
  728. (
  729. PBYTE pbSecret,
  730. DWORD cbSecret,
  731. PBYTE pbSeed,
  732. DWORD cbSeed,
  733. PBYTE pbKeyOut, //Buffer to copy the result...
  734. DWORD cbKeyOut, //# of bytes of key length they want as output.
  735. BOOL fNSCPInteropMode
  736. )
  737. {
  738. BOOL fRet = FALSE;
  739. BYTE rgbDigest[A_SHA_DIGEST_LEN];
  740. DWORD iKey;
  741. PBYTE pbAofiDigest = (PBYTE)SSAlloc(cbSeed + A_SHA_DIGEST_LEN);
  742. if (pbAofiDigest == NULL)
  743. goto Ret;
  744. ZeroMemory(pbAofiDigest, cbSeed+A_SHA_DIGEST_LEN);
  745. // First, we define a data expansion function, P_hash(secret, data)
  746. // which uses a single hash function to expand a secret and seed into
  747. // an arbitrary quantity of output:
  748. // P_hash(secret, seed) = HMAC_hash(secret, A(1) + seed) +
  749. // HMAC_hash(secret, A(2) + seed) +
  750. // HMAC_hash(secret, A(3) + seed) + ...
  751. // Where + indicates concatenation.
  752. // A() is defined as:
  753. // A(0) = seed
  754. // A(i) = HMAC_hash(secret, A(i-1))
  755. if (fNSCPInteropMode)
  756. {
  757. // NSCP interop mode: 7/7/97
  758. // nscp leaves (A_SHA_DIGEST_LEN-cbSeed) bytes zeroed between
  759. // the seed and the appended seed. For interop, do derivation this way
  760. // Also, they use A(0) to derive key bytes, whereas TLS spec
  761. // specifies to wait for A(1).
  762. CopyMemory(pbAofiDigest, pbSeed, cbSeed);
  763. }
  764. else
  765. {
  766. // build A(1)
  767. if (!FMyPrimitiveHMACParam(pbSecret, cbSecret, pbSeed, cbSeed, pbAofiDigest))
  768. goto Ret;
  769. }
  770. // create Aofi: ( A(i) | seed )
  771. CopyMemory(&pbAofiDigest[A_SHA_DIGEST_LEN], pbSeed, cbSeed);
  772. for (iKey=0; cbKeyOut; iKey++)
  773. {
  774. // build Digest = HMAC(key | A(i) | seed);
  775. if (!FMyPrimitiveHMACParam(pbSecret, cbSecret, pbAofiDigest, cbSeed + A_SHA_DIGEST_LEN, rgbDigest))
  776. goto Ret;
  777. // append to pbKeyOut
  778. CopyMemory(pbKeyOut, rgbDigest, A_SHA_DIGEST_LEN);
  779. pbKeyOut += A_SHA_DIGEST_LEN;
  780. if(cbKeyOut < A_SHA_DIGEST_LEN)
  781. break;
  782. cbKeyOut -= A_SHA_DIGEST_LEN;
  783. // build A(i) = HMAC(key, A(i-1))
  784. if (!FMyPrimitiveHMACParam(pbSecret, cbSecret, pbAofiDigest, A_SHA_DIGEST_LEN, pbAofiDigest))
  785. goto Ret;
  786. }
  787. fRet = TRUE;
  788. Ret:
  789. if (pbAofiDigest)
  790. SSFree(pbAofiDigest);
  791. return fRet;
  792. }
  793. #if DBG
  794. // test vector for real P_Hash
  795. BOOL FTestPHASH_and_HMAC()
  796. {
  797. BYTE rgbKey[] = {0x33, 0x62, 0xf9, 0x42, 0x43};
  798. CHAR szPwd[] = "My Password";
  799. BYTE rgbKeyOut[7*A_SHA_DIGEST_LEN];
  800. static BYTE rgbTestVectorOutput[] = {
  801. 0x24, 0xF2, 0x98, 0x75, 0xE1, 0x90, 0x6D, 0x49,
  802. 0x96, 0x5B, 0x87, 0xB8, 0xBC, 0xD3, 0x11, 0x6C,
  803. 0x13, 0xDC, 0xBD, 0xC2, 0x7E, 0x56, 0xD0, 0x3C,
  804. 0xAC, 0xCD, 0x86, 0x58, 0x31, 0x67, 0x7B, 0x23,
  805. 0x19, 0x6E, 0x36, 0x65, 0xBF, 0x9F, 0x3D, 0x03,
  806. 0x5A, 0x9C, 0x6E, 0xD7, 0xEB, 0x3E, 0x5A, 0xE6,
  807. 0x05, 0x86, 0x84, 0x5A, 0xC3, 0x97, 0xFC, 0x17,
  808. 0xF5, 0xF0, 0xF5, 0x16, 0x67, 0xAD, 0x7C, 0xED,
  809. 0x65, 0xDC, 0x0B, 0x99, 0x58, 0x5D, 0xCA, 0x66,
  810. 0x28, 0xAD, 0xA5, 0x39, 0x54, 0x44, 0x36, 0x13,
  811. 0x91, 0xCE, 0xE9, 0x73, 0x23, 0x43, 0x2E, 0xEC,
  812. 0xA2, 0xC3, 0xE7, 0xFA, 0x74, 0xA7, 0xB6, 0x75,
  813. 0x77, 0xF5, 0xF5, 0x16, 0xC2, 0xEE, 0xED, 0x7A,
  814. 0x21, 0x86, 0x1D, 0x84, 0x6F, 0xC6, 0x03, 0xF3,
  815. 0xCC, 0x77, 0x02, 0xFA, 0x76, 0x46, 0x64, 0x57,
  816. 0xBB, 0x56, 0x3A, 0xF7, 0x7E, 0xB4, 0xD6, 0x52,
  817. 0x72, 0x8C, 0x34, 0xF1, 0xA4, 0x1E, 0xA7, 0xA6,
  818. 0xCD, 0xBD, 0x3C, 0x16, 0x4D, 0x79, 0x20, 0x50 };
  819. P_Hash(
  820. rgbKey, sizeof(rgbKey),
  821. (PBYTE)szPwd, strlen(szPwd),
  822. rgbKeyOut, sizeof(rgbKeyOut), FALSE);
  823. if (0 != memcmp(rgbKeyOut, rgbTestVectorOutput, sizeof(rgbKeyOut)) )
  824. {
  825. OutputDebugString("ERROR: phash vector test invalid!!!\n");
  826. return FALSE;
  827. }
  828. return TRUE;
  829. }
  830. // test vector for NSCP P_Hash
  831. BOOL F_NSCP_TestPHASH_and_HMAC()
  832. {
  833. BYTE rgbKey[] = { 0xc9, 0xc1, 0x69, 0x6e, 0x30, 0xa8, 0x91, 0x0d,
  834. 0x12, 0x19, 0x48, 0xef, 0x23, 0xac, 0x5b, 0x1f,
  835. 0x2e, 0xc4, 0x0e, 0xc2 };
  836. BYTE rgbSalt[] = { 0x1a, 0xb5, 0xf1, 0x1a, 0x5b, 0x6a, 0x6a, 0x5e };
  837. BYTE rgbKeyOut[7*A_SHA_DIGEST_LEN];
  838. static BYTE rgbTestVectorOutput[] = {
  839. 0x52, 0x7c, 0xbf, 0x90, 0xb1, 0xa1, 0xd0, 0xbf,
  840. 0x21, 0x56, 0x34, 0xf2, 0x1f, 0x5c, 0x98, 0xcf,
  841. 0x55, 0x95, 0xb1, 0x35, 0x65, 0xe3, 0x31, 0x44,
  842. 0x78, 0xc5, 0x41, 0xa9, 0x2a, 0x14, 0x80, 0x19,
  843. 0x56, 0x86, 0xa4, 0x71, 0x07, 0x24, 0x2d, 0x64 };
  844. assert(sizeof(rgbKeyOut) > sizeof(rgbTestVectorOutput));
  845. P_Hash(
  846. rgbKey, sizeof(rgbKey),
  847. rgbSalt, sizeof(rgbSalt),
  848. rgbKeyOut, sizeof(rgbTestVectorOutput),
  849. TRUE);
  850. if (0 != memcmp(rgbKeyOut, rgbTestVectorOutput, sizeof(rgbTestVectorOutput)) )
  851. {
  852. OutputDebugString("ERROR: NSCP phash vector test invalid!!!\n");
  853. return FALSE;
  854. }
  855. return TRUE;
  856. }
  857. #endif // DBG