// This code is derived from jcifs smb client library // Ported by J. Arturo // // 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System; using SharpCifs.Util.Sharpen; namespace SharpCifs.Util { /// Implements the MD4 message digest algorithm in Java. /// /// Implements the MD4 message digest algorithm in Java. ///

/// References: ///

    ///
  1. Ronald L. Rivest, /// " /// The MD4 Message-Digest Algorithm", /// IETF RFC-1320 (informational). ///
///

$Revision: 1.2 $ /// /// Raif S. Naffah public class Md4 : MessageDigest { ///

The size in bytes of the input block to the tranformation algorithm. /// The size in bytes of the input block to the tranformation algorithm. private const int BlockLength = 64; /// 4 32-bit words (interim result) private int[] _context = new int[4]; /// Number of bytes processed so far mod. /// Number of bytes processed so far mod. 2 power of 64. private long _count; /// 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits. /// 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits. private byte[] _buffer = new byte[BlockLength]; /// 512 bits work buffer = 16 x 32-bit words private int[] _x = new int[16]; public Md4() { // This file is currently unlocked (change this line if you lock the file) // // $Log: MD4.java,v $ // Revision 1.2 1998/01/05 03:41:19 iang // Added references only. // // Revision 1.1.1.1 1997/11/03 22:36:56 hopwood // + Imported to CVS (tagged as 'start'). // // Revision 0.1.0.0 1997/07/14 R. Naffah // + original version // // $Endlog$ // MD4 specific object variables //........................................................................... // = 512 / 8; // Constructors //........................................................................... EngineReset(); } /// This constructor is here to implement cloneability of this class. /// This constructor is here to implement cloneability of this class. private Md4(Md4 md) : this() { _context = (int[])md._context.Clone(); _buffer = (byte[])md._buffer.Clone(); _count = md._count; } // Cloneable method implementation //........................................................................... /// Returns a copy of this MD object. /// Returns a copy of this MD object. 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. /// /// /// Resets this object disregarding any temporary data present at the /// time of the invocation of this call. /// protected void EngineReset() { // initial values of MD4 i.e. A, B, C, D // as per rfc-1320; they are low-order byte first _context[0] = unchecked(0x67452301); _context[1] = unchecked((int)(0xEFCDAB89)); _context[2] = unchecked((int)(0x98BADCFE)); _context[3] = unchecked(0x10325476); _count = 0L; for (int i = 0; i < BlockLength; i++) { _buffer[i] = 0; } } /// Continues an MD4 message digest using the input byte. /// Continues an MD4 message digest using the input byte. protected void EngineUpdate(byte b) { // compute number of bytes still unhashed; ie. present in buffer int i = (int)(_count % BlockLength); _count++; // update number of bytes _buffer[i] = b; if (i == BlockLength - 1) { Transform(_buffer, 0); } } /// MD4 block update operation. /// /// 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 block to consider protected 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 IndexOutOfRangeException(); } // compute number of bytes still unhashed; ie. present in buffer int bufferNdx = (int)(_count % BlockLength); _count += len; // update number of bytes int partLen = BlockLength - bufferNdx; int i = 0; if (len >= partLen) { Array.Copy(input, offset, _buffer, bufferNdx, partLen); Transform(_buffer, 0); for (i = partLen; i + BlockLength - 1 < len; i += BlockLength) { Transform(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. /// /// /// 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. protected byte[] EngineDigest() { // pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512 int bufferNdx = (int)(_count % BlockLength); int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx); // padding is alwas binary 1 followed by binary 0s byte[] tail = new byte[padLen + 8]; tail[0] = unchecked(unchecked(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] = unchecked((byte)((long)(((ulong)(_count * 8)) >> (8 * i)))); } EngineUpdate(tail, 0, tail.Length); byte[] result = new byte[16]; // cast this MD4's context (array of 4 ints) into an array of 16 bytes. for (int i1 = 0; i1 < 4; i1++) { for (int j = 0; j < 4; j++) { result[i1 * 4 + j] = unchecked((byte)((int)(((uint)_context[i1]) >> (8 * j)))); } } // reset the engine EngineReset(); return result; } // own methods //........................................................................... /// MD4 basic transformation. /// /// 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(byte[] block, int offset) { // encodes 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] = (block[offset++] & unchecked(0xFF)) | (block[offset++] & unchecked( 0xFF)) << 8 | (block[offset++] & unchecked(0xFF)) << 16 | (block[offset ++] & unchecked(0xFF)) << 24; } int a = _context[0]; int b = _context[1]; int c = _context[2]; int 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 int Ff(int a, int b, int c, int d, int x, int s) { int t = a + ((b & c) | (~b & d)) + x; return t << s | (int)(((uint)t) >> (32 - s)); } private int Gg(int a, int b, int c, int d, int x, int s) { int t = a + ((b & (c | d)) | (c & d)) + x + unchecked(0x5A827999); return t << s | (int)(((uint)t) >> (32 - s)); } private int Hh(int a, int b, int c, int d, int x, int s) { int t = a + (b ^ c ^ d) + x + unchecked(0x6ED9EBA1); return t << s | (int)(((uint)t) >> (32 - s)); } public override byte[] Digest() { return EngineDigest(); } public override int GetDigestLength() { return EngineDigest().Length; } public override void Reset() { EngineReset(); } public override void Update(byte[] b) { EngineUpdate(b, 0, b.Length); } public override void Update(byte b) { EngineUpdate(b); } public override void Update(byte[] b, int offset, int len) { EngineUpdate(b, offset, len); } } }