Changeset 868


Ignore:
Timestamp:
Nov 18, 2009, 3:51:46 PM (12 years ago)
Author:
pretzsch
Message:

+ MD5 plugin: Documentation for PresentableMd5 helper class

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/CrypPlugins/MD5/PresentableMd5.cs

    r864 r868  
    1111    public class PresentableMd5 : INotifyPropertyChanged
    1212    {
     13        /// <summary>
     14        /// A list containing all states that have already been calculated
     15        /// </summary>
    1316        public List<PresentableMd5State> StateHistory { get; set; }
    1417
    15         public PresentableMd5State CurrentState { get; set; }
    16 
     18        /// <summary>
     19        /// The current state of the algorithm
     20        /// </summary>
     21        public PresentableMd5State CurrentState { get; protected set; }
     22
     23        /// <summary>
     24        /// Sequential number identifying the current state of the algorithm
     25        /// </summary>
    1726        public int CurrentStateNumber { get; protected set; }
    1827
     28        /// <summary>
     29        /// The stream where data is read from
     30        /// </summary>
    1931        protected Stream DataStream { get; set; }
    2032
     33        /// <summary>
     34        /// Returns whether this object has been initialized using the Initialize() method
     35        /// </summary>
    2136        public bool IsInitialized { get; protected set; }
    2237
     38        /// <summary>
     39        /// Array of integer constants, each one is used in one of the compression function's 64 steps
     40        /// </summary>
    2341        protected static readonly uint[] AdditionConstantTable = new uint[64]
    2442                        {       0xd76aa478,0xe8c7b756,0x242070db,0xc1bdceee,
     
    3957                                0xf7537e82,0xbd3af235,0x2ad7d2bb,0xeb86d391     };
    4058
     59        /// <summary>
     60        /// Array of 64 constants indicating how far the compression function's rotate operator shifts in each step
     61        /// </summary>
    4162        protected static readonly ushort[] ShiftConstantTable = new ushort[64]
    4263                        {       7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
     
    4566                6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21      };
    4667
     68        /// <summary>
     69        /// Amount of bytes in one block of data
     70        /// </summary>
    4771        protected const int DATA_BLOCK_SIZE = 64;
    4872
     73        /// <summary>
     74        /// The state before CurrentState, null if CurrentState is first state
     75        /// </summary>
    4976        public PresentableMd5State LastState
    5077        {
     
    5885        }
    5986
     87        /// <summary>
     88        /// Delegate for status changed handlers
     89        /// </summary>
    6090        public delegate void StatusChangedHandler();
     91
     92        /// <summary>
     93        /// Raised whenever the algorithm changes its status
     94        /// </summary>
    6195        public event StatusChangedHandler StatusChanged;
    6296
     97        /// <summary>
     98        /// Raised whenever a property changes, important for WPF binding
     99        /// </summary>
    63100        public event PropertyChangedEventHandler PropertyChanged;
     101
     102        /// <summary>
     103        /// Wrapper that raises a PropertyChanged event
     104        /// </summary>
     105        /// <param name="propertyName"></param>
    64106        void OnPropChanged(string propertyName)
    65107        {
     
    68110        }
    69111
     112        /// <summary>
     113        /// Raises a StatusChanged event and PropertyChanged events for important properties
     114        /// </summary>
    70115        private void OnStatusChanged()
    71116        {
     
    80125        }
    81126
     127        /// <summary>
     128        /// Constructs state history list and adds the first "uninitialized" state
     129        /// </summary>
    82130        public PresentableMd5()
    83131        {
     
    86134        }
    87135
     136        /// <summary>
     137        /// Assigns a data source and initializes the algorithm, putting it into "initialized" state
     138        /// </summary>
     139        /// <param name="dataStream">Data source</param>
    88140        public void Initialize(Stream dataStream)
    89141        {
     
    98150        }
    99151
     152        /// <summary>
     153        /// Clears the state history and adds the "uninitialized" state
     154        /// </summary>
    100155        private void SetUninitializedState()
    101156        {
     
    110165        }
    111166
     167        /// <summary>
     168        /// Adds a new state to the history and sets it as the current state
     169        /// </summary>
    112170        protected void AddNewState()
    113171        {
     
    121179        }
    122180
     181        /// <summary>
     182        /// Determine if there are states beyond the current one available in the history
     183        /// </summary>
    123184        public bool HistoryHasMoreStates
    124185        {
     
    132193        }
    133194
     195        /// <summary>
     196        /// Navigate one step back using the state history
     197        /// </summary>
    134198        public void PreviousStep()
    135199        {
     
    142206        }
    143207
     208        /// <summary>
     209        /// Determines whether the current state is the "finished" state
     210        /// </summary>
    144211        public bool IsInFinishedState
    145212        {
     
    150217        }
    151218
     219        /// <summary>
     220        /// Determines whether the current state is the first, "uninitialized", state
     221        /// </summary>
    152222        public bool IsInFirstState
    153223        {
     
    158228        }
    159229
     230        /// <summary>
     231        /// Goes one step forward by either restoring a previously calculated state from the history or calculating the next state
     232        /// </summary>
    160233        public void NextStep()
    161234        {
     
    181254        }
    182255
     256        /// <summary>
     257        /// Moves through the algorithm's steps until it is finished
     258        /// </summary>
    183259        public void NextStepUntilFinished()
    184260        {
     
    190266        }
    191267
     268        /// <summary>
     269        /// Moves one or more steps through the algorithm until the next "finished round" state
     270        /// </summary>
    192271        public void NextStepUntilRoundEnd()
    193272        {
     
    195274                return;
    196275
    197             while (!IsInFinishedState && CurrentState.State != Md5State.FINISHED_ROUND)
     276            do
    198277                NextStep();
    199         }
    200 
     278            while (!IsInFinishedState && CurrentState.State != Md5State.FINISHED_ROUND);
     279        }
     280
     281
     282        /// <summary>
     283        /// Moves one or more steps through the algorithm until the next "finished compression" state
     284        /// </summary>
    201285        public void NextStepUntilBlockEnd()
    202286        {
     
    204288                return;
    205289
    206             while (!IsInFinishedState && CurrentState.State != Md5State.FINISHED_COMPRESSION)
     290            do
    207291                NextStep();
    208         }
    209 
     292            while (!IsInFinishedState && CurrentState.State != Md5State.FINISHED_COMPRESSION);
     293        }
     294
     295        /// <summary>
     296        /// Performs the next step in the algorithm
     297        /// </summary>
     298        /// <param name="previousState">Previous state</param>
     299        /// <param name="newState">The new state which is to be determined</param>
    210300        public void PerformStep(PresentableMd5State previousState, PresentableMd5State newState)
    211301        {
     
    213303            {
    214304                case Md5State.INITIALIZED:
    215                     // If initialization is complete, start by reading data
     305                    // Start by reading data
    216306                    newState.State = Md5State.READING_DATA;
    217307                    break;
    218308
    219309                case Md5State.READING_DATA:
    220                     // Read data and enter "data read" state
     310                    // Fetch next data block and enter "data read" state
    221311                    ReadData(newState);
    222312                    newState.State = Md5State.READ_DATA;
     
    224314
    225315                case Md5State.READ_DATA:
    226                     // If an underfull buffer was read, we're at the end of the digestible data, so enter "starting padding" state
     316                    // If an underfull buffer was read, enter "starting padding" state
    227317                    // If a full buffer was read, enter "starting compression" state
    228318                    if (previousState.DataLength < DATA_BLOCK_SIZE)
     
    233323
    234324                case Md5State.STARTING_PADDING:
    235                     // First step of padding is adding the padding bytes, so enter that state
     325                    // First step of padding is adding the padding bytes
    236326                    newState.State = Md5State.ADDING_PADDING_BYTES;
    237327                    break;
     
    244334
    245335                case Md5State.ADDED_PADDING_BYTES:
    246                     // The next step for padding is adding the data length, so enter that state
     336                    // Next step for padding is adding the data length
    247337                    newState.State = Md5State.ADDING_LENGTH;
    248338                    break;
     
    265355
    266356                case Md5State.STARTING_COMPRESSION:
     357                    // Perform pre-compression initialization and continue by starting the first round
    267358                    StartCompression(newState);
    268359                    newState.State = Md5State.STARTING_ROUND;
     
    270361
    271362                case Md5State.STARTING_ROUND:
     363                    // Start the round and continue with the first round step
    272364                    StartRound(newState);
    273365                    newState.State = Md5State.STARTING_ROUND_STEP;
     
    275367
    276368                case Md5State.STARTING_ROUND_STEP:
     369                    // Perform the step and go into finished state
    277370                    PerformRoundStep(newState);
    278371                    newState.State = Md5State.FINISHED_ROUND_STEP;
     
    280373
    281374                case Md5State.FINISHED_ROUND_STEP:
     375                    // If last step, go into 'finished round' state, else continue with next step
    282376                    if (previousState.IsLastStepInRound)
    283377                        newState.State = Md5State.FINISHED_ROUND;
     
    290384
    291385                case Md5State.FINISHED_ROUND:
     386                    // If last step, go into "finishing compression" state, else continue with next round
    292387                    if (previousState.IsLastRound)
    293388                        newState.State = Md5State.FINISHING_COMPRESSION;
     
    300395
    301396                case Md5State.FINISHING_COMPRESSION:
     397                    // Perform finishing actions and go into "finished compression" state
    302398                    FinishCompression(newState);
    303399                    newState.State = Md5State.FINISHED_COMPRESSION;
     
    305401
    306402                case Md5State.FINISHED_COMPRESSION:
    307                     // If compression is finished, check if there's more data left in buffer. If so, reenter compression function with offset
     403                    // If there's more data left in buffer, reenter compression function with offset
    308404                    if (previousState.DataLength - previousState.DataOffset > DATA_BLOCK_SIZE)
    309405                    {
     
    331427        }
    332428
     429        /// <summary>
     430        /// Performs the steps necessary after the individual compression function steps have run
     431        /// </summary>
     432        /// <param name="newState">Algorithm state to modify</param>
    333433        private void FinishCompression(PresentableMd5State newState)
    334434        {
     435            // Add compression function results to accumulators
    335436            newState.H1 += newState.A;
    336437            newState.H2 += newState.B;
     
    338439            newState.H4 += newState.D;
    339440
     441            // Increment the number of bytes hashed so far
    340442            newState.BytesHashed += DATA_BLOCK_SIZE;
    341443        }
    342444
     445        /// <summary>
     446        /// Reads from the data source
     447        /// </summary>
     448        /// <param name="newState">Algorithm state to modify</param>
    343449        private void ReadData(PresentableMd5State newState)
    344450        {
     451            // Fetch up to 64 bytes of data
    345452            newState.Data = new byte[128];
    346453            newState.DataLength = (uint)DataStream.Read(newState.Data, 0, 64);
     
    348455        }
    349456
     457        /// <summary>
     458        /// Performs initialization before a round
     459        /// </summary>
     460        /// <param name="newState">Algorithm state to modify</param>
    350461        private void StartRound(PresentableMd5State newState)
    351462        {
     463            // Reset round step counter
    352464            newState.RoundStepIndex = 0;
    353465        }
    354466
     467        /// <summary>
     468        /// Performs initialization required before running compression function steps
     469        /// </summary>
     470        /// <param name="newState">Algorithm state to modify</param>
    355471        private void StartCompression(PresentableMd5State newState)
    356472        {
     473            // Read data into unsigned 32 bit integers
    357474            newState.X = new uint[16];
    358 
    359475            for (uint j = 0; j < 64; j += 4)
    360476            {
     
    365481            }
    366482
     483            // Reset round counter
    367484            newState.RoundIndex = 0;
    368485
     486            // Initialize A, B, C, D with accumulated values
    369487            newState.A = newState.H1;
    370488            newState.B = newState.H2;
     
    373491        }
    374492
     493        /// <summary>
     494        /// Adds the data length part of the padding
     495        /// </summary>
     496        /// <param name="newState">Algorithm state to modify</param>
    375497        private void AddLength(PresentableMd5State newState)
    376498        {
     499            // Determine offset behind last written byte
    377500            uint lengthOffset = newState.DataLength + 8;
    378501
     502            // Write the length in bit as 8 byte little-endian integer
    379503            for (int i = 8; i > 0; i--)
    380504                newState.Data[lengthOffset - i] = (byte)(newState.LengthInBit >> ((8 - i) * 8) & 0xff);
    381505
     506            // Remember that padding is done now
    382507            newState.IsPaddingDone = true;
    383508        }
    384509
     510        /// <summary>
     511        /// Adds padding bytes to the data
     512        /// </summary>
     513        /// <param name="newState">Algorithm state to modify</param>
    385514        private void AddPaddingBytes(PresentableMd5State newState)
    386515        {
     
    399528        }
    400529
     530        /// <summary>
     531        /// Sets up and adds the "initialized" state
     532        /// </summary>
    401533        public void PerformInitializationStep()
    402534        {
     535            // Add a state
    403536            AddNewState();
    404537
     538            // Initialize new state
    405539            CurrentState.BytesHashed = 0;
     540            CurrentState.State = Md5State.INITIALIZED;
     541
     542            // Set initial accumulator values
    406543            CurrentState.H1 = 0x67452301;
    407544            CurrentState.H2 = 0xEFCDAB89;
    408545            CurrentState.H3 = 0x98BADCFE;
    409546            CurrentState.H4 = 0X10325476;
    410             CurrentState.State = Md5State.INITIALIZED;
    411         }
    412 
     547
     548        }
     549
     550        /// <summary>
     551        /// Shift-Rotates an unsigned integer to the left
     552        /// </summary>
     553        /// <param name="uiNumber">Integer to rotate</param>
     554        /// <param name="shift">Number of bits to shift</param>
     555        /// <returns>Result of the shift</returns>
    413556        public static uint RotateLeft(uint uiNumber, ushort shift)
    414557        {
     
    416559        }
    417560
     561        /// <summary>
     562        /// Delegate for the inner round function applied in each step of the compression function
     563        /// </summary>
     564        /// <param name="a"></param>
     565        /// <param name="b"></param>
     566        /// <param name="c"></param>
     567        /// <param name="d"></param>
     568        /// <returns></returns>
    418569        protected delegate uint RoundFunction(uint a, uint b, uint c, uint d);
     570
     571        /// <summary>
     572        /// Constant array of the four inner round functions
     573        /// </summary>
    419574        protected readonly RoundFunction[] ROUND_FUNCTION = { FuncF, FuncG, FuncH, FuncI };
    420575
     576        /// <summary>
     577        /// Performs one step of the compression function
     578        /// </summary>
     579        /// <param name="newState">Algorithm state to modify</param>
    421580        private void PerformRoundStep(PresentableMd5State newState)
    422581        {
    423             Console.WriteLine("Before R {0} S {1,2}: A = {2,10} B = {3,10} C = {4,10} D = {5,10}", newState.Round, newState.RoundStep, newState.A, newState.B, newState.C, newState.D);
    424 
     582            // Determine which round function to use
    425583            RoundFunction roundFunction = ROUND_FUNCTION[newState.RoundIndex];
    426584
    427             uint i = newState.RoundIndex * 16 + newState.RoundStepIndex;
    428 
     585            // Determine which step in the compression function this is
     586            uint stepIndex = newState.RoundIndex * 16 + newState.RoundStepIndex;
     587
     588            // Determine which part of the data to use in this step
    429589            uint wordIndex;
    430590            switch (newState.RoundIndex)
     
    432592                default:
    433593                case 0:
    434                     wordIndex = i;
     594                    wordIndex = stepIndex;
    435595                    break;
    436596                case 1:
    437                     wordIndex = 5 * i + 1;
     597                    wordIndex = 5 * stepIndex + 1;
    438598                    break;
    439599                case 2:
    440                     wordIndex = 3 * i + 5;
     600                    wordIndex = 3 * stepIndex + 5;
    441601                    break;
    442602                case 3:
    443                     wordIndex = 7 * i;
     603                    wordIndex = 7 * stepIndex;
    444604                    break;
    445605            }
    446606            wordIndex %= 16;
    447607
    448             ExecRoundFunction(newState, roundFunction, newState.X[wordIndex], i);
    449 
    450             if (newState.IsLastRound && newState.IsLastStepInRound)
    451 
    452                 Console.WriteLine("After  R {0} S {1,2}: A = {2,10} B = {3,10} C = {4,10} D = {5,10}", newState.Round, newState.RoundStep, newState.A, newState.B, newState.C, newState.D);
    453         }
    454 
     608            // Execute the chosen round function
     609            ExecRoundFunction(newState, roundFunction, newState.X[wordIndex], stepIndex);
     610        }
     611
     612        /// <summary>
     613        /// Executes the round function and modifies algorithm state to reflect results
     614        /// </summary>
     615        /// <param name="state">Algorithm state to modify</param>
     616        /// <param name="function">The inner round function to execute</param>
     617        /// <param name="W">The part of the data to use in the round function</param>
     618        /// <param name="i">Index of this step (range 0 - 63)</param>
    455619        protected static void ExecRoundFunction(PresentableMd5State state, RoundFunction function, uint W, uint i)
    456620        {
     621            // Apply central compression function
    457622            state.A = state.B + RotateLeft((state.A + function(state.A, state.B, state.C, state.D) + W + AdditionConstantTable[i]), ShiftConstantTable[i]);
    458623
     624            // Right-rotate the 4 compression result accumulators
    459625            uint oldD = state.D;
    460626            state.D = state.C;
     
    464630        }
    465631
     632        /// <summary>
     633        /// Inner round function F, applied in step 1-16 of the compression function
     634        /// </summary>
     635        /// <param name="a">Temporary step variable A</param>
     636        /// <param name="b">Temporary step variable B</param>
     637        /// <param name="c">Temporary step variable C</param>
     638        /// <param name="d">Temporary step variable D</param>
     639        /// <returns>Result of inner round function F</returns>
    466640        protected static uint FuncF(uint a, uint b, uint c, uint d)
    467641        {
     
    469643        }
    470644
     645        /// <summary>
     646        /// Inner round function G, applied in step 17-32 of the compression function
     647        /// </summary>
     648        /// <param name="a">Temporary step variable A</param>
     649        /// <param name="b">Temporary step variable B</param>
     650        /// <param name="c">Temporary step variable C</param>
     651        /// <param name="d">Temporary step variable D</param>
     652        /// <returns>Result of inner round function G</returns>
    471653        protected static uint FuncG(uint a, uint b, uint c, uint d)
    472654        {
     
    474656        }
    475657
     658        /// <summary>
     659        /// Inner round function H, applied in step 33-48 of the compression function
     660        /// </summary>
     661        /// <param name="a">Temporary step variable A</param>
     662        /// <param name="b">Temporary step variable B</param>
     663        /// <param name="c">Temporary step variable C</param>
     664        /// <param name="d">Temporary step variable D</param>
     665        /// <returns>Result of inner round function H</returns>
    476666        protected static uint FuncH(uint a, uint b, uint c, uint d)
    477667        {
     
    479669        }
    480670
     671        /// <summary>
     672        /// Inner round function I, applied in step 49-64 of the compression function
     673        /// </summary>
     674        /// <param name="a">Temporary step variable A</param>
     675        /// <param name="b">Temporary step variable B</param>
     676        /// <param name="c">Temporary step variable C</param>
     677        /// <param name="d">Temporary step variable D</param>
     678        /// <returns>Result of inner round function I</returns>
    481679        protected static uint FuncI(uint a, uint b, uint c, uint d)
    482680        {
     
    484682        }
    485683
     684        /// <summary>
     685        /// The current state's accumulator variables as byte array
     686        /// </summary>
     687        /// <remarks>
     688        /// When the algorithm is finished, this is the computed MD5 digest value.
     689        /// </remarks>
    486690        public byte[] HashValueBytes
    487691        {
     
    497701        }
    498702
     703        /// <summary>
     704        /// Writes an integer into an array in little-endian representation
     705        /// </summary>
     706        /// <param name="array">Array which should be written to</param>
     707        /// <param name="offset">Offset in the array</param>
     708        /// <param name="value">Integer to write to array</param>
    499709        protected void writeUintToArray(byte[] array, int offset, uint value)
    500710        {
Note: See TracChangeset for help on using the changeset viewer.