网站运营seo文章大全提供全面的站长运营经验及seo技术!/*
copyright 2002 blood ([email protected])
this code is ported from norbert hranitzky's
([email protected])
java version.
*/
//reference namespace
using system;
using system.text;
namespace blood.com.security
{
/// <summary>
/// implements the md4 message digest algorithm in c#
/// </summary>
public class md4
{
// md4 specific object variables
//-----------------------------------------------------------------------
/// <summary>
/// the size in bytes of the input block to the transformation algorithm
/// </summary>
private const int block_length = 64; // = 512 / 8
/// <summary>
/// 4 32-bit words (interim result)
/// </summary>
private uint[] context = new uint[4];
/// <summary>
/// number of bytes procesed so far mod. 2 power of 64.
/// </summary>
private long count;
/// <summary>
/// 512-bit input buffer = 16 x 32-bit words holds until it reaches 512 bits
/// </summary>
private byte[] buffer = new byte[block_length];
/// <summary>
/// 512-bit work buffer = 16 x 32-bit words
/// </summary>
private uint[] x = new uint[16];
// constructors
//------------------------------------------------------------------------
public md4()
{
enginereset();
}
/// <summary>
/// this constructor is here to implement the clonability of this class
/// </summary>
/// <param name="md"> </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
//-------------------------------------------------------------------------
/// <summary>
/// resets this object disregarding any temporary data present at the
/// time of the invocation of this call.
/// </summary>
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;
}
}
/// <summary>
/// continues an md4 message digest using the input byte
/// </summary>
/// <param name="b">byte to input</param>
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);
}
/// <summary>
/// md4 block update operation
/// </summary>
/// <remarks>
/// 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.
/// </remarks>
/// <param name="input">input block</param>
/// <param name="offset">start of meaningful bytes in input</param>
/// <param name="len">count of bytes in input blcok 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 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);
}
}
/// <summary>
/// completes the hash computation by performing final operations such
/// as padding. at the return of this enginedigest, the md engine is
/// reset.
/// </summary>
/// <returns>the array of bytes for the resulting hash value.</returns>
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;
}
/// <summary>
/// returns a byte hash from a string
/// </summary>
/// <param name="s">string to hash</param>
/// <returns>byte-array that contains the hash</returns>
public byte[] getbytehashfromstring(string s)
{
byte[] b = encoding.utf8.getbytes(s);
md4 md4 = new md4();
md4.engineupdate(b, 0, b.length);
return md4.enginedigest();
}
/// <summary>
/// returns a binary hash from an input byte array
/// </summary>
/// <param name="b">byte-array to hash</param>
/// <returns>binary hash of input</returns>
public byte[] getbytehashfrombytes(byte[] b)
{
md4 md4 = new md4();
md4.engineupdate(b, 0, b.length);
return md4.enginedigest();
}
/// <summary>
/// returns a string that contains the hexadecimal hash
/// </summary>
/// <param name="b">byte-array to input</param>
/// <returns>string that contains the hex of the hash</returns>
public string gethexhashfrombytes(byte[] b)
{
byte[] e = getbytehashfrombytes(b);
return bytestohex(e, e.length);
}
/// <summary>
/// returns a byte hash from the input byte
/// </summary>
/// <param name="b">byte to hash</param>
/// <returns>binary hash of the input byte</returns>
public byte[] getbytehashfrombyte(byte b)
{
md4 md4 = new md4();
md4.engineupdate(b);
return md4.enginedigest();
}
/// <summary>
/// returns a string that contains the hexadecimal hash
/// </summary>
/// <param name="b">byte to hash</param>
/// <returns>string that contains the hex of the hash</returns>
public string gethexhashfrombyte(byte b)
{
byte[] e = getbytehashfrombyte(b);
return bytestohex(e, e.length);
}
/// <summary>
/// returns a string that contains the hexadecimal hash
/// </summary>
/// <param name="s">string to hash</param>
/// <returns>string that contains the hex of the hash</returns>
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
//-----------------------------------------------------------------------------------
/// <summary>
/// md4 basic transformation
/// </summary>
/// <remarks>
/// transforms context based on 512 bits from input block starting
/// from the offset'th byte.
/// </remarks>
/// <param name="block">input sub-array</param>
/// <param name="offset">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