| /* | 
 |  * Copyright (C) 2001 Nikos Mavroyanopoulos | 
 |  * Copyright (C) 2004 Hans Leidekker | 
 |  * | 
 |  * This library is free software; you can redistribute it and/or | 
 |  * modify it under the terms of the GNU Lesser General Public | 
 |  * License as published by the Free Software Foundation; either | 
 |  * version 2.1 of the License, or (at your option) any later version. | 
 |  * | 
 |  * This library is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
 |  * Lesser General Public License for more details. | 
 |  * | 
 |  * You should have received a copy of the GNU Lesser General Public | 
 |  * License along with this library; if not, write to the Free Software | 
 |  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
 |  */ | 
 |  | 
 | /* | 
 |  * This code implements the MD4 message-digest algorithm. | 
 |  * It is based on code in the public domain written by Colin | 
 |  * Plumb in 1993. The algorithm is due to Ron Rivest. | 
 |  * | 
 |  * Equivalent code is available from RSA Data Security, Inc. | 
 |  * This code has been tested against that, and is equivalent, | 
 |  * except that you don't need to include two pages of legalese | 
 |  * with every copy. | 
 |  * | 
 |  * To compute the message digest of a chunk of bytes, declare an | 
 |  * MD4_CTX structure, pass it to MD4Init, call MD4Update as | 
 |  * needed on buffers full of bytes, and then call MD4Final, which | 
 |  * will fill a supplied 16-byte array with the digest. | 
 |  */ | 
 |  | 
 | #include <stdarg.h> | 
 |  | 
 | #include "ntstatus.h" | 
 | #define WIN32_NO_STATUS | 
 | #include "windef.h" | 
 | #include "winternl.h" | 
 |  | 
 | typedef struct | 
 | { | 
 |     unsigned int buf[4]; | 
 |     unsigned int i[2]; | 
 |     unsigned char in[64]; | 
 |     unsigned char digest[16]; | 
 | } MD4_CTX; | 
 |  | 
 | static void MD4Transform( unsigned int buf[4], unsigned int const in[16] ); | 
 |  | 
 | /* | 
 |  * Note: this code is harmless on little-endian machines. | 
 |  */ | 
 | static void byteReverse( unsigned char *buf, unsigned longs ) | 
 | { | 
 |     unsigned int t; | 
 |  | 
 |     do { | 
 |         t = ((unsigned)buf[3] << 8 | buf[2]) << 16 | | 
 |             ((unsigned)buf[1] << 8 | buf[0]); | 
 |         *(unsigned int *)buf = t; | 
 |         buf += 4; | 
 |     } while (--longs); | 
 | } | 
 |  | 
 | /* | 
 |  * Start MD4 accumulation.  Set bit count to 0 and buffer to mysterious | 
 |  * initialization constants. | 
 |  */ | 
 | VOID WINAPI MD4Init( MD4_CTX *ctx ) | 
 | { | 
 |     ctx->buf[0] = 0x67452301; | 
 |     ctx->buf[1] = 0xefcdab89; | 
 |     ctx->buf[2] = 0x98badcfe; | 
 |     ctx->buf[3] = 0x10325476; | 
 |  | 
 |     ctx->i[0] = ctx->i[1] = 0; | 
 | } | 
 |  | 
 | /* | 
 |  * Update context to reflect the concatenation of another buffer full | 
 |  * of bytes. | 
 |  */ | 
 | VOID WINAPI MD4Update( MD4_CTX *ctx, const unsigned char *buf, unsigned int len ) | 
 | { | 
 |     register unsigned int t; | 
 |  | 
 |     /* Update bitcount */ | 
 |     t = ctx->i[0]; | 
 |  | 
 |     if ((ctx->i[0] = t + (len << 3)) < t) | 
 |         ctx->i[1]++;        /* Carry from low to high */ | 
 |  | 
 |     ctx->i[1] += len >> 29; | 
 |     t = (t >> 3) & 0x3f; | 
 |  | 
 |     /* Handle any leading odd-sized chunks */ | 
 |     if (t) | 
 |     { | 
 |         unsigned char *p = (unsigned char *)ctx->in + t; | 
 |         t = 64 - t; | 
 |  | 
 |         if (len < t) | 
 |         { | 
 |             memcpy( p, buf, len ); | 
 |             return; | 
 |         } | 
 |  | 
 |         memcpy( p, buf, t ); | 
 |         byteReverse( ctx->in, 16 ); | 
 |  | 
 |         MD4Transform( ctx->buf, (unsigned int *)ctx->in ); | 
 |  | 
 |         buf += t; | 
 |         len -= t; | 
 |     } | 
 |  | 
 |     /* Process data in 64-byte chunks */ | 
 |     while (len >= 64) | 
 |     { | 
 |         memcpy( ctx->in, buf, 64 ); | 
 |         byteReverse( ctx->in, 16 ); | 
 |  | 
 |         MD4Transform( ctx->buf, (unsigned int *)ctx->in ); | 
 |  | 
 |         buf += 64; | 
 |         len -= 64; | 
 |     } | 
 |  | 
 |     /* Handle any remaining bytes of data. */ | 
 |     memcpy( ctx->in, buf, len ); | 
 | } | 
 |  | 
 | /* | 
 |  * Final wrapup - pad to 64-byte boundary with the bit pattern  | 
 |  * 1 0* (64-bit count of bits processed, MSB-first) | 
 |  */ | 
 | VOID WINAPI MD4Final( MD4_CTX *ctx ) | 
 | { | 
 |     unsigned int count; | 
 |     unsigned char *p; | 
 |  | 
 |     /* Compute number of bytes mod 64 */ | 
 |     count = (ctx->i[0] >> 3) & 0x3F; | 
 |  | 
 |     /* Set the first char of padding to 0x80.  This is safe since there is | 
 |        always at least one byte free */ | 
 |     p = ctx->in + count; | 
 |     *p++ = 0x80; | 
 |  | 
 |     /* Bytes of padding needed to make 64 bytes */ | 
 |     count = 64 - 1 - count; | 
 |  | 
 |     /* Pad out to 56 mod 64 */ | 
 |     if (count < 8) | 
 |     { | 
 |         /* Two lots of padding:  Pad the first block to 64 bytes */ | 
 |         memset( p, 0, count ); | 
 |         byteReverse( ctx->in, 16 ); | 
 |         MD4Transform( ctx->buf, (unsigned int *)ctx->in ); | 
 |  | 
 |         /* Now fill the next block with 56 bytes */ | 
 |         memset( ctx->in, 0, 56 ); | 
 |     } | 
 |     else | 
 |     { | 
 |         /* Pad block to 56 bytes */ | 
 |         memset( p, 0, count - 8 ); | 
 |     } | 
 |  | 
 |     byteReverse( ctx->in, 14 ); | 
 |  | 
 |     /* Append length in bits and transform */ | 
 |     ((unsigned int *)ctx->in)[14] = ctx->i[0]; | 
 |     ((unsigned int *)ctx->in)[15] = ctx->i[1]; | 
 |  | 
 |     MD4Transform( ctx->buf, (unsigned int *)ctx->in ); | 
 |     byteReverse( (unsigned char *)ctx->buf, 4 ); | 
 |     memcpy( ctx->digest, ctx->buf, 16 ); | 
 | } | 
 |  | 
 | /* The three core functions */ | 
 |  | 
 | #define rotl32(x,n)  (((x) << ((unsigned int)(n))) | ((x) >> (32 - (unsigned int)(n)))) | 
 |  | 
 | #define F( x, y, z ) (((x) & (y)) | ((~x) & (z))) | 
 | #define G( x, y, z ) (((x) & (y)) | ((x) & (z)) | ((y) & (z))) | 
 | #define H( x, y, z ) ((x) ^ (y) ^ (z)) | 
 |  | 
 | #define FF( a, b, c, d, x, s ) { \ | 
 |     (a) += F( (b), (c), (d) ) + (x); \ | 
 |     (a) = rotl32( (a), (s) ); \ | 
 |   } | 
 | #define GG( a, b, c, d, x, s ) { \ | 
 |     (a) += G( (b), (c), (d) ) + (x) + (unsigned int)0x5a827999; \ | 
 |     (a) = rotl32( (a), (s) ); \ | 
 |   } | 
 | #define HH( a, b, c, d, x, s ) { \ | 
 |     (a) += H( (b), (c), (d) ) + (x) + (unsigned int)0x6ed9eba1; \ | 
 |     (a) = rotl32( (a), (s) ); \ | 
 |   } | 
 |  | 
 | /* | 
 |  * The core of the MD4 algorithm | 
 |  */ | 
 | static void MD4Transform( unsigned int buf[4], const unsigned int in[16] ) | 
 | { | 
 |     register unsigned int a, b, c, d; | 
 |  | 
 |     a = buf[0]; | 
 |     b = buf[1]; | 
 |     c = buf[2]; | 
 |     d = buf[3]; | 
 |  | 
 |     FF( a, b, c, d, in[0], 3 ); | 
 |     FF( d, a, b, c, in[1], 7 ); | 
 |     FF( c, d, a, b, in[2], 11 ); | 
 |     FF( b, c, d, a, in[3], 19 ); | 
 |     FF( a, b, c, d, in[4], 3 ); | 
 |     FF( d, a, b, c, in[5], 7 ); | 
 |     FF( c, d, a, b, in[6], 11 ); | 
 |     FF( b, c, d, a, in[7], 19 ); | 
 |     FF( a, b, c, d, in[8], 3 ); | 
 |     FF( d, a, b, c, in[9], 7 ); | 
 |     FF( c, d, a, b, in[10], 11 ); | 
 |     FF( b, c, d, a, in[11], 19 ); | 
 |     FF( a, b, c, d, in[12], 3 ); | 
 |     FF( d, a, b, c, in[13], 7 ); | 
 |     FF( c, d, a, b, in[14], 11 ); | 
 |     FF( b, c, d, a, in[15], 19 ); | 
 |  | 
 |     GG( a, b, c, d, in[0], 3 ); | 
 |     GG( d, a, b, c, in[4], 5 ); | 
 |     GG( c, d, a, b, in[8], 9 ); | 
 |     GG( b, c, d, a, in[12], 13 ); | 
 |     GG( a, b, c, d, in[1], 3 ); | 
 |     GG( d, a, b, c, in[5], 5 ); | 
 |     GG( c, d, a, b, in[9], 9 ); | 
 |     GG( b, c, d, a, in[13], 13 ); | 
 |     GG( a, b, c, d, in[2], 3 ); | 
 |     GG( d, a, b, c, in[6], 5 ); | 
 |     GG( c, d, a, b, in[10], 9 ); | 
 |     GG( b, c, d, a, in[14], 13 ); | 
 |     GG( a, b, c, d, in[3], 3 ); | 
 |     GG( d, a, b, c, in[7], 5 ); | 
 |     GG( c, d, a, b, in[11], 9 ); | 
 |     GG( b, c, d, a, in[15], 13 ); | 
 |  | 
 |     HH( a, b, c, d, in[0], 3 ); | 
 |     HH( d, a, b, c, in[8], 9 ); | 
 |     HH( c, d, a, b, in[4], 11 ); | 
 |     HH( b, c, d, a, in[12], 15 ); | 
 |     HH( a, b, c, d, in[2], 3 ); | 
 |     HH( d, a, b, c, in[10], 9 ); | 
 |     HH( c, d, a, b, in[6], 11 ); | 
 |     HH( b, c, d, a, in[14], 15 ); | 
 |     HH( a, b, c, d, in[1], 3 ); | 
 |     HH( d, a, b, c, in[9], 9 ); | 
 |     HH( c, d, a, b, in[5], 11 ); | 
 |     HH( b, c, d, a, in[13], 15 ); | 
 |     HH( a, b, c, d, in[3], 3 ); | 
 |     HH( d, a, b, c, in[11], 9 ); | 
 |     HH( c, d, a, b, in[7], 11 ); | 
 |     HH( b, c, d, a, in[15], 15 ); | 
 |  | 
 |     buf[0] += a; | 
 |     buf[1] += b; | 
 |     buf[2] += c; | 
 |     buf[3] += d; | 
 | } | 
 |  | 
 | /****************************************************************************** | 
 |  * SystemFunction007  [ADVAPI32.@] | 
 |  * | 
 |  * MD4 hash a unicode string | 
 |  * | 
 |  * PARAMS | 
 |  *   string  [I] the string to hash | 
 |  *   output  [O] the md4 hash of the string (16 bytes) | 
 |  * | 
 |  * RETURNS | 
 |  *  Success: STATUS_SUCCESS | 
 |  *  Failure: STATUS_UNSUCCESSFUL | 
 |  * | 
 |  */ | 
 | NTSTATUS WINAPI SystemFunction007(const UNICODE_STRING *string, LPBYTE hash) | 
 | { | 
 |     MD4_CTX ctx; | 
 |  | 
 |     MD4Init( &ctx ); | 
 |     MD4Update( &ctx, (const BYTE *)string->Buffer, string->Length ); | 
 |     MD4Final( &ctx ); | 
 |     memcpy( hash, ctx.digest, 0x10 ); | 
 |  | 
 |     return STATUS_SUCCESS; | 
 | } | 
 |  | 
 | /****************************************************************************** | 
 |  * SystemFunction010  [ADVAPI32.@] | 
 |  * SystemFunction011  [ADVAPI32.@] | 
 |  * | 
 |  * MD4 hashes 16 bytes of data | 
 |  * | 
 |  * PARAMS | 
 |  *   unknown []  seems to have no effect on the output | 
 |  *   data    [I] pointer to data to hash (16 bytes) | 
 |  *   output  [O] the md4 hash of the data (16 bytes) | 
 |  * | 
 |  * RETURNS | 
 |  *  Success: STATUS_SUCCESS | 
 |  *  Failure: STATUS_UNSUCCESSFUL | 
 |  * | 
 |  */ | 
 | NTSTATUS WINAPI SystemFunction010(LPVOID unknown, const BYTE *data, LPBYTE hash) | 
 | { | 
 |     MD4_CTX ctx; | 
 |  | 
 |     MD4Init( &ctx ); | 
 |     MD4Update( &ctx, data, 0x10 ); | 
 |     MD4Final( &ctx ); | 
 |     memcpy( hash, ctx.digest, 0x10 ); | 
 |  | 
 |     return STATUS_SUCCESS; | 
 | } |