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.

203 lines
4.5 KiB

  1. // Circular hash code.
  2. //
  3. // This code implements a circular hash algorithm, intended as a variable
  4. // length hash function that is fast to update. (The hash function will be
  5. // called many times.) This is done by SHA-1'ing each of the inputs, then
  6. // circularly XORing this value into a buffer.
  7. #ifndef KMODE_RNG
  8. #include <nt.h>
  9. #include <ntrtl.h>
  10. #include <nturtl.h>
  11. #include <windows.h>
  12. #else
  13. #include <ntifs.h>
  14. #include <windef.h>
  15. #endif // KMODE_RNG
  16. #include <sha.h>
  17. #include <md4.h>
  18. #include "circhash.h"
  19. #ifdef KMODE_RNG
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, InitCircularHash)
  22. #pragma alloc_text(PAGE, DestroyCircularHash)
  23. #pragma alloc_text(PAGE, GetCircularHashValue)
  24. #pragma alloc_text(PAGE, UpdateCircularHash)
  25. #endif // ALLOC_PRAGMA
  26. #endif // KMODE_RNG
  27. //
  28. // internal state flags
  29. //
  30. #define CH_INVALID_HASH_CTXT 0
  31. #define CH_VALID_HASH_CTXT 0x1423
  32. BOOL
  33. InitCircularHash(
  34. IN CircularHash *NewHash,
  35. IN DWORD dwUpdateInc,
  36. IN DWORD dwAlgId,
  37. IN DWORD dwMode
  38. )
  39. {
  40. #ifdef KMODE_RNG
  41. PAGED_CODE();
  42. #endif // KMODE_RNG
  43. if (NULL == NewHash)
  44. return FALSE;
  45. NewHash->dwCircHashVer = CH_VALID_HASH_CTXT;
  46. NewHash->dwCircSize = sizeof(NewHash->CircBuf);
  47. NewHash->dwMode = dwMode;
  48. NewHash->dwCircInc = dwUpdateInc;
  49. NewHash->dwCurCircPos = 0;
  50. NewHash->dwAlgId = dwAlgId;
  51. return TRUE;
  52. }
  53. VOID
  54. DestroyCircularHash(
  55. IN CircularHash *OldHash
  56. )
  57. {
  58. #ifdef KMODE_RNG
  59. PAGED_CODE();
  60. #endif // KMODE_RNG
  61. if ((NULL == OldHash) || (CH_VALID_HASH_CTXT != OldHash->dwCircHashVer))
  62. return;
  63. RtlZeroMemory( OldHash, sizeof( *OldHash ) );
  64. }
  65. BOOL
  66. GetCircularHashValue(
  67. IN CircularHash *CurrentHash,
  68. OUT BYTE **ppbHashValue,
  69. OUT DWORD *pcbHashValue
  70. )
  71. {
  72. #ifdef KMODE_RNG
  73. PAGED_CODE();
  74. #endif // KMODE_RNG
  75. if ((NULL == CurrentHash) || (CH_VALID_HASH_CTXT != CurrentHash->dwCircHashVer))
  76. return FALSE;
  77. *ppbHashValue = CurrentHash->CircBuf;
  78. *pcbHashValue = CurrentHash->dwCircSize;
  79. return TRUE;
  80. }
  81. BOOL
  82. UpdateCircularHash(
  83. IN CircularHash *CurrentHash,
  84. IN VOID *pvData,
  85. IN DWORD cbData
  86. )
  87. {
  88. A_SHA_CTX shaCtx;
  89. MD4_CTX md4Ctx;
  90. BYTE LocalResBuf[A_SHA_DIGEST_LEN];
  91. PBYTE pHash;
  92. DWORD dwHashSize;
  93. DWORD i, j;
  94. PBYTE pbCircularBuffer;
  95. DWORD cbCircularBuffer;
  96. DWORD cbCircularPosition;
  97. #ifdef KMODE_RNG
  98. PAGED_CODE();
  99. #endif // KMODE_RNG
  100. if ((NULL == CurrentHash) || (CH_VALID_HASH_CTXT != CurrentHash->dwCircHashVer))
  101. return FALSE;
  102. pbCircularBuffer = CurrentHash->CircBuf;
  103. cbCircularBuffer = CurrentHash->dwCircSize;
  104. cbCircularPosition = CurrentHash->dwCurCircPos;
  105. //
  106. // First, hash in the result
  107. //
  108. if( CurrentHash->dwAlgId == CH_ALG_MD4 ) {
  109. dwHashSize = MD4DIGESTLEN;
  110. MD4Init(&md4Ctx);
  111. MD4Update(&md4Ctx, (unsigned char*)pvData, cbData);
  112. if (CurrentHash->dwMode & CH_MODE_FEEDBACK)
  113. {
  114. MD4Update(&md4Ctx, pbCircularBuffer, cbCircularBuffer);
  115. }
  116. MD4Final(&md4Ctx);
  117. pHash = md4Ctx.digest;
  118. } else {
  119. dwHashSize = A_SHA_DIGEST_LEN;
  120. A_SHAInit(&shaCtx);
  121. A_SHAUpdateNS(&shaCtx, (unsigned char*)pvData, cbData);
  122. if (CurrentHash->dwMode & CH_MODE_FEEDBACK)
  123. {
  124. A_SHAUpdateNS(&shaCtx, pbCircularBuffer, cbCircularBuffer);
  125. }
  126. A_SHAFinalNS(&shaCtx, LocalResBuf);
  127. pHash = LocalResBuf;
  128. }
  129. //
  130. // Now, XOR this into the circular buffer
  131. //
  132. //
  133. // this is a slow way of doing this (byte at time, versus DWORD/DWORD64),
  134. // but it'll work for now...
  135. // In most cases, we can assume we'll wrap once, but let's keep it general for now.
  136. //
  137. j = cbCircularPosition;
  138. for( i = 0 ; i < dwHashSize ; i++ )
  139. {
  140. if (j >= cbCircularBuffer)
  141. j = 0;
  142. pbCircularBuffer[j] ^= pHash[i];
  143. j++;
  144. }
  145. //
  146. // Update. Since dwCircInc should be relatively prime to dwCircSize, this
  147. // should result in the pointer continually cycling through dwCircSize values.
  148. //
  149. CurrentHash->dwCurCircPos = (cbCircularPosition + CurrentHash->dwCircInc)
  150. % cbCircularBuffer;
  151. return TRUE;
  152. }