首页 > 开发 > 综合 > 正文

The MD4 Class.(C#)

2024-07-21 02:22:15
字体:
来源:转载
供稿:网友
  • 网站运营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
    发表评论 共有条评论
    用户名: 密码:
    验证码: 匿名发表