/ *
CopyRight 2002 Blood (Eaststarbuy@sina.com)
This Code is Ported from Norbert Hranitzky's
(Norbert.hranitzky@mchp.siemens.de)
Java Version.
* /
// Reference Namespace
Using system;
Using system.text;
Namespace blood.com.security
{
///
/// Implements the MD4 Message Digest Algorithm in C #
/// summary>
Public Class MD4
{
// MD4 Specific Object Variables
/ / -------------------------------------------------------------------------------------------- -----------------------
///
//// The size in bytes of the input block to the transformation algorithm
/// summary>
Private const Int block_length = 64; // = 512/8
///
/// 4 32-Bit Words (Interim Result)
/// summary>
Private uint [] context = new uint [4];
///
/// Number of Bytes Proced So Far Mod. 2 Power Of 64.
/// summary>
PRIVATE long count;
///
/// 512-bit infut buffer = 16 x 32-Bit Words Holds Until It Reaches 512 BITS
/// summary>
Private Byte [] buffer = new byte [block_length];
///
/// 512-bit work buffer = 16 x 32-Bit Words
/// summary>
Private uint [] x = new uint [16];
// conntructors
/ / -------------------------------------------------------------------------------------------- ---------------------------------------------------------------------------------------------------------------------------------------
Public MD4 ()
{
Engineeren ();
}
///
/// this constructor is here to mailment theclonability of this class
/// summary>
/// param>
Private MD4 (MD4 MD): this ()
{
// this ();
CONTEXT = (uint []) md.context.clone ();
Buffer = (Byte []) md.buffer.clone ();
Count = md.count;
}
// Clonable Method Implementation
/ / -------------------------------------------------------------------------------------------- ------------------------- Public Object Clone ()
{
Return New MD4 (this);
}
// jce methods
/ / -------------------------------------------------------------------------------------------- -------------------------
///
/// Resets this Object Disregarding Any Temporary Data Present At The
/// Time of the Invocation of this Call.
/// summary>
Private void Engineeset ()
{
// Initial Values of MD4 I.E. A, B, C, D
// AS Per RFC-1320; They Are Low-Order Byte First
CONTEXT [0] = 0x67452301;
Context [1] = 0xefcdab89;
Context [2] = 0x98badcfe;
CONTEXT [3] = 0x10325476;
Count = 0L;
For (int i = 0; i { Buffer [i] = 0; } } /// /// Continues an MD4 Message Digest Using The Input Byte /// summary> /// byte to input param> Private void EngineUpdate (byte b) { // compute number of bytes still unhased; ie. present in buffer INT i = (int) (count% block_length); Count ; // Update Number of Bytes Buffer [i] = B; IF (i == block_length - 1) Transform (REF Buffer, 0); } /// /// md4 block update operation /// summary> /// /// Continues an MD4 Message Digest Operation by Filling The Buffer, /// transform (ion) Data in 512-bit Message Block (s), Updating The Variables /// context and count, and leaving (buffering) THE Remaining bytes in buffer /// for the next update or finish. /// remarks> /// Input block param> /// Start of meaningful bytes in input param> /// count of bytes in input blocok to consider param> private void EngineUpdate (byte [] Input, int offset, int LEN) { // Make Sure We don't Exceed Input's Allocated Size / Length IF (Offset <0 || Len <0 || (long) Offset Len> Input.length) { Throw new argumentOutofrangeException (); } // compute number of bytes still unhased; ie. present in buffer Int bufferndx = (int); COUNT% block_length Count = le; // update number of bytes INT Partlen = block_length - bufferndx; INT i = 0; IF (len> = partlen) { Array.copy (Input, Offset I, Buffer, Bufferndx, Partle); Transform (REF Buffer, 0); For (i = partlen; i block_length - 1 { Transform (Ref INPUT, OFFSET I); } Bufferndx = 0; } // Buffer Remaining Input IF (i { Array.copy (Input, Offset i, Buffer, Bufferndx, Len - i); } } /// /// Completes the Hash Computation by Performing Final Operations Such /// AS Padding. at the return of this engineDigest, The MD Engine IS /// reset. /// summary> /// Private byte [] Enginedigest () { // Pad Output to 56 MOD 64; AS RFC1320 PUTS IT: CONGRUENT TO 448 MOD 512 Int bufferndx = (int); COUNT% block_length INT Padlen = (Bufferndx <56)? (56 - Bufferndx): (120 - Bufferndx); //Padding is always binary 1 FOLLOWED by binary 0's Byte [] tail = new byte [padlen 8]; Tail [0] = (Byte) 0x80; // Append Length Before Final Transform // Save Number of Bits, Casting the long to an array of 8 bytes // Save low-order byte first.for (int i = 0; i <8; i ) { TAIL [Padlen I] = (Byte) ((count * 8) >> (8 * i)); } EngineUpdate (tail, 0, tail.length); Byte [] result = new byte [16]; // Cast this MD4's Context (Array of 4 UINTS) Into an Array of 16 Bytes. For (int i = 0; i <4; i ) { For (int J = 0; j <4; j ) { Result [i * 4 j] = (byte) (Context [i] >> (8 * j)); } } // reset the engine Engineeren (); Return Result; } /// /// Returns a byte hash from a string /// summary> /// String to Hash param> /// Public Byte [] getBytehashfromstring (String s) { Byte [] b = encoding.utf8.getbytes (s); MD4 MD4 = New MD4 (); Md4.EngineUpdate (B, 0, B.Length); Return md4.enginedigest (); } /// /// Returns a binary hash from an input byte array /// summary> /// byte-array to hash param> /// Public Byte [] getBytehashfrombytes (byte [] b) { MD4 MD4 = New MD4 (); Md4.EngineUpdate (B, 0, B.Length); Return md4.enginedigest (); } /// /// Returns a string That Contains the Hexadecimal Hash /// summary> /// byte-array to input param> /// Public string getHexhashfrombytes (byte [] b) { Byte [] E = getBytehashfrombytes (b); Return Bytestohex (E, E.LENGTH); } /// /// Returns a byte hash from the input byte /// summary> /// byte to hash param> /// Public Byte [] getBytehashfrombyte (byte b) { MD4 MD4 = New MD4 (); Md4.EngineUpdate (b); Return md4.enginedigest (); } /// /// Returns a string That Contains the Hexadecimal Hash /// summary> /// byte to hash param> /// Public String GetHexhashfrombyte (Byte B) { Byte [] E = getBytehashfrombyte (b); Return Bytestohex (E, E.LENGTH); } /// /// Returns a string That Contains the Hexadecimal Hash /// summary> /// String to Hash param> /// Public String GetHexHashfromstring (String S) { Byte [] b = getBytehashfromstring (s); Return Bytestohex (B, B.Length); } Private static string bytestohex (byte [] a, int LEN) { String Temp = bitconverter.tostring (a); // We need to remove the dashes That come from the bitconverter Stringbuilder SB = New StringBuilder ((LEN - 2) / 2); // this sale be the final size For (int i = 0; i { IF (Temp [I]! = '-') { Sb.append (Temp [i]); } } Return sb.toString (); } // OWN Methods / / -------------------------------------------------------------------------------------------- ----------------------------------- /// /// md4 Basic Transformation /// summary> /// /// Transforms Context Based on 512 Bits from Input Block Starting /// from the offset'th byte. /// remarks> /// input sub-array param> /// Starting position of sub-array param> Private Void Transform (Ref Byte [] block, int offset { // Decodes 64 bytes from Input Block Into An Array Of 16 32-bit // Entities. Use a as a temp var. For (int i = 0; i <16; i ) { X [i] = ((uint) block [offset ] & 0xff) | ((uint) Block [Offset ] & 0xFF) << 8) | ((uint) Block [Offset ] & 0xFF) << 16) | ((uint) block [offset ] & 0xff) << 24); } Uint a = context [0]; uint b = context [1]; uint c = context [2]; Uint D = context [3]; A = ff (A, B, C, D, X [0], 3); D = ff (D, A, B, C, X [1], 7); C = ff (C, D, A, B, X [2], 11); B = ff (B, C, D, A, X [3], 19); A = ff (A, B, C, D, X [4], 3); D = ff (D, A, B, C, X [5], 7); C = ff (C, D, A, B, X [6], 11); B = ff (B, C, D, A, X [7], 19); A = ff (A, B, C, D, X [8], 3); D = ff (D, A, B, C, X [9], 7); C = ff (C, D, A, B, X [10], 11); B = ff (B, C, D, A, X [11], 19); A = ff (A, B, C, D, X [12], 3); D = ff (D, A, B, C, X [13], 7); C = ff (C, D, A, B, X [14], 11); B = FF (B, C, D, A, X [15], 19); A = GG (A, B, C, D, X [0], 3); D = GG (D, A, B, C, X [4], 5); C = GG (C, D, A, B, X [8], 9); B = GG (B, C, D, A, X [12], 13); A = GG (A, B, C, D, X [1], 3); D = GG (D, A, B, C, X [5], 5); C = GG (C, D, A, B, X [9], 9); B = GG (B, C, D, A, X [13], 13); A = GG (A, B, C, D, X [2], 3); D = GG (D, A, B, C, X [6], 5); C = GG (C, D, A, B, X [10], 9); B = GG (B, C, D, A, X [14], 13); A = GG (A, B, C, D, X [3], 3); D = GG (D, A, B, C, X [7], 5); C = GG (C, D, A, B, X [11], 9); B = GG (B, C, D, A, X [15], 13); A = HH (A, B, C, D, X [0], 3); D = HH (D, A, B, C, X [8], 9); C = HH (C, D, A, B, X [4], 11); B = HH (B, C, D, A, X [12], 15); A = HH (A, B, C, D, X [2], 3); D = HH (D, A, B, C, X [10], 9); C = HH (C, D, A, B, X [6], 11); B = HH (B, C, D, A, X [14], 15); A = HH (A, B, C, D, X [1], 3); D = HH (D, A, B, C, X [9], 9); C = HH (C, D, A, B, X [5], 11); B = HH (B, C, D, A, X [13], 15); A = HH (A, B, C, D, X [3], 3); D = HH (D, A, B, C, X [11], 9); C = HH (C, D, A, B, X [7], 11); B = HH (B, C, D, A, X [15], 15); Context [0] = a; Context [1] = B; Context [2] = C; Context [3] = D; } // The Basic MD4 Atomic Functions. Private uint ff (uint a, uint B, uint C, uint D, uint x, int S) { UINT T = a ((B & C) | (~ B & D)) x; Return T << S | T >> (32 - s); } Private uint GG (Uint A, Uint B, Uint C, Uint D, UINT X, INT S) { UINT T = a ((B & (C | D)) | (C & D)) x 0x5a827999; Return T << S | T >> (32 - s); } Private uint HH (uint a, uint B, uint C, uint D, uint x, int S) { UINT T = A (B ^ c ^ D) x 0x6ed9eba1; Return T << S | T >> (32 - s); } } // Class MD4 } // namespace blood.com.security