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.

460 lines
15 KiB

  1. /* (C) 1997-1998 Microsoft Corp.
  2. *
  3. * CBC64 - 64-bit hashing algorithm
  4. *
  5. * CBC64 is part of a Microsoft Research project to create a fast encryption
  6. * algorithm for the NT5 NTFS-EFS encrypted disk subsystem. Though
  7. * originally intended for encryption use, CBC64 makes a fast hash
  8. * and checksum function with known probabilities for failure and known
  9. * good variability based on input.
  10. *
  11. * CBC64 takes as input four seed values a, b, c, and d. The bits of a and
  12. * c MUST correspond to the coefficients of an irreducible polynomial.
  13. * Associated code (RandomIrreduciblePolynomial(), which is included in this
  14. * file but ifdef-ed out) will take a random number as seed value and
  15. * converge to a usable value (or zero if the seed cannot be converged,
  16. * in which case a new random seed must be tried).
  17. *
  18. * In an encryption context, a, b, c, and d would correspond to "secrets"
  19. * held by the encrypter and decrypter. For our purposes -- use as a hash
  20. * function -- we can simply hardcode all four -- a and c with values from
  21. * RandomIrreduciblePolynomial() on two random numbers, b and d with
  22. * simple random numbers.
  23. *
  24. * For a set of N inputs (e.g. bitmaps) the probability of duplicate hash
  25. * value creation has been proven to be (N^2)/(2^64).
  26. *
  27. * Original algorithm notes:
  28. * From "Chain& Sum primitive and its applications to
  29. * Stream Ciphers and MACs"
  30. * Ramarathnam Venkatesan (Microsoft Research)
  31. * Mariusz Jackubowski (Princeton/MS Research)
  32. *
  33. * To Appear in Advances in Cryptology EuroCrypt 98, Springer Verlag.
  34. * Patent rights being applied for by Microsoft.
  35. *
  36. * Extracted from the algorithm for simulating CBC-Encryption and its
  37. * message integrity properties using much faster stream ciphers. Its
  38. * analysis appears in the above paper.
  39. *
  40. * Algorithm is a MAC with input preprocessing by ((Alpha)x + (Beta))
  41. * mod 2^32, followed by forward (ax + b) and (cx + d) in field GF(2^32).
  42. */
  43. #include "cbchash.h"
  44. #define CBC_a 0xBB40E665
  45. #define CBC_b 0x544B2FBA
  46. #define CBC_c 0xDC3F08DD
  47. #define CBC_d 0x39D589AE
  48. #define CBC_bXORa (CBC_b ^ CBC_a)
  49. #define CBC_dXORc (CBC_d ^ CBC_c)
  50. // For removal of branches in main loop -- over twice as fast as the code
  51. // with branches.
  52. const UINT32 CBC_AB[2] = { CBC_b, CBC_bXORa };
  53. const UINT32 CBC_CD[2] = { CBC_d, CBC_dXORc };
  54. void __fastcall SHCLASS NextCBC64(
  55. CBC64Context *pContext,
  56. UINT32 *pData,
  57. unsigned NumDWORDBlocks)
  58. {
  59. while (NumDWORDBlocks--) {
  60. // Checksum is used to overcome known collision characteristics of
  61. // CBC64. It is a low-tech solution that simply decreases the
  62. // probability of collision where used.
  63. pContext->Checksum += *pData;
  64. pContext->Datum = CBC_RandomOddAlpha * (*pData + pContext->Datum) +
  65. CBC_RandomBeta;
  66. pContext->Key1 ^= pContext->Datum;
  67. pContext->Key1 = (pContext->Key1 << 1) ^
  68. (CBC_CD[(pContext->Key1 & 0x80000000) >> 31]);
  69. pContext->Key2 ^= pContext->Datum;
  70. pContext->Key2 = (pContext->Key2 << 1) ^
  71. (CBC_AB[(pContext->Key2 & 0x80000000) >> 31]);
  72. pData++;
  73. }
  74. }
  75. /*
  76. *
  77. * Support functions for determining irreducible a and c.
  78. *
  79. */
  80. #if 0
  81. // Original CBC64 from which the First()-Next() algorithm was derived.
  82. // Returns the first part of the key value; second key part is last param.
  83. UINT32 __fastcall SHCLASS CBC64(
  84. UINT32 *Data,
  85. unsigned NumDWORDBlocks,
  86. UINT32 *pKey2)
  87. {
  88. int i;
  89. UINT32 abMAC, cdMAC, Datum;
  90. // For removal of branches in main loops -- over twice as fast as the code
  91. // with branches.
  92. const UINT32 AB[2] = { CBC_b, CBC_bXORa };
  93. const UINT32 CD[2] = { CBC_d, CBC_dXORc };
  94. // Block 0.
  95. abMAC = cdMAC = Datum = *Data * CBC_RandomOddAlpha + CBC_RandomBeta;
  96. abMAC = (abMAC << 1) ^ (AB[(cdMAC & 0x80000000) >> 31]);
  97. cdMAC = (cdMAC << 1) ^ (CD[(cdMAC & 0x80000000) >> 31]);
  98. // Blocks 1 through nblocks - 2
  99. i = NumDWORDBlocks - 1;
  100. while (--i) {
  101. Data++;
  102. Datum = CBC_RandomOddAlpha * (*Data + Datum) + CBC_RandomBeta;
  103. cdMAC ^= Datum;
  104. cdMAC = (cdMAC << 1) ^ (CD[(cdMAC & 0x80000000) >> 31]);
  105. abMAC ^= Datum;
  106. abMAC = (abMAC << 1) ^ (AB[(abMAC & 0x80000000) >> 31]);
  107. }
  108. // Last block (nblocks - 1)
  109. Data++;
  110. Datum = CBC_RandomOddAlpha * (*Data + Datum) + CBC_RandomBeta;
  111. cdMAC ^= Datum;
  112. cdMAC = (cdMAC << 1) ^ (CD[(cdMAC & 0x80000000) >> 31]);
  113. abMAC ^= Datum;
  114. *pKey2 = (abMAC << 1) ^ (AB[(abMAC & 0x80000000) >> 31]);
  115. return cdMAC;
  116. }
  117. #include <stdio.h>
  118. #include <string.h>
  119. #include <time.h>
  120. #include <windows.h>
  121. // multiply y by x mod x^32+p
  122. __inline UINT32 Multiply(UINT32 y, UINT32 p)
  123. {
  124. return (y & 0x80000000) ? (y<<1)^p : y<<1;
  125. }
  126. // divide y by x mod x^32+p
  127. __inline UINT32 Divide(UINT32 y, UINT32 p)
  128. {
  129. return (y & 1) ? 0x80000000^((y^p)>>1) : y>>1;
  130. }
  131. // compute (x^32+p) mod qq[i]
  132. __inline UINT32 PolyMod(UINT32 p, UINT32 i)
  133. {
  134. static const UINT32 qq[2]={18<<2, 127};
  135. static const UINT32 rt[2][256] = {
  136. 0,32,8,40,16,48,24,56,32,0,40,8,48,16,56,24,8,40,0,32,
  137. 24,56,16,48,40,8,32,0,56,24,48,16,16,48,24,56,0,32,8,40,
  138. 48,16,56,24,32,0,40,8,24,56,16,48,8,40,0,32,56,24,48,16,
  139. 40,8,32,0,32,0,40,8,48,16,56,24,0,32,8,40,16,48,24,56,
  140. 40,8,32,0,56,24,48,16,8,40,0,32,24,56,16,48,48,16,56,24,
  141. 32,0,40,8,16,48,24,56,0,32,8,40,56,24,48,16,40,8,32,0,
  142. 24,56,16,48,8,40,0,32,8,40,0,32,24,56,16,48,40,8,32,0,
  143. 56,24,48,16,0,32,8,40,16,48,24,56,32,0,40,8,48,16,56,24,
  144. 24,56,16,48,8,40,0,32,56,24,48,16,40,8,32,0,16,48,24,56,
  145. 0,32,8,40,48,16,56,24,32,0,40,8,40,8,32,0,56,24,48,16,
  146. 8,40,0,32,24,56,16,48,32,0,40,8,48,16,56,24,0,32,8,40,
  147. 16,48,24,56,56,24,48,16,40,8,32,0,24,56,16,48,8,40,0,32,
  148. 48,16,56,24,32,0,40,8,16,48,24,56,0,32,8,40,
  149. 0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,
  150. 40,42,44,46,48,50,52,54,56,58,60,62,63,61,59,57,55,53,51,49,
  151. 47,45,43,41,39,37,35,33,31,29,27,25,23,21,19,17,15,13,11,9,
  152. 7,5,3,1,1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,
  153. 33,35,37,39,41,43,45,47,49,51,53,55,57,59,61,63,62,60,58,56,
  154. 54,52,50,48,46,44,42,40,38,36,34,32,30,28,26,24,22,20,18,16,
  155. 14,12,10,8,6,4,2,0,2,0,6,4,10,8,14,12,18,16,22,20,
  156. 26,24,30,28,34,32,38,36,42,40,46,44,50,48,54,52,58,56,62,60,
  157. 61,63,57,59,53,55,49,51,45,47,41,43,37,39,33,35,29,31,25,27,
  158. 21,23,17,19,13,15,9,11,5,7,1,3,3,1,7,5,11,9,15,13,
  159. 19,17,23,21,27,25,31,29,35,33,39,37,43,41,47,45,51,49,55,53,
  160. 59,57,63,61,60,62,56,58,52,54,48,50,44,46,40,42,36,38,32,34,
  161. 28,30,24,26,20,22,16,18,12,14,8,10,4,6,0,2};
  162. p ^= qq[i]<<(32-6);
  163. p ^= rt[i][p>>24]<<16;
  164. p ^= rt[i][(p>>16)&0xff]<<8;
  165. p ^= rt[i][(p>>8)&0xff];
  166. if (p&(1<<7))
  167. p ^= qq[i]<<1;
  168. if (p&(1<<6))
  169. p ^= qq[i];
  170. return p % (1<<6);
  171. }
  172. // do an analogue of Fermat test on x^32+p
  173. BOOL Irreducible(UINT32 p)
  174. {
  175. static const UINT32 expand[256] = {
  176. 0x0, 0x1, 0x4, 0x5, 0x10, 0x11, 0x14, 0x15,
  177. 0x40, 0x41, 0x44, 0x45, 0x50, 0x51, 0x54, 0x55,
  178. 0x100, 0x101, 0x104, 0x105, 0x110, 0x111, 0x114, 0x115,
  179. 0x140, 0x141, 0x144, 0x145, 0x150, 0x151, 0x154, 0x155,
  180. 0x400, 0x401, 0x404, 0x405, 0x410, 0x411, 0x414, 0x415,
  181. 0x440, 0x441, 0x444, 0x445, 0x450, 0x451, 0x454, 0x455,
  182. 0x500, 0x501, 0x504, 0x505, 0x510, 0x511, 0x514, 0x515,
  183. 0x540, 0x541, 0x544, 0x545, 0x550, 0x551, 0x554, 0x555,
  184. 0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
  185. 0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
  186. 0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
  187. 0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
  188. 0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
  189. 0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
  190. 0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
  191. 0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
  192. 0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
  193. 0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
  194. 0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
  195. 0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
  196. 0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
  197. 0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
  198. 0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
  199. 0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
  200. 0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
  201. 0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
  202. 0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
  203. 0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
  204. 0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
  205. 0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
  206. 0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
  207. 0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555};
  208. // tables used for fast squaring
  209. UINT32 pp[4], ph[16], pl[4][16];
  210. UINT32 g, v;
  211. int i;
  212. pp[0] = 0;
  213. pp[1] = p;
  214. if (p&0x80000000)
  215. {
  216. pp[2] = p ^ (p<<1);
  217. pp[3] = p<<1;
  218. }
  219. else
  220. {
  221. pp[2] = p<<1;
  222. pp[3] = p ^ (p<<1);
  223. }
  224. v = 0x40000000;
  225. for (i=0; i<16; i++)
  226. ph[i] = v = (v<<2) ^ pp[v >> 30];
  227. for (i=0; i<4; i++)
  228. {
  229. pl[i][0] = 0;
  230. pl[i][1] = ph[4*i+0];
  231. pl[i][2] = ph[4*i+1];
  232. pl[i][3] = ph[4*i+0] ^ ph[4*i+1];
  233. pl[i][4] = ph[4*i+2];
  234. pl[i][5] = ph[4*i+2] ^ ph[4*i+0];
  235. pl[i][6] = ph[4*i+2] ^ ph[4*i+1];
  236. pl[i][7] = pl[i][5] ^ ph[4*i+1];
  237. pl[i][8] = ph[4*i+3];
  238. pl[i][9] = ph[4*i+3] ^ ph[4*i+0];
  239. pl[i][10] = ph[4*i+3] ^ ph[4*i+1];
  240. pl[i][11] = pl[i][9] ^ ph[4*i+1];
  241. pl[i][12] = ph[4*i+3] ^ ph[4*i+2];
  242. pl[i][13] = pl[i][12] ^ ph[4*i+0];
  243. pl[i][14] = pl[i][10] ^ ph[4*i+2];
  244. pl[i][15] = pl[i][14] ^ ph[4*i+0];
  245. }
  246. // compute x^(2^16) mod x^32+p
  247. // x^32 mod x^32+p = p
  248. g = p;
  249. // square g
  250. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  251. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^ pl[3][(g>>28)&0xf];
  252. // square g 10 more times to get x^(2^16)
  253. for (i=0; i<2; i++)
  254. {
  255. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  256. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^ pl[3][(g>>28)&0xf];
  257. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  258. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^ pl[3][(g>>28)&0xf];
  259. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  260. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^ pl[3][(g>>28)&0xf];
  261. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  262. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^ pl[3][(g>>28)&0xf];
  263. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  264. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^ pl[3][(g>>28)&0xf];
  265. }
  266. // if x^(2^16) mod x^32+p = x then x^32+p has a divisor whose degree is a power of 2
  267. if (g==2)
  268. return FALSE;
  269. // compute x^(2^32) mod x^32+p
  270. for (i=0; i<4; i++)
  271. {
  272. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  273. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^
  274. pl[3][(g>>28)&0xf];
  275. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  276. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^
  277. pl[3][(g>>28)&0xf];
  278. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  279. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^
  280. pl[3][(g>>28)&0xf];
  281. g = expand[g&0xff] ^ (expand[(g>>8)&0xff]<<16) ^
  282. pl[0][(g>>16)&0xf] ^ pl[1][(g>>20)&0xf] ^ pl[2][(g>>24)&0xf] ^
  283. pl[3][(g>>28)&0xf];
  284. }
  285. // x^32+p is irreducible iff x^(2^16) mod x^32+p != x and
  286. // x^(2^32) mod x^32+p = x
  287. return (g == 2);
  288. }
  289. // Take as input a random 32-bit value
  290. // If successful, output is the lowest 32 bits of a degree 32 irreducible
  291. // polynomial otherwise output is 0, in which case try again with a different
  292. // random input.
  293. UINT32 RandomIrreduciblePolynomial(UINT32 p)
  294. {
  295. #define interval (1 << 6)
  296. BYTE sieve[interval];
  297. UINT32 r;
  298. int i;
  299. memset(sieve, 0, interval);
  300. p ^= p % interval;
  301. r = PolyMod(p, 0);
  302. sieve[r] = 1;
  303. sieve[r^3] = 1;
  304. sieve[r^5] = 1;
  305. sieve[r^15] = 1;
  306. sieve[r^9] = 1;
  307. sieve[r^27] = 1;
  308. sieve[r^29] = 1;
  309. sieve[r^23] = 1;
  310. sieve[r^17] = 1;
  311. sieve[r^51] = 1;
  312. sieve[r^53] = 1;
  313. sieve[r^63] = 1;
  314. sieve[r^57] = 1;
  315. sieve[r^43] = 1;
  316. sieve[r^45] = 1;
  317. sieve[r^39] = 1;
  318. sieve[r^33] = 1;
  319. sieve[r^7] = 1;
  320. sieve[r^21] = 1;
  321. sieve[r^49] = 1;
  322. sieve[r^35] = 1;
  323. r = PolyMod(p, 1);
  324. sieve[r] = 1;
  325. sieve[r^11] = 1;
  326. sieve[r^22] = 1;
  327. sieve[r^29] = 1;
  328. sieve[r^44] = 1;
  329. sieve[r^39] = 1;
  330. sieve[r^58] = 1;
  331. sieve[r^49] = 1;
  332. sieve[r^13] = 1;
  333. sieve[r^26] = 1;
  334. sieve[r^23] = 1;
  335. sieve[r^52] = 1;
  336. sieve[r^57] = 1;
  337. sieve[r^46] = 1;
  338. sieve[r^35] = 1;
  339. for (i=1; i<interval; i+=2)
  340. if (sieve[i]==0 && Irreducible(p^i) )
  341. return p^i;
  342. return 0;
  343. }
  344. // 16x2 similar bitmaps that come up with same CBC64 (error condition).
  345. DWORD FailData[2][8] =
  346. {
  347. { 0x00000010, 0x00000010, 0x00000001, 0x00000010,
  348. 0x61AA61AA, 0x61AA61AA, 0x6161AA61, 0xAAAA61AA },
  349. { 0x00000010, 0x00000010, 0x00000001, 0x00000010,
  350. 0x6AAA61AA, 0x61AA61AA, 0x6161AA61, 0x6AAA61AA }
  351. };
  352. int __cdecl main()
  353. {
  354. enum { LEN = 512 };
  355. enum { REPS = 1000 };
  356. UINT32 X[LEN+1];
  357. UINT32 i;
  358. UINT32 Key2;
  359. double start1, end1, speed1;
  360. for (i=0; i<LEN; X[i++]=i*486248); //junk data //
  361. // initialize the variables a,b,c,d
  362. // This has to be done only once
  363. // a = RandomIrreduciblePolynomial(CBC_a);
  364. // c = RandomIrreduciblePolynomial(CBC_c);
  365. // Make sure these numbers are not zero; if not
  366. // Call the routine Random...polynomial() with different seed
  367. printf("a = %X, c = %X \n", RandomIrreduciblePolynomial(CBC_a),
  368. RandomIrreduciblePolynomial(CBC_c));
  369. // b = CBC_b; //put in some random number
  370. // d = CBC_d; // put in some random number
  371. printf("begin macing\n");
  372. start1=clock();
  373. for (i=0; i<REPS; i++)
  374. CBC64(X, LEN, &Key2);
  375. end1=clock();
  376. printf("end macing \n");
  377. speed1 = 32 * LEN * REPS / ((double) (end1 - start1)/CLOCKS_PER_SEC);
  378. printf("MAC speed:%4.0lf\n %", speed1);
  379. printf(" start1= %d end1= %d \n ", start1, end1);
  380. scanf ("%d", &Key2); /* just hang so that I can see the output */
  381. return 0;
  382. }
  383. #endif // 0