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.

510 lines
14 KiB

  1. /*
  2. File: primitiv.cpp
  3. Title: Cryptographic Primitives for Protected Storage
  4. Author: Matt Thomlinson
  5. Date: 11/22/96
  6. With the help of the rsa32 library, this module manufactures
  7. actually _usable_ primitives.
  8. Since CryptoAPI base provider may call us, we can't use
  9. CryptXXX primitives (circular dependencies may result).
  10. Functions in this module:
  11. FMyMakeDESKey
  12. Given key material, does necessary DES key setup. Has the
  13. side effect of stashing the keying material in the DESKey
  14. structure.
  15. FMyPrimitiveSHA
  16. Given pbData/cbData, runs SHA1 Init-Update-Final and returns
  17. the hash buffer.
  18. FMyPrimitiveDESEncrypt
  19. Given a ppbBlock/pcbBlock/DESKey structure, DES CBC (with an
  20. IV of 0)encrypts the block with the DESKey passed in. DESKey
  21. must be passed in with key setup already done. Note that this
  22. call might realloc ppbBlock since the encrypted length must be
  23. a multiple of the blocksize.
  24. FMyPrimitiveDESDecrypt
  25. Given a pbBlock/pcbBlock/DESKey structure, decrypts the
  26. block with the given (prepared) DESKey. Note that pbBlock
  27. will not be realloced, since the output buffer is always
  28. smaller than or the same size as the encrypted buffer.
  29. FMyPrimitiveDeriveKey
  30. Derives a DES key from multiple input buffers in
  31. the following manner:
  32. FMyMakeDESKey( SHA1(Salt | OtherData) )
  33. FMyOldPrimitiveHMAC (non-interoperable, buggy version of HMAC)
  34. FMyPrimitiveHMAC
  35. Derives a quality HMAC (Keyed message-authentication code) for
  36. passed-in data and prepared DESKey. The HMAC is computed in
  37. the following (standard HMAC) manner:
  38. KoPad = KiPad = DESKey key setup buffer
  39. XOR(KoPad, 0x5c5c5c5c)
  40. XOR(KiPad, 0x36363636)
  41. HMAC = SHA1(KoPad | SHA1(KiPad | Data))
  42. */
  43. #include <windows.h>
  44. // crypto defs
  45. #include <wincrypt.h>
  46. #include "sha.h"
  47. #include "des.h"
  48. #include "modes.h"
  49. #include "randlib.h"
  50. // others
  51. #include "primitiv.h"
  52. #include "debug.h"
  53. #define OLD_MAC_K_PADSIZE 16
  54. #define HMAC_K_PADSIZE 64
  55. BOOL FMyMakeDESKey(
  56. PDESKEY pDESKey,
  57. BYTE* pbKeyMaterial)
  58. {
  59. CopyMemory(pDESKey->rgbKey, pbKeyMaterial, DES_BLOCKLEN);
  60. // assumes pbKeyMaterial is at least DES_BLOCKLEN bytes
  61. deskey(&pDESKey->sKeyTable, pbKeyMaterial); // takes material, runs DES table setup
  62. return TRUE;
  63. }
  64. BOOL FMyPrimitiveSHA(
  65. PBYTE pbData,
  66. DWORD cbData,
  67. BYTE rgbHash[A_SHA_DIGEST_LEN])
  68. {
  69. A_SHA_CTX sSHAHash;
  70. A_SHAInit(&sSHAHash);
  71. A_SHAUpdate(&sSHAHash, (BYTE *) pbData, cbData);
  72. A_SHAFinal(&sSHAHash, rgbHash);
  73. return TRUE;
  74. }
  75. BOOL FMyPrimitiveDESDecrypt(
  76. PBYTE pbBlock, // in out
  77. DWORD *pcbBlock, // in out
  78. DESKEY sDESKey) // in
  79. {
  80. BOOL fRet = FALSE;
  81. DWORD dwDataLen = *pcbBlock;
  82. DWORD i;
  83. if (dwDataLen % DES_BLOCKLEN)
  84. {
  85. SetLastError((DWORD) NTE_BAD_DATA);
  86. return FALSE;
  87. }
  88. BYTE rgbBuf[DES_BLOCKLEN];
  89. BYTE rgbFeedBack[DES_BLOCKLEN];
  90. ZeroMemory(rgbFeedBack, DES_BLOCKLEN);
  91. // pump the data through the decryption, including padding
  92. // NOTE: the total length is a multiple of BlockLen
  93. for (DWORD BytePos = 0; (BytePos + DES_BLOCKLEN) <= dwDataLen; BytePos += DES_BLOCKLEN)
  94. {
  95. // put the encrypted text into a temp buffer
  96. CopyMemory(rgbBuf, pbBlock + BytePos, DES_BLOCKLEN);
  97. CBC(des, DES_BLOCKLEN, pbBlock + BytePos, rgbBuf, &sDESKey.sKeyTable,
  98. DECRYPT, rgbFeedBack);
  99. }
  100. // ## NOTE: if the pad is wrong, the user's buffer is hosed, because
  101. // ## we've decrypted into the user's buffer -- can we re-encrypt it?
  102. //
  103. // if dwPadVal is wrong, we've failed to decrypt correctly. Bad key?
  104. //
  105. DWORD dwPadVal = (DWORD) *(pbBlock + dwDataLen - 1);
  106. if (dwPadVal == 0 || dwPadVal > DES_BLOCKLEN)
  107. {
  108. SetLastError((DWORD) NTE_BAD_DATA);
  109. goto Ret;
  110. }
  111. // Make sure all the (rest of the) pad bytes are correct.
  112. for (i=1; i<dwPadVal; i++)
  113. {
  114. if ((pbBlock)[dwDataLen - (i + 1)] != dwPadVal)
  115. {
  116. SetLastError((DWORD) NTE_BAD_DATA);
  117. goto Ret;
  118. }
  119. }
  120. // update the length
  121. *pcbBlock -= dwPadVal;
  122. fRet = TRUE;
  123. Ret:
  124. return fRet;
  125. }
  126. BOOL FMyPrimitiveDESEncrypt(
  127. PBYTE* ppbBlock, // in out
  128. DWORD *pcbBlock, // in out
  129. DESKEY sDESKey) // in
  130. {
  131. BOOL fRet = FALSE;
  132. DWORD dwDataLen = *pcbBlock;
  133. PBYTE pTemp;
  134. DWORD cbPartial = (*pcbBlock % DES_BLOCKLEN);
  135. DWORD dwPadVal = DES_BLOCKLEN - cbPartial;
  136. if (dwPadVal != 0)
  137. {
  138. *pcbBlock += dwPadVal;
  139. pTemp = (PBYTE)SSReAlloc(*ppbBlock, *pcbBlock);
  140. if (NULL == pTemp) {
  141. return FALSE;
  142. }
  143. *ppbBlock = pTemp;
  144. }
  145. // now we're a multiple of DES_BLOCKLEN
  146. SS_ASSERT((*pcbBlock % DES_BLOCKLEN) == 0);
  147. if (dwPadVal)
  148. {
  149. // Fill the pad with a value equal to the
  150. // length of the padding, so decrypt will
  151. // know the length of the original data
  152. // and as a simple integrity check.
  153. FillMemory(*ppbBlock + dwDataLen, (int)dwPadVal, (size_t)dwPadVal);
  154. }
  155. // allocate memory for a temporary buffer
  156. BYTE rgbBuf[DES_BLOCKLEN];
  157. BYTE rgbFeedBack[DES_BLOCKLEN];
  158. ZeroMemory(rgbFeedBack, DES_BLOCKLEN);
  159. PBYTE pbData = *ppbBlock;
  160. // pump the full blocks of data through
  161. for (dwDataLen = *pcbBlock; dwDataLen>0; dwDataLen-=DES_BLOCKLEN, pbData+=DES_BLOCKLEN)
  162. {
  163. SS_ASSERT(dwDataLen >= DES_BLOCKLEN);
  164. // put the plaintext into a temporary
  165. // buffer, then encrypt the data
  166. // back into the caller's buffer
  167. CopyMemory(rgbBuf, pbData, DES_BLOCKLEN);
  168. CBC(des, DES_BLOCKLEN, pbData, rgbBuf, &sDESKey.sKeyTable,
  169. ENCRYPT, rgbFeedBack);
  170. }
  171. fRet = TRUE;
  172. //Ret:
  173. return fRet;
  174. }
  175. BOOL FMyPrimitiveDeriveKey(
  176. PBYTE pbSalt,
  177. DWORD cbSalt,
  178. PBYTE pbOtherData,
  179. DWORD cbOtherData,
  180. DESKEY* pDesKey)
  181. {
  182. BOOL fRet = FALSE;
  183. A_SHA_CTX sSHAHash;
  184. BYTE HashVal[A_SHA_DIGEST_LEN];
  185. /*
  186. PBYTE pbToBeHashed = (PBYTE)SSAlloc(cbSalt+cbOtherData);
  187. if(pbToBeHashed == NULL) return FALSE;
  188. CopyMemory(pbToBeHashed, pbSalt, cbSalt);
  189. CopyMemory((PBYTE)((DWORD)pbToBeHashed+cbSalt), pbOtherData, cbOtherData);
  190. // hash data
  191. BYTE rgbHash[A_SHA_DIGEST_LEN];
  192. if (!FMyPrimitiveSHA(pbToBeHashed, cbSalt+cbOtherData, rgbHash))
  193. goto Ret;
  194. */
  195. // NEW: put hashing code inline: saves alloc, copy, free
  196. A_SHAInit(&sSHAHash);
  197. A_SHAUpdate(&sSHAHash, (BYTE *) pbSalt, cbSalt);
  198. A_SHAUpdate(&sSHAHash, (BYTE *) pbOtherData, cbOtherData);
  199. A_SHAFinal(&sSHAHash, HashVal);
  200. // now all data hashed, derive a session key
  201. SS_ASSERT(sizeof(HashVal) >= DES_BLOCKLEN);
  202. if (!FMyMakeDESKey(pDesKey, HashVal))
  203. goto Ret;
  204. ZeroMemory( HashVal, sizeof(HashVal) );
  205. fRet = TRUE;
  206. Ret:
  207. return fRet;
  208. }
  209. BOOL FMyOldPrimitiveHMAC(
  210. DESKEY sMacKey,
  211. PBYTE pbData,
  212. DWORD cbData,
  213. BYTE rgbHMAC[A_SHA_DIGEST_LEN])
  214. {
  215. BOOL fRet = FALSE;
  216. BYTE rgbKipad[OLD_MAC_K_PADSIZE];
  217. BYTE rgbKopad[OLD_MAC_K_PADSIZE];
  218. ZeroMemory(rgbKipad, OLD_MAC_K_PADSIZE);
  219. CopyMemory(rgbKipad, &sMacKey.rgbKey, DES_BLOCKLEN);
  220. CopyMemory(rgbKopad, rgbKipad, sizeof(rgbKipad));
  221. BYTE rgbHMACTmp[OLD_MAC_K_PADSIZE+A_SHA_DIGEST_LEN];
  222. // assert we're a multiple
  223. SS_ASSERT( (OLD_MAC_K_PADSIZE % sizeof(DWORD)) == 0);
  224. // Kipad, Kopad are padded sMacKey. Now XOR across...
  225. for(DWORD dwBlock=0; dwBlock<OLD_MAC_K_PADSIZE/sizeof(DWORD); dwBlock++)
  226. {
  227. ((DWORD*)rgbKipad)[dwBlock] ^= 0x36363636;
  228. ((DWORD*)rgbKopad)[dwBlock] ^= 0x5C5C5C5C;
  229. }
  230. // prepend Kipad to data, Hash to get H1
  231. {
  232. // do this inline, don't call MyPrimitiveSHA since it would require data copy
  233. A_SHA_CTX sSHAHash;
  234. BYTE HashVal[A_SHA_DIGEST_LEN];
  235. A_SHAInit(&sSHAHash);
  236. A_SHAUpdate(&sSHAHash, pbData, cbData);
  237. A_SHAUpdate(&sSHAHash, rgbKipad, OLD_MAC_K_PADSIZE);
  238. // Finish off the hash
  239. A_SHAFinal(&sSHAHash, HashVal);
  240. // prepend Kopad to H1, hash to get HMAC
  241. CopyMemory(rgbHMACTmp, rgbKopad, OLD_MAC_K_PADSIZE);
  242. CopyMemory(rgbHMACTmp+OLD_MAC_K_PADSIZE, HashVal, A_SHA_DIGEST_LEN);
  243. }
  244. if (!FMyPrimitiveSHA(
  245. rgbHMACTmp,
  246. sizeof(rgbHMACTmp),
  247. rgbHMAC))
  248. goto Ret;
  249. fRet = TRUE;
  250. Ret:
  251. return fRet;
  252. }
  253. BOOL FMyPrimitiveHMAC(
  254. DESKEY sMacKey,
  255. PBYTE pbData,
  256. DWORD cbData,
  257. BYTE rgbHMAC[A_SHA_DIGEST_LEN])
  258. {
  259. return FMyPrimitiveHMACParam(
  260. sMacKey.rgbKey,
  261. DES_BLOCKLEN,
  262. pbData,
  263. cbData,
  264. rgbHMAC);
  265. }
  266. BOOL FMyPrimitiveHMACParam(
  267. PBYTE pbKeyMaterial,
  268. DWORD cbKeyMaterial,
  269. PBYTE pbData,
  270. DWORD cbData,
  271. BYTE rgbHMAC[A_SHA_DIGEST_LEN] // output buffer
  272. )
  273. {
  274. BOOL fRet = FALSE;
  275. BYTE rgbKipad[HMAC_K_PADSIZE];
  276. BYTE rgbKopad[HMAC_K_PADSIZE];
  277. // truncate
  278. if (cbKeyMaterial > HMAC_K_PADSIZE)
  279. cbKeyMaterial = HMAC_K_PADSIZE;
  280. ZeroMemory(rgbKipad, HMAC_K_PADSIZE);
  281. CopyMemory(rgbKipad, pbKeyMaterial, cbKeyMaterial);
  282. ZeroMemory(rgbKopad, HMAC_K_PADSIZE);
  283. CopyMemory(rgbKopad, pbKeyMaterial, cbKeyMaterial);
  284. BYTE rgbHMACTmp[HMAC_K_PADSIZE+A_SHA_DIGEST_LEN];
  285. // assert we're a multiple
  286. SS_ASSERT( (HMAC_K_PADSIZE % sizeof(DWORD)) == 0);
  287. // Kipad, Kopad are padded sMacKey. Now XOR across...
  288. for(DWORD dwBlock=0; dwBlock<HMAC_K_PADSIZE/sizeof(DWORD); dwBlock++)
  289. {
  290. ((DWORD*)rgbKipad)[dwBlock] ^= 0x36363636;
  291. ((DWORD*)rgbKopad)[dwBlock] ^= 0x5C5C5C5C;
  292. }
  293. // prepend Kipad to data, Hash to get H1
  294. {
  295. // do this inline, don't call MyPrimitiveSHA since it would require data copy
  296. A_SHA_CTX sSHAHash;
  297. BYTE HashVal[A_SHA_DIGEST_LEN];
  298. A_SHAInit(&sSHAHash);
  299. A_SHAUpdate(&sSHAHash, rgbKipad, HMAC_K_PADSIZE);
  300. A_SHAUpdate(&sSHAHash, pbData, cbData);
  301. // Finish off the hash
  302. A_SHAFinal(&sSHAHash, HashVal);
  303. // prepend Kopad to H1, hash to get HMAC
  304. CopyMemory(rgbHMACTmp, rgbKopad, HMAC_K_PADSIZE);
  305. CopyMemory(rgbHMACTmp+HMAC_K_PADSIZE, HashVal, A_SHA_DIGEST_LEN);
  306. }
  307. // final hash: output value into passed-in buffer
  308. if (!FMyPrimitiveSHA(
  309. rgbHMACTmp,
  310. sizeof(rgbHMACTmp),
  311. rgbHMAC))
  312. goto Ret;
  313. fRet = TRUE;
  314. Ret:
  315. return fRet;
  316. }
  317. /////////////////////////////////////////////////////////////////////////
  318. // PKCS5DervivePBKDF2_SHA
  319. //
  320. // Performs a PKCS #5 Iterative key derivation (type 2)
  321. // using HMAC_SHA as the primitive hashing function
  322. /////////////////////////////////////////////////////////////////////////
  323. BOOL PKCS5DervivePBKDF2(
  324. PBYTE pbKeyMaterial,
  325. DWORD cbKeyMaterial,
  326. PBYTE pbSalt,
  327. DWORD cbSalt,
  328. DWORD KeyGenAlg,
  329. DWORD cIterationCount,
  330. DWORD iBlockIndex,
  331. BYTE rgbPKCS5Key[A_SHA_DIGEST_LEN] // output buffer
  332. )
  333. {
  334. DWORD i,j;
  335. A_SHA_CTX sSHAHash;
  336. BYTE rgbPKCS5Temp[A_SHA_DIGEST_LEN];
  337. BYTE rgbTempData[PBKDF2_MAX_SALT_SIZE + 4];
  338. if((cIterationCount <1) ||
  339. (NULL == pbKeyMaterial) ||
  340. (NULL == pbSalt) ||
  341. (0 == cbKeyMaterial) ||
  342. (0 == cbSalt) ||
  343. (cbSalt > PBKDF2_MAX_SALT_SIZE) ||
  344. (KeyGenAlg != CALG_HMAC))
  345. {
  346. return FALSE;
  347. }
  348. //
  349. // Add in the block index
  350. //
  351. CopyMemory(rgbTempData, pbSalt, cbSalt);
  352. rgbTempData[cbSalt] = 0;
  353. rgbTempData[cbSalt+1] = 0;
  354. rgbTempData[cbSalt+2] = 0;
  355. rgbTempData[cbSalt+3] = (BYTE)(iBlockIndex & 0xff);
  356. //
  357. // Perfom the initial iteration, which is
  358. // HMAC_SHA1(KeyMaterial, Salt || cBlockIndex)
  359. //
  360. if(!FMyPrimitiveHMACParam(pbKeyMaterial,
  361. cbKeyMaterial,
  362. rgbTempData,
  363. cbSalt+4,
  364. rgbPKCS5Key))
  365. return FALSE;
  366. //
  367. // Perform additional iterations
  368. // HMAC_SHA1(KeyMaterial, last)
  369. //
  370. for (i=1; i<cIterationCount; i++)
  371. {
  372. if(!FMyPrimitiveHMACParam(pbKeyMaterial,
  373. cbKeyMaterial,
  374. rgbPKCS5Key,
  375. A_SHA_DIGEST_LEN,
  376. rgbPKCS5Temp))
  377. return FALSE;
  378. // xor back into the primary key.
  379. for(j=0; j < (A_SHA_DIGEST_LEN / 4); j++)
  380. {
  381. ((DWORD *)rgbPKCS5Key)[j] ^= ((DWORD *)rgbPKCS5Temp)[j];
  382. }
  383. }
  384. return TRUE;
  385. }