/*
* Creation date : Tues Mar 26 09:00:00 2007
* Last modified : %modify_time%
*/
/** @file
* \brief This file contains implementation of RC4. 
*
* \version LLF_RC4.c#1:csrc:1
* \author Yermalayeu Ihar
* \remarks Copyright (C) 2007 by Discretix Technologies Ltd.
* All Rights reserved
*/

/************************ Include Files ***********************/

#include "LLF_RC4.h"

/************************ Defines *****************************/
/************************ Enums *******************************/
/************************ Typedefs ****************************/
/************************ Global Data *************************/
/************************ Private function prototype **********/
/************************ Private Functions *******************/
/************************ Public Functions ********************/

/**
****************************************************************
* Function Name: 
*  LLF_RC4
*
*  @param Key_ptr [in] - A pointer to the user's key buffer.
*  @param KeySize [in] - The size of the KEY in bytes.
*  @param DataIn_ptr [in] - The pointer to the buffer of the input data to the RC4. 
*                   The pointer's value does not need to be word-aligned.
*  @param DataInSize [in] - The size of the input data.
*  @param DataOut_ptr [in/out] The pointer to the buffer of the output data from the RC4.
*                The pointer's value does not need to be word-aligned. 
*                The size of this buffer must be the same as the DataIn buffer.  
*
* @returns \b
*  CE2Error_t 
*  - CE2_OK - on success
*  - Otherwise - error code:
*
* \brief \b 
* Description:
*  This function provides a RC4 function for processing data.
*
*  The function allocates an internal RC4 Context, and initializes the RC4 Context with the
*  cryptographic attributes that are needed for the RC4 cryptographic operation. Next the
*  function loads the engine with the initializing values, and then processes the data,
*  returning the processed data in the output buffer. Finally, the function frees the
*  internally allocated context.
*
*  \b 
* Algorithm:
*  -# The key-scheduling
*  -# Encryption/decryption
***************************************************************/
CE2Error_t LLF_RC4  (DxUint8_t 				      *Key_ptr, 
                     DxUint32_t 				   KeySizeInBytes,
                     DxUint8_t                    *DataIn_ptr,                                  
                     DxUint32_t                    DataInSize,
                     DxUint8_t                    *DataOut_ptr)
{
  DxUint8_t S[CE2_RC4_S_BOX_SIZE_IN_BYTES], T;
  int i, j;
  DxUint32_t d;

  /**************************************************/
  /* The key-scheduling                             */
  /*                                                */
  /* for i from 0 to 255                            */
  /*   S[i] := i                                    */
  /* j := 0                                         */
  /* for i from 0 to 255                            */
  /*   j := (j + S[i] + key[i mod KeyLen]) mod 256  */
  /*   swap(S[i],S[j])                              */
  /**************************************************/

  /* for i from 0 to 255 */
  for (i = 0; i < CE2_RC4_S_BOX_SIZE_IN_BYTES; i++)
    S[i] = i;
  j = 0;
  /* for i from 0 to 255 */
  for (i = 0; i < CE2_RC4_S_BOX_SIZE_IN_BYTES; i++) {
    /* j := (j + S[i] + key[i mod KeyLen]) mod 256 */
    j = (j + S[i] + Key_ptr[i%KeySizeInBytes])%CE2_RC4_S_BOX_SIZE_IN_BYTES;
    /* swap(S[i],S[j]) */
    T = S[i];
    S[i] = S[j];
    S[j] = T;
  }

  /*********************************************************/
  /* Encryption/decryption                                 */
  /*                                                       */
  /* i := 0                                                */
  /* j := 0                                                */
  /* for d from 0 to DataSize - 1                          */
  /*   i := (i + 1) mod 256                                */
  /*   j := (j + S[i]) mod 256                             */
  /*   swap(S[i],S[j])                                     */
  /*   DataOut[d] = S[(S[i] + S[j]) mod 256] XOR DataIn[d] */
  /*********************************************************/

  i = 0;
  j = 0;
  /* for d from 0 to DataSize - 1 */
  for (d = 0; d < DataInSize; d++) {
    /* i := (i + 1) mod 256 */
    i = (i + 1)%CE2_RC4_S_BOX_SIZE_IN_BYTES;
    /* j := (j + S[i]) mod 256 */
    j = (j + S[i])%CE2_RC4_S_BOX_SIZE_IN_BYTES; 
    /* swap(S[i],S[j]) */
    T = S[i];
    S[i] = S[j];
    S[j] = T;
    /* DataOut[d] = S[(S[i] + S[j]) mod 256] XOR DataIn[d] */
    DataOut_ptr[d] = DataIn_ptr[d]^S[(S[i] + S[j])%CE2_RC4_S_BOX_SIZE_IN_BYTES];
  }

  return CE2_OK;
}
