/*
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#
///
public class MD4
{
// MD4 specific object variables
//-----------------------------------------------------------------------
///
/// The size in bytes of the input block to the transformation algorithm
///
private const int BLOCK_LENGTH = 64; // = 512 / 8
///
/// 4 32-bit words (interim result)
///
private uint[] context = new uint[4];
///
/// Number of bytes procesed so far mod. 2 power of 64.
///
private long count;
///
/// 512-bit input buffer = 16 x 32-bit words holds until it reaches 512 bits
///
private byte[] buffer = new byte[BLOCK_LENGTH];
///
/// 512-bit work buffer = 16 x 32-bit words
///
private uint[] X = new uint[16];
// Constructors
//------------------------------------------------------------------------
public MD4()
{
engineReset(,',',');
}
///
/// This constructor is here to implement the clonability of this class
///
///
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.
///
private void engineReset()
{
// 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 < BLOCK_LENGTH; i++)
{
buffer[i] = 0;
}
}
///
/// Continues an MD4 message digest using the input byte
///
/// byte to input
private void engineUpdate(byte b)
{
// compute number of bytes still unhashed; 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
///
///
/// Continues an MD4 message digest operation by filling the buffer,
/// transform(ing) 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.
///
/// input block
/// start of meaningful bytes in input
/// count of bytes in input blcok to consider
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 unhashed; ie. present in buffer
int bufferNdx = (int)(count % BLOCK_LENGTH,',',');
count += len; // update number of bytes
int partLen = BLOCK_LENGTH - bufferNdx;
int i = 0;
if(len >= partLen)
{
Array.Copy(input, offset + i, buffer, bufferNdx, partLen,',',');
transform(ref buffer, 0,',',');
for(i = partLen; i + BLOCK_LENGTH - 1 < len; i+= BLOCK_LENGTH)
{
transform(ref input, offset + i,',',');
}
bufferNdx = 0;
}
// buffer remaining input
if(i < len)
{
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.
///
///the array of bytes for the resulting hash value.
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
engineReset(,',',');
return result;
}
///
/// Returns a byte hash from a string
///
/// string to hash
///byte-array that contains the hash
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
///
/// byte-array to hash
///binary hash of input
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
///
/// byte-array to input
///String that contains the hex of the hash
public string GetHexHashFromBytes(byte[] b)
{
byte[] e = GetByteHashFromBytes(b,',',');
return bytesToHex(e, e.Length,',',');
}
///
/// Returns a byte hash from the input byte
///
/// byte to hash
///binary hash of the input byte
public byte[] GetByteHashFromByte(byte b)
{
MD4 md4 = new MD4(,',',');
md4.engineUpdate(b,',',');
return md4.engineDigest(,',',');
}
///
/// Returns a string that contains the hexadecimal hash
///
/// byte to hash
///String that contains the hex of the hash
public string GetHexHashFromByte(byte b)
{
byte[] e = GetByteHashFromByte(b,',',');
return bytesToHex(e, e.Length,',',');
}
///
/// Returns a string that contains the hexadecimal hash
///
/// string to hash
///String that contains the hex of the hash
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 should be the final size
for(int i = 0; i < temp.Length ; i++)
{
if(temp[i] != '-')
{
sb.Append(temp[i],',',');
}
}
return sb.ToString(,',',');
}
// own methods
//-----------------------------------------------------------------------------------
///
/// MD4 basic transformation
///
///
/// Transforms context based on 512 bits from input block starting
/// from the offset'th byte.
///
/// input sub-array
/// starting position of sub-array
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
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#
///
public class MD4
{
// MD4 specific object variables
//-----------------------------------------------------------------------
///
/// The size in bytes of the input block to the transformation algorithm
///
private const int BLOCK_LENGTH = 64; // = 512 / 8
///
/// 4 32-bit words (interim result)
///
private uint[] context = new uint[4];
///
/// Number of bytes procesed so far mod. 2 power of 64.
///
private long count;
///
/// 512-bit input buffer = 16 x 32-bit words holds until it reaches 512 bits
///
private byte[] buffer = new byte[BLOCK_LENGTH];
///
/// 512-bit work buffer = 16 x 32-bit words
///
private uint[] X = new uint[16];
// Constructors
//------------------------------------------------------------------------
public MD4()
{
engineReset(,',',');
}
///
/// This constructor is here to implement the clonability of this class
///
///
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.
///
private void engineReset()
{
// 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 < BLOCK_LENGTH; i++)
{
buffer[i] = 0;
}
}
///
/// Continues an MD4 message digest using the input byte
///
/// byte to input
private void engineUpdate(byte b)
{
// compute number of bytes still unhashed; 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
///
///
/// Continues an MD4 message digest operation by filling the buffer,
/// transform(ing) 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.
///
/// input block
/// start of meaningful bytes in input
/// count of bytes in input blcok to consider
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 unhashed; ie. present in buffer
int bufferNdx = (int)(count % BLOCK_LENGTH,',',');
count += len; // update number of bytes
int partLen = BLOCK_LENGTH - bufferNdx;
int i = 0;
if(len >= partLen)
{
Array.Copy(input, offset + i, buffer, bufferNdx, partLen,',',');
transform(ref buffer, 0,',',');
for(i = partLen; i + BLOCK_LENGTH - 1 < len; i+= BLOCK_LENGTH)
{
transform(ref input, offset + i,',',');
}
bufferNdx = 0;
}
// buffer remaining input
if(i < len)
{
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.
///
///
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
engineReset(,',',');
return result;
}
///
/// Returns a byte hash from a string
///
/// string to hash
///
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
///
/// byte-array to hash
///
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
///
/// byte-array to input
///
public string GetHexHashFromBytes(byte[] b)
{
byte[] e = GetByteHashFromBytes(b,',',');
return bytesToHex(e, e.Length,',',');
}
///
/// Returns a byte hash from the input byte
///
/// byte to hash
///
public byte[] GetByteHashFromByte(byte b)
{
MD4 md4 = new MD4(,',',');
md4.engineUpdate(b,',',');
return md4.engineDigest(,',',');
}
///
/// Returns a string that contains the hexadecimal hash
///
/// byte to hash
///
public string GetHexHashFromByte(byte b)
{
byte[] e = GetByteHashFromByte(b,',',');
return bytesToHex(e, e.Length,',',');
}
///
/// Returns a string that contains the hexadecimal hash
///
/// string to hash
///
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 should be the final size
for(int i = 0; i < temp.Length ; i++)
{
if(temp[i] != '-')
{
sb.Append(temp[i],',',');
}
}
return sb.ToString(,',',');
}
// own methods
//-----------------------------------------------------------------------------------
///
/// MD4 basic transformation
///
///
/// Transforms context based on 512 bits from input block starting
/// from the offset'th byte.
///
/// input sub-array
/// starting position of sub-array
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
关键字词: