204 lines
4.3 KiB
C
204 lines
4.3 KiB
C
|
// Circular hash code.
|
||
|
//
|
||
|
// This code implements a circular hash algorithm, intended as a variable
|
||
|
// length hash function that is fast to update. (The hash function will be
|
||
|
// called many times.) This is done by SHA-1'ing each of the inputs, then
|
||
|
// circularly XORing this value into a buffer.
|
||
|
|
||
|
#ifndef KMODE_RNG
|
||
|
|
||
|
#include <nt.h>
|
||
|
#include <ntrtl.h>
|
||
|
#include <nturtl.h>
|
||
|
#include <windows.h>
|
||
|
|
||
|
#else
|
||
|
|
||
|
#include <ntifs.h>
|
||
|
#include <windef.h>
|
||
|
|
||
|
#endif // KMODE_RNG
|
||
|
|
||
|
#include <sha.h>
|
||
|
#include <md4.h>
|
||
|
|
||
|
#include "circhash.h"
|
||
|
|
||
|
|
||
|
#ifdef KMODE_RNG
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGE, InitCircularHash)
|
||
|
#pragma alloc_text(PAGE, DestroyCircularHash)
|
||
|
#pragma alloc_text(PAGE, GetCircularHashValue)
|
||
|
#pragma alloc_text(PAGE, UpdateCircularHash)
|
||
|
#endif // ALLOC_PRAGMA
|
||
|
#endif // KMODE_RNG
|
||
|
|
||
|
|
||
|
//
|
||
|
// internal state flags
|
||
|
//
|
||
|
|
||
|
#define CH_INVALID_HASH_CTXT 0
|
||
|
#define CH_VALID_HASH_CTXT 0x1423
|
||
|
|
||
|
BOOL
|
||
|
InitCircularHash(
|
||
|
IN CircularHash *NewHash,
|
||
|
IN DWORD dwUpdateInc,
|
||
|
IN DWORD dwAlgId,
|
||
|
IN DWORD dwMode
|
||
|
)
|
||
|
{
|
||
|
|
||
|
#ifdef KMODE_RNG
|
||
|
PAGED_CODE();
|
||
|
#endif // KMODE_RNG
|
||
|
|
||
|
if (NULL == NewHash)
|
||
|
return FALSE;
|
||
|
|
||
|
NewHash->dwCircHashVer = CH_VALID_HASH_CTXT;
|
||
|
NewHash->dwCircSize = sizeof(NewHash->CircBuf);
|
||
|
NewHash->dwMode = dwMode;
|
||
|
NewHash->dwCircInc = dwUpdateInc;
|
||
|
NewHash->dwCurCircPos = 0;
|
||
|
NewHash->dwAlgId = dwAlgId;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DestroyCircularHash(
|
||
|
IN CircularHash *OldHash
|
||
|
)
|
||
|
{
|
||
|
#ifdef KMODE_RNG
|
||
|
PAGED_CODE();
|
||
|
#endif // KMODE_RNG
|
||
|
|
||
|
if ((NULL == OldHash) || (CH_VALID_HASH_CTXT != OldHash->dwCircHashVer))
|
||
|
return;
|
||
|
|
||
|
RtlZeroMemory( OldHash, sizeof( *OldHash ) );
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
GetCircularHashValue(
|
||
|
IN CircularHash *CurrentHash,
|
||
|
OUT BYTE **ppbHashValue,
|
||
|
OUT DWORD *pcbHashValue
|
||
|
)
|
||
|
{
|
||
|
#ifdef KMODE_RNG
|
||
|
PAGED_CODE();
|
||
|
#endif // KMODE_RNG
|
||
|
|
||
|
if ((NULL == CurrentHash) || (CH_VALID_HASH_CTXT != CurrentHash->dwCircHashVer))
|
||
|
return FALSE;
|
||
|
|
||
|
*ppbHashValue = CurrentHash->CircBuf;
|
||
|
*pcbHashValue = CurrentHash->dwCircSize;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
UpdateCircularHash(
|
||
|
IN CircularHash *CurrentHash,
|
||
|
IN VOID *pvData,
|
||
|
IN DWORD cbData
|
||
|
)
|
||
|
{
|
||
|
A_SHA_CTX shaCtx;
|
||
|
MD4_CTX md4Ctx;
|
||
|
BYTE LocalResBuf[A_SHA_DIGEST_LEN];
|
||
|
PBYTE pHash;
|
||
|
DWORD dwHashSize;
|
||
|
DWORD i, j;
|
||
|
|
||
|
PBYTE pbCircularBuffer;
|
||
|
DWORD cbCircularBuffer;
|
||
|
DWORD cbCircularPosition;
|
||
|
|
||
|
#ifdef KMODE_RNG
|
||
|
PAGED_CODE();
|
||
|
#endif // KMODE_RNG
|
||
|
|
||
|
|
||
|
if ((NULL == CurrentHash) || (CH_VALID_HASH_CTXT != CurrentHash->dwCircHashVer))
|
||
|
return FALSE;
|
||
|
|
||
|
pbCircularBuffer = CurrentHash->CircBuf;
|
||
|
cbCircularBuffer = CurrentHash->dwCircSize;
|
||
|
cbCircularPosition = CurrentHash->dwCurCircPos;
|
||
|
|
||
|
//
|
||
|
// First, hash in the result
|
||
|
//
|
||
|
|
||
|
if( CurrentHash->dwAlgId == CH_ALG_MD4 ) {
|
||
|
|
||
|
dwHashSize = MD4DIGESTLEN;
|
||
|
|
||
|
MD4Init(&md4Ctx);
|
||
|
MD4Update(&md4Ctx, (unsigned char*)pvData, cbData);
|
||
|
|
||
|
if (CurrentHash->dwMode & CH_MODE_FEEDBACK)
|
||
|
{
|
||
|
MD4Update(&md4Ctx, pbCircularBuffer, cbCircularBuffer);
|
||
|
}
|
||
|
|
||
|
MD4Final(&md4Ctx);
|
||
|
pHash = md4Ctx.digest;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
dwHashSize = A_SHA_DIGEST_LEN;
|
||
|
|
||
|
A_SHAInit(&shaCtx);
|
||
|
A_SHAUpdateNS(&shaCtx, (unsigned char*)pvData, cbData);
|
||
|
|
||
|
if (CurrentHash->dwMode & CH_MODE_FEEDBACK)
|
||
|
{
|
||
|
A_SHAUpdateNS(&shaCtx, pbCircularBuffer, cbCircularBuffer);
|
||
|
}
|
||
|
|
||
|
A_SHAFinalNS(&shaCtx, LocalResBuf);
|
||
|
pHash = LocalResBuf;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now, XOR this into the circular buffer
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// this is a slow way of doing this (byte at time, versus DWORD/DWORD64),
|
||
|
// but it'll work for now...
|
||
|
// In most cases, we can assume we'll wrap once, but let's keep it general for now.
|
||
|
//
|
||
|
|
||
|
j = cbCircularPosition;
|
||
|
|
||
|
for( i = 0 ; i < dwHashSize ; i++ )
|
||
|
{
|
||
|
if (j >= cbCircularBuffer)
|
||
|
j = 0;
|
||
|
|
||
|
pbCircularBuffer[j] ^= pHash[i];
|
||
|
|
||
|
j++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Update. Since dwCircInc should be relatively prime to dwCircSize, this
|
||
|
// should result in the pointer continually cycling through dwCircSize values.
|
||
|
//
|
||
|
|
||
|
CurrentHash->dwCurCircPos = (cbCircularPosition + CurrentHash->dwCircInc)
|
||
|
% cbCircularBuffer;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|