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.

518 lines
15 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 2000-2002 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: Hashing.cpp
  6. * Content: This file contains code to support hashing operations on protocol data
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 07/15/02 simonpow Created
  12. *
  13. ****************************************************************************/
  14. #include "dnproti.h"
  15. /*********************************************************************************************
  16. ** Following is standard code for the SHA1 hashing algo.
  17. ** Taken from RFC 3174 (http://www.ietf.org/rfc/rfc3174.txt)
  18. ** Minor tweaks have been made to reduce unecessary error checking
  19. */
  20. #define SHA1HashSize 20
  21. typedef DWORD uint32_t;
  22. typedef BYTE uint8_t;
  23. typedef int int_least16_t;
  24. /*
  25. * This structure will hold context information for the SHA-1
  26. * hashing operation
  27. */
  28. typedef struct SHA1Context
  29. {
  30. uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */
  31. uint32_t Length_Low; /* Message length in bits */
  32. uint32_t Length_High; /* Message length in bits */
  33. int_least16_t Message_Block_Index; /* Index into message block array */
  34. uint8_t Message_Block[64]; /* 512-bit message blocks */
  35. int Computed; /* Is the digest computed? */
  36. } SHA1Context;
  37. /*
  38. * Function Prototypes
  39. */
  40. void SHA1Reset( SHA1Context *);
  41. void SHA1Input( SHA1Context *, const uint8_t *, unsigned int);
  42. void SHA1Result( SHA1Context *, uint8_t Message_Digest[SHA1HashSize]);
  43. /*
  44. * Define the SHA1 circular left shift macro
  45. */
  46. #define SHA1CircularShift(bits,word) \
  47. (((word) << (bits)) | ((word) >> (32-(bits))))
  48. /* Local Function Prototyptes */
  49. void SHA1PadMessage(SHA1Context *);
  50. void SHA1ProcessMessageBlock(SHA1Context *);
  51. /*
  52. * SHA1Reset
  53. *
  54. * Description:
  55. * This function will initialize the SHA1Context in preparation
  56. * for computing a new SHA1 message digest.
  57. */
  58. #undef DPF_MODNAME
  59. #define DPF_MODNAME "SHA1Reset"
  60. void SHA1Reset(SHA1Context *context)
  61. {
  62. DNASSERT(context);
  63. context->Length_Low = 0;
  64. context->Length_High = 0;
  65. context->Message_Block_Index = 0;
  66. context->Intermediate_Hash[0] = 0x67452301;
  67. context->Intermediate_Hash[1] = 0xEFCDAB89;
  68. context->Intermediate_Hash[2] = 0x98BADCFE;
  69. context->Intermediate_Hash[3] = 0x10325476;
  70. context->Intermediate_Hash[4] = 0xC3D2E1F0;
  71. context->Computed = 0;
  72. }
  73. /*
  74. * SHA1Result
  75. *
  76. * Description:
  77. * This function will return the 160-bit message digest into the
  78. * Message_Digest array provided by the caller.
  79. * NOTE: The first octet of hash is stored in the 0th element,
  80. * the last octet of hash in the 19th element.
  81. *
  82. * Parameters:
  83. * context: [in/out]
  84. * The context to use to calculate the SHA-1 hash.
  85. * Message_Digest: [out]
  86. * Where the digest is returned.
  87. *
  88. */
  89. #undef DPF_MODNAME
  90. #define DPF_MODNAME "SHA1Result"
  91. void SHA1Result( SHA1Context *context,
  92. uint8_t Message_Digest[SHA1HashSize])
  93. {
  94. int i;
  95. if (!context->Computed)
  96. {
  97. SHA1PadMessage(context);
  98. for(i=0; i<64; ++i)
  99. {
  100. /* message may be sensitive, clear it out */
  101. context->Message_Block[i] = 0;
  102. }
  103. context->Length_Low = 0; /* and clear length */
  104. context->Length_High = 0;
  105. context->Computed = 1;
  106. }
  107. for(i = 0; i < SHA1HashSize; ++i)
  108. {
  109. Message_Digest[i] = (uint8_t ) (context->Intermediate_Hash[i>>2] >> 8 * ( 3 - ( i & 0x03 ) ));
  110. }
  111. }
  112. /*
  113. * SHA1Input
  114. *
  115. * Description:
  116. * This function accepts an array of octets as the next portion
  117. * of the message.
  118. *
  119. * Parameters:
  120. * context: [in/out]
  121. * The SHA context to update
  122. * message_array: [in]
  123. * An array of characters representing the next portion of
  124. * the message.
  125. * length: [in]
  126. * The length of the message in message_array
  127. *
  128. */
  129. #undef DPF_MODNAME
  130. #define DPF_MODNAME "SHA1Input"
  131. void SHA1Input( SHA1Context *context,
  132. const uint8_t *message_array,
  133. unsigned length)
  134. {
  135. while(length--)
  136. {
  137. context->Message_Block[context->Message_Block_Index++] =(*message_array & 0xFF);
  138. context->Length_Low += 8;
  139. if (context->Length_Low == 0)
  140. {
  141. context->Length_High++;
  142. DNASSERT(context->Length_High!=0);
  143. }
  144. if (context->Message_Block_Index == 64)
  145. {
  146. SHA1ProcessMessageBlock(context);
  147. }
  148. message_array++;
  149. }
  150. }
  151. /*
  152. * SHA1ProcessMessageBlock
  153. *
  154. * Description:
  155. * This function will process the next 512 bits of the message
  156. * stored in the Message_Block array.
  157. *
  158. * Parameters:
  159. * None.
  160. *
  161. * Returns:
  162. * Nothing.
  163. *
  164. * Comments:
  165. * Many of the variable names in this code, especially the
  166. * single character names, were used because those were the
  167. * names used in the publication.
  168. *
  169. *
  170. */
  171. void SHA1ProcessMessageBlock(SHA1Context *context)
  172. {
  173. const uint32_t K[] = { /* Constants defined in SHA-1 */
  174. 0x5A827999,
  175. 0x6ED9EBA1,
  176. 0x8F1BBCDC,
  177. 0xCA62C1D6
  178. };
  179. int t; /* Loop counter */
  180. uint32_t temp; /* Temporary word value */
  181. uint32_t W[80]; /* Word sequence */
  182. uint32_t A, B, C, D, E; /* Word buffers */
  183. /*
  184. * Initialize the first 16 words in the array W
  185. */
  186. for(t = 0; t < 16; t++)
  187. {
  188. W[t] = context->Message_Block[t * 4] << 24;
  189. W[t] |= context->Message_Block[t * 4 + 1] << 16;
  190. W[t] |= context->Message_Block[t * 4 + 2] << 8;
  191. W[t] |= context->Message_Block[t * 4 + 3];
  192. }
  193. for(t = 16; t < 80; t++)
  194. {
  195. W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]);
  196. }
  197. A = context->Intermediate_Hash[0];
  198. B = context->Intermediate_Hash[1];
  199. C = context->Intermediate_Hash[2];
  200. D = context->Intermediate_Hash[3];
  201. E = context->Intermediate_Hash[4];
  202. for(t = 0; t < 20; t++)
  203. {
  204. temp = SHA1CircularShift(5,A) +
  205. ((B & C) | ((~B) & D)) + E + W[t] + K[0];
  206. E = D;
  207. D = C;
  208. C = SHA1CircularShift(30,B);
  209. B = A;
  210. A = temp;
  211. }
  212. for(t = 20; t < 40; t++)
  213. {
  214. temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1];
  215. E = D;
  216. D = C;
  217. C = SHA1CircularShift(30,B);
  218. B = A;
  219. A = temp;
  220. }
  221. for(t = 40; t < 60; t++)
  222. {
  223. temp = SHA1CircularShift(5,A) +
  224. ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2];
  225. E = D;
  226. D = C;
  227. C = SHA1CircularShift(30,B);
  228. B = A;
  229. A = temp;
  230. }
  231. for(t = 60; t < 80; t++)
  232. {
  233. temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3];
  234. E = D;
  235. D = C;
  236. C = SHA1CircularShift(30,B);
  237. B = A;
  238. A = temp;
  239. }
  240. context->Intermediate_Hash[0] += A;
  241. context->Intermediate_Hash[1] += B;
  242. context->Intermediate_Hash[2] += C;
  243. context->Intermediate_Hash[3] += D;
  244. context->Intermediate_Hash[4] += E;
  245. context->Message_Block_Index = 0;
  246. }
  247. /*
  248. * SHA1PadMessage
  249. *
  250. * Description:
  251. * According to the standard, the message must be padded to an even
  252. * 512 bits. The first padding bit must be a '1'. The last 64
  253. * bits represent the length of the original message. All bits in
  254. * between should be 0. This function will pad the message
  255. * according to those rules by filling the Message_Block array
  256. * accordingly. It will also call the ProcessMessageBlock function
  257. * provided appropriately. When it returns, it can be assumed that
  258. * the message digest has been computed.
  259. *
  260. * Parameters:
  261. * context: [in/out]
  262. * The context to pad
  263. * ProcessMessageBlock: [in]
  264. * The appropriate SHA*ProcessMessageBlock function
  265. * Returns:
  266. * Nothing.
  267. *
  268. */
  269. void SHA1PadMessage(SHA1Context *context)
  270. {
  271. /*
  272. * Check to see if the current message block is too small to hold
  273. * the initial padding bits and length. If so, we will pad the
  274. * block, process it, and then continue padding into a second
  275. * block.
  276. */
  277. if (context->Message_Block_Index > 55)
  278. {
  279. context->Message_Block[context->Message_Block_Index++] = 0x80;
  280. while(context->Message_Block_Index < 64)
  281. {
  282. context->Message_Block[context->Message_Block_Index++] = 0;
  283. }
  284. SHA1ProcessMessageBlock(context);
  285. while(context->Message_Block_Index < 56)
  286. {
  287. context->Message_Block[context->Message_Block_Index++] = 0;
  288. }
  289. }
  290. else
  291. {
  292. context->Message_Block[context->Message_Block_Index++] = 0x80;
  293. while(context->Message_Block_Index < 56)
  294. {
  295. context->Message_Block[context->Message_Block_Index++] = 0;
  296. }
  297. }
  298. /*
  299. * Store the message length as the last 8 octets
  300. */
  301. context->Message_Block[56] = (uint8_t ) (context->Length_High >> 24);
  302. context->Message_Block[57] = (uint8_t ) (context->Length_High >> 16);
  303. context->Message_Block[58] = (uint8_t ) (context->Length_High >> 8);
  304. context->Message_Block[59] = (uint8_t ) (context->Length_High);
  305. context->Message_Block[60] = (uint8_t ) (context->Length_Low >> 24);
  306. context->Message_Block[61] = (uint8_t ) (context->Length_Low >> 16);
  307. context->Message_Block[62] = (uint8_t ) (context->Length_Low >> 8);
  308. context->Message_Block[63] = (uint8_t ) (context->Length_Low);
  309. SHA1ProcessMessageBlock(context);
  310. }
  311. /*
  312. ** Above was all standard SHA1 hash code taken from RFC 3174
  313. **********************************************************************************************/
  314. union HashResult
  315. {
  316. //all 160 bits of the result
  317. uint8_t val_160[SHA1HashSize];
  318. //the first 64 bits of the result
  319. ULONGLONG val_64;
  320. };
  321. /*
  322. ** Generate Connect Signature
  323. **
  324. ** This takes a session identity, an address hash, and a connect secret and hashes them together to create
  325. ** a signature we can pass back to a connecting host that it can use to identify itself
  326. */
  327. #undef DPF_MODNAME
  328. #define DPF_MODNAME "GenerateConnectSig"
  329. ULONGLONG GenerateConnectSig(DWORD dwSessID, DWORD dwAddressHash, ULONGLONG ullConnectSecret)
  330. {
  331. //arrange all the supplied input parameters into a single data block
  332. struct InputBuffer
  333. {
  334. DWORD dwSessID;
  335. DWORD dwAddressHash;
  336. ULONGLONG ullConnectSecret;
  337. } inputData = { dwSessID, dwAddressHash, ullConnectSecret };
  338. HashResult result;
  339. SHA1Context context;
  340. //create a context for the hash and add in the input data
  341. SHA1Reset(&context);
  342. SHA1Input(&context, (const uint8_t * ) &inputData, sizeof(inputData));
  343. //get result of the hash and return the first 64 bits as the result
  344. SHA1Result(&context, result.val_160);
  345. DPFX(DPFPREP, 7, "Connect Sig %x-%x", DPFX_OUTPUT_ULL(result.val_64));
  346. return result.val_64;
  347. }
  348. #undef DPF_MODNAME
  349. #define DPF_MODNAME "GenerateOutgoingFrameSig"
  350. ULONGLONG GenerateOutgoingFrameSig(PFMD pFMD, ULONGLONG ullSecret)
  351. {
  352. SHA1Context context;
  353. HashResult result;
  354. BUFFERDESC * pBuffers=pFMD->SendDataBlock.pBuffers;
  355. //create context for hash and then iterate over all the frames we're going to send
  356. SHA1Reset(&context);
  357. for (DWORD dwLoop=0; dwLoop<pFMD->SendDataBlock.dwBufferCount; dwLoop++)
  358. {
  359. SHA1Input(&context, (const uint8_t * ) pBuffers[dwLoop].pBufferData, pBuffers[dwLoop].dwBufferSize);
  360. }
  361. //also hash in our secret, and return the first 64 bits of the result
  362. SHA1Input(&context, (const uint8_t * ) &ullSecret, sizeof(ullSecret));
  363. SHA1Result(&context, result.val_160);
  364. DPFX(DPFPREP, 7, "Outgoing Frame Sig %x-%x", DPFX_OUTPUT_ULL(result.val_64));
  365. return result.val_64;
  366. }
  367. #undef DPF_MODNAME
  368. #define DPF_MODNAME "GenerateIncomingFrameSig"
  369. ULONGLONG GenerateIncomingFrameSig(BYTE * pbyFrame, DWORD dwFrameSize, ULONGLONG ullSecret)
  370. {
  371. SHA1Context context;
  372. HashResult result;
  373. //create context for hash and add in packet data followed by the secret
  374. SHA1Reset(&context);
  375. SHA1Input(&context, (const uint8_t * ) pbyFrame, dwFrameSize);
  376. SHA1Input(&context, (const uint8_t * ) &ullSecret, sizeof(ullSecret));
  377. //get result of hash and return its first 64 bits as the result
  378. SHA1Result(&context, result.val_160);
  379. DPFX(DPFPREP, 7, "Incoming Frame Sig %x-%x", DPFX_OUTPUT_ULL(result.val_64));
  380. return result.val_64;
  381. }
  382. #undef DPF_MODNAME
  383. #define DPF_MODNAME "GenerateNewSecret"
  384. ULONGLONG GenerateNewSecret(ULONGLONG ullCurrentSecret, ULONGLONG ullSecretModifier)
  385. {
  386. SHA1Context context;
  387. HashResult result;
  388. //create context for hash and combine secret followed by modifier
  389. SHA1Reset(&context);
  390. SHA1Input(&context, (const uint8_t * ) &ullCurrentSecret, sizeof(ullCurrentSecret));
  391. SHA1Input(&context, (const uint8_t * ) &ullSecretModifier, sizeof(ullSecretModifier));
  392. //get result and return first 64 bits as the result
  393. SHA1Result(&context, result.val_160);
  394. DPFX(DPFPREP, 5, "Combined current secret %x-%x with modifier %x-%x to create new secret %x-%x",
  395. DPFX_OUTPUT_ULL(ullCurrentSecret), DPFX_OUTPUT_ULL(ullSecretModifier), DPFX_OUTPUT_ULL(result.val_64));
  396. return result.val_64;
  397. }
  398. #undef DPF_MODNAME
  399. #define DPF_MODNAME "GenerateRemoteSecretModifier"
  400. ULONGLONG GenerateRemoteSecretModifier(BYTE * pbyData, DWORD dwDataSize)
  401. {
  402. SHA1Context context;
  403. HashResult result;
  404. //create context for hash and hash supplied data
  405. SHA1Reset(&context);
  406. SHA1Input(&context, (const uint8_t * ) pbyData, dwDataSize);
  407. //get result and return first 64 bits as the result
  408. SHA1Result(&context, result.val_160);
  409. DPFX(DPFPREP, 5, "New Remote Secret Modifier %x-%x", DPFX_OUTPUT_ULL(result.val_64));
  410. return result.val_64;
  411. }
  412. #undef DPF_MODNAME
  413. #define DPF_MODNAME "GenerateLocalSecretModifier"
  414. ULONGLONG GenerateLocalSecretModifier(BUFFERDESC * pBuffers, DWORD dwNumBuffers)
  415. {
  416. SHA1Context context;
  417. HashResult result;
  418. //create context for hash and hash supplied data
  419. SHA1Reset(&context);
  420. for (DWORD dwLoop=0; dwLoop<dwNumBuffers; dwLoop++)
  421. {
  422. SHA1Input(&context, (const uint8_t * ) pBuffers[dwLoop].pBufferData, pBuffers[dwLoop].dwBufferSize);
  423. }
  424. //get result and return first 64 bits as the result
  425. SHA1Result(&context, result.val_160);
  426. DPFX(DPFPREP, 5, "New Local Secret Modifier %x-%x", DPFX_OUTPUT_ULL(result.val_64));
  427. return result.val_64;
  428. }