using System;

namespace HRM.BO
{
	public class AES
	{
		private int _nNk, _nNb, _nNr;
		private int[] _nOnBits, _n2Power, _nFKey, _nRKey, _nFTable, _nRTable, _nRCo;
		private byte[] _bytOnBits, _byt2Power, _nInCo, _nFbSub, _nRbSub, _nPTab, _nLTab, _nFi, _nRi;

		public AES()
		{
			_nInCo=new byte[4];
			_nOnBits=new int[32];
			_n2Power=new int[32];
			_nFKey=new int[128];
			_nRKey=new int[120];
			_nFTable=new int[256];
			_nRTable=new int[256];
			_nRCo=new int[30];
			_bytOnBits=new byte[8];
			_byt2Power=new byte[8];
			_nFi=new byte[24];
			_nRi=new byte[24];
			_nInCo=new byte[4];
			_nFbSub=new byte[256];
			_nRbSub=new byte[256];
			_nPTab=new byte[256];
			_nLTab=new byte[256];
			
			_nInCo[0]=0xB;
			_nInCo[1]=0xD;
			_nInCo[2]=0x9;
			_nInCo[3]=0xE;

			// Could have done this with a loop calculating each value, but simply
			// assigning the values is quicker - BITS SET FROM RIGHT
			_bytOnBits[0]=1;          // 00000001
			_bytOnBits[1]=3;          // 00000011
			_bytOnBits[2]=7;          // 00000111
			_bytOnBits[3]=15;         // 00001111
			_bytOnBits[4]=31;         // 00011111
			_bytOnBits[5]=63;         // 00111111
			_bytOnBits[6]=127;        // 01111111
			_bytOnBits[7]=255;        // 11111111
			
			// Could have done this with a loop calculating each value, but simply
			// assigning the values is quicker - POWERS OF 2
			_byt2Power[0]=1;          // 00000001
			_byt2Power[1]=2;          // 00000010
			_byt2Power[2]=4;          // 00000100
			_byt2Power[3]=8;          // 00001000
			_byt2Power[4]=16;         // 00010000
			_byt2Power[5]=32;         // 00100000
			_byt2Power[6]=64;         // 01000000
			_byt2Power[7]=128;        // 10000000

			// Could have done this with a loop calculating each value, but simply
			// assigning the values is quicker - BITS SET FROM RIGHT
			_nOnBits[0]=1;					// 00000000000000000000000000000001
			_nOnBits[1]=3;					// 00000000000000000000000000000011
			_nOnBits[2]=7;					// 00000000000000000000000000000111
			_nOnBits[3]=15;				// 00000000000000000000000000001111
			_nOnBits[4]=31;				// 00000000000000000000000000011111
			_nOnBits[5]=63;				// 00000000000000000000000000111111
			_nOnBits[6]=127;				// 00000000000000000000000001111111
			_nOnBits[7]=255;				// 00000000000000000000000011111111
			_nOnBits[8]=511;				// 00000000000000000000000111111111
			_nOnBits[9]=023;				// 00000000000000000000001111111111
			_nOnBits[10]=2047;				// 00000000000000000000011111111111
			_nOnBits[11]=4095;				// 00000000000000000000111111111111
			_nOnBits[12]=8191;				// 00000000000000000001111111111111
			_nOnBits[13]=16383;			// 00000000000000000011111111111111
			_nOnBits[14]=32767;			// 00000000000000000111111111111111
			_nOnBits[15]=65535;			// 00000000000000001111111111111111
			_nOnBits[16]=131071;			// 00000000000000011111111111111111
			_nOnBits[17]=262143;			// 00000000000000111111111111111111
			_nOnBits[18]=524287;			// 00000000000001111111111111111111
			_nOnBits[19]=1048575;			// 00000000000011111111111111111111
			_nOnBits[20]=2097151;			// 00000000000111111111111111111111
			_nOnBits[21]=4194303;			// 00000000001111111111111111111111
			_nOnBits[22]=8388607;			// 00000000011111111111111111111111
			_nOnBits[23]=16777215;			// 00000000111111111111111111111111
			_nOnBits[24]=33554431;			// 00000001111111111111111111111111
			_nOnBits[25]=67108863;			// 00000011111111111111111111111111
			_nOnBits[26]=134217727;		// 00000111111111111111111111111111
			_nOnBits[27]=268435455;		// 00001111111111111111111111111111
			_nOnBits[28]=536870911;		// 00011111111111111111111111111111
			_nOnBits[29]=1073741823;		// 00111111111111111111111111111111
			_nOnBits[30]= 2147483647;		// 01111111111111111111111111111111
			
			// Could have done this with a loop calculating each value, but simply
			// assigning the values is quicker - POWERS OF 2
			_n2Power[0]=1;				// 00000000000000000000000000000001
			_n2Power[1]=2;				// 00000000000000000000000000000010
			_n2Power[2]=4;				// 00000000000000000000000000000100
			_n2Power[3]=8;				// 00000000000000000000000000001000
			_n2Power[4]=16;				// 00000000000000000000000000010000
			_n2Power[5]=32;				// 00000000000000000000000000100000
			_n2Power[6]=64;				// 00000000000000000000000001000000
			_n2Power[7]=128;			// 00000000000000000000000010000000
			_n2Power[8]=256;			// 00000000000000000000000100000000
			_n2Power[9]=512;			// 00000000000000000000001000000000
			_n2Power[10]=1024;			// 00000000000000000000010000000000
			_n2Power[11]=2048;			// 00000000000000000000100000000000
			_n2Power[12]=4096;			// 00000000000000000001000000000000
			_n2Power[13]=8192;			// 00000000000000000010000000000000
			_n2Power[14]=16384;			// 00000000000000000100000000000000
			_n2Power[15]=32768;			// 00000000000000001000000000000000
			_n2Power[16]=65536;			// 00000000000000010000000000000000
			_n2Power[17]=131072;		// 00000000000000100000000000000000
			_n2Power[18]=262144;		// 00000000000001000000000000000000
			_n2Power[19]=524288;		// 00000000000010000000000000000000
			_n2Power[20]=1048576;		// 00000000000100000000000000000000
			_n2Power[21]=2097152;		// 00000000001000000000000000000000
			_n2Power[22]=4194304;		// 00000000010000000000000000000000
			_n2Power[23]=8388608;		// 00000000100000000000000000000000
			_n2Power[24]=16777216;		// 00000001000000000000000000000000
			_n2Power[25]=33554432;		// 00000010000000000000000000000000
			_n2Power[26]=67108864;		// 00000100000000000000000000000000
			_n2Power[27]=134217728;		// 00001000000000000000000000000000
			_n2Power[28]=268435456;		// 00010000000000000000000000000000
			_n2Power[29]=536870912;		// 00100000000000000000000000000000
			_n2Power[30]=1073741824;	// 01000000000000000000000000000000	
		}
		private int LShift(int nValue, int nShiftBits)
		{
			return (nValue<<nShiftBits); 
		}

		//*******************************************************************************
		// RShift (FUNCTION)
		//*******************************************************************************
		private int RShift(int lValue, int iShiftBits)
		{
			int nRShift=0;
			if(iShiftBits==0)
			{
				nRShift=lValue;
			}
			else if(iShiftBits==31)
			{
				if((lValue & -2147483648)!=0)
				{nRShift=1;}
				else
				{nRShift=0;}
			}
			else if(iShiftBits<0 || iShiftBits>31)
			{
				nRShift=-1; 
			}
			nRShift=((lValue & 2147483646)/_n2Power[iShiftBits]);
			if((lValue & -2147483648)!=0)
			{
				nRShift=(nRShift | (1073741824/_n2Power[iShiftBits-1]));
			}
			return nRShift; 
		}

		//*******************************************************************************
		// LShiftByte (FUNCTION)
		//*******************************************************************************
		private byte LShiftByte(byte bytValue, byte bytShiftBits)
		{
			byte nLShiftByte=0;
			if(bytShiftBits==0)
			{
				nLShiftByte=bytValue;
			}
			else if(bytShiftBits==7)
			{
				if((bytValue & 1)!=0)
				{nLShiftByte = 0x80;}
				else
				{nLShiftByte=0;}
			}
			else if(bytShiftBits<0 || bytShiftBits>7)
			{
				nLShiftByte=0;
			}
			nLShiftByte=(byte)((bytValue & _bytOnBits[7-bytShiftBits])*_byt2Power[bytShiftBits]);
			
			return nLShiftByte; 
		}

		//*******************************************************************************
		// RShiftByte (FUNCTION)
		//*******************************************************************************
		private byte RShiftByte(byte bytValue, byte bytShiftBits)
		{
			byte nRShiftByte=0;
			if(bytShiftBits==0)
			{
				nRShiftByte=bytValue;
			}
			else if(bytShiftBits==7)
			{
				if((bytValue & 0x80)!=0)
				{nRShiftByte=1;}
				else
				{nRShiftByte=0;}
			}
			else if(bytShiftBits<0 || bytShiftBits>7)
			{
				nRShiftByte=0;
			}
			nRShiftByte=(byte)(bytValue/_byt2Power[bytShiftBits]);

			return nRShiftByte;
		}

		//*******************************************************************************
		// RotateLeft (FUNCTION)
		//*******************************************************************************
		private int RotateLeft(int lValue, int iShiftBits)
		{
			return (LShift(lValue, iShiftBits)|RShift(lValue, (int)(32-iShiftBits)));
		}

		////*******************************************************************************
		//// RotateLeftByte (FUNCTION)
		//*******************************************************************************
		private byte RotateLeftByte(byte bytValue, byte bytShiftBits)
		{
			return (byte)(LShiftByte(bytValue, bytShiftBits) | RShiftByte(bytValue, (byte)(8-bytShiftBits)));
		}

		//*******************************************************************************
		// Pack (FUNCTION)
		//*******************************************************************************
		private int  Pack(byte[] b)
		{
			int nTemp=0, nPack=0;
			for(int nCount=0; nCount<=3; nCount++)
			{
				nTemp=b[nCount];
				nPack=nPack | LShift(nTemp, (int)(nCount*8));
			}
			return nPack;
		}

		//*******************************************************************************
		// PackFrom (FUNCTION)
		//*******************************************************************************
		private int PackFrom(byte[] b, int k)
		{	
			int nPackFrom=0, nTemp=0;
			for(int nCount=0; nCount<=3; nCount++)
			{
				nTemp=b[nCount+k];
				nPackFrom=nPackFrom | LShift(nTemp, (int)(nCount*8));
			}
			return nPackFrom;
		}

		//*******************************************************************************
		// Unpack (SUB)
		//*******************************************************************************
		private void Unpack(int a, ref byte[] b)
		{
			b[0]=(byte)(a & _nOnBits[7]);
			b[1]=(byte)(RShift(a,  8) & _nOnBits[7]);
			b[2]=(byte)(RShift(a, 16) & _nOnBits[7]);
			b[3]=(byte)(RShift(a, 24) & _nOnBits[7]);
		}

		//*******************************************************************************
		// UnpackFrom (SUB)
		//*******************************************************************************
		private void UnpackFrom(int a, ref byte[] b, int k)
		{
			b[0+k]=(byte)(a             & _nOnBits[7]);
			b[1+k]=(byte)(RShift(a, 8)  & _nOnBits[7]);
			b[2+k]=(byte)(RShift(a, 16) & _nOnBits[7]);
			b[3+k]=(byte)(RShift(a, 24) & _nOnBits[7]);
		}

		//*******************************************************************************
		// xtime (FUNCTION)
		//*******************************************************************************
		private byte xTime(byte a)
		{
			byte b=0;
			if((a & 0x80)!=0)
			{b=0x1B;}
			else
			{b=0;}
			a=LShiftByte(a, 1);
			a=(byte)(a^b);
			return a;
		}

		//*******************************************************************************
		// bmul (FUNCTION)
		//*******************************************************************************
		private byte bMul(byte x, byte Y)
		{
			byte nbmul=0;
			if(x!=0 && Y!=0)
			{
				nbmul=(byte)(_nPTab[(_nLTab[x]+ _nLTab[Y]) % 255]);
			}
			return nbmul;
		}

		//*******************************************************************************
		// SubByte (FUNCTION)
		//*******************************************************************************
		private int SubByte(int a)
		{
			byte[] b=new byte[4];
			Unpack(a, ref b);
			b[0]=_nFbSub[b[0]];
			b[1]=_nFbSub[b[1]];
			b[2]=_nFbSub[b[2]];
			b[3]=_nFbSub[b[3]];

			return (Pack(b));
		}

		//*******************************************************************************
		// product (FUNCTION)
		//*******************************************************************************
		private int Product(int x, int y)
		{
			byte[] xb=new Byte[4];
			byte[] yb=new Byte[4];

			Unpack(x, ref xb);
			Unpack(y, ref yb);

			return (bMul(xb[0], yb[0]) ^ bMul(xb[1], yb[1]) ^ bMul(xb[2], yb[2]) ^ bMul(xb[3], yb[3]));
		}

		//*******************************************************************************
		// InvMixCol (FUNCTION)
		//*******************************************************************************
		private int InvMixCol(int x)
		{
			int m=0;
			byte[] b=new byte[4];
			
			m=Pack(_nInCo);
			b[3]=(byte)Product(m, x);
			m=RotateLeft(m, 24);
			b[2]=(byte)Product(m, x);
			m=RotateLeft(m, 24);
			b[1]=(byte)Product(m, x);
			m=RotateLeft(m, 24);
			b[0]=(byte)Product(m, x);
			
			return Pack(b);
		}

		//*******************************************************************************
		// ByteSub (FUNCTION)
		//*******************************************************************************
		private byte ByteSub(byte x)
		{
			byte Y=0;
			Y=_nPTab[255-_nLTab[x]];
			x=Y;
			x=RotateLeftByte(x, 1);
			Y=(byte)(Y ^ x);
			x=RotateLeftByte(x, 1);
			Y=(byte)(Y ^ x);
			x=RotateLeftByte(x, 1);
			Y=(byte)(Y ^ x);
			x=RotateLeftByte(x, 1);
			Y=(byte)(Y ^ x);
			Y=(byte)(Y ^ 0x63);

			return Y;
		}

		//*******************************************************************************
		// gentables (SUB)
		//*******************************************************************************
		private void GenTables()
		{
			int i=0;
			byte Y=0, ib=0;
			byte[] b=new byte[4];
			
			_nLTab[0]=0;
			_nPTab[0]=1;
			_nLTab[1]=0;
			_nPTab[1]=3;
			_nLTab[3]=1;

			for(i=2; i<=255; i++)
			{
				_nPTab[i]= (byte)(_nPTab[i-1] ^ xTime(_nPTab[i-1]));
				_nLTab[_nPTab[i]]=(byte)i;
			}

			_nFbSub[0]=0x63;
			_nRbSub[0x63]=0;

			for(i=1; i<=255; i++)
			{
				ib=(byte)i;
				Y=ByteSub(ib);
				_nFbSub[i]=Y;
				_nRbSub[Y]=(byte)i;
			}

			Y=1;
			for(i=0; i<=29; i++)
			{
				_nRCo[i]=Y;
				Y=xTime(Y);
			}
			for(i=0; i<=255; i++)
			{
				Y=_nFbSub[i];
				b[3]=(byte)(Y ^ xTime(Y));
				b[2]=Y;
				b[1]=Y;
				b[0]=xTime(Y);
				_nFTable[i]=Pack(b);

				Y=_nRbSub[i];
				b[3]=bMul(_nInCo[0], Y);
				b[2]=bMul(_nInCo[1], Y);
				b[1]=bMul(_nInCo[2], Y);
				b[0]=bMul(_nInCo[3], Y);
				_nRTable[i]=Pack(b);
			}
		}

		//*******************************************************************************
		// gkey (SUB)
		//*******************************************************************************
		private void GenKey(int nb, int nk, byte[] KEY)
		{
			int i=0, j=0, k=0, m=0, N=0, C1=0, C2=0, C3=0;
			int[] CipherKey=new int[8];
			
			_nNb = nb;
			_nNk = nk;

			if(_nNb>=_nNk)
			{_nNr=6+_nNb;}
			else
			{_nNr=6+_nNk;}

			C1 = 1;
			if(_nNb<8)
			{C2=2; C3=3;}
			else
			{C2=3; C3=4;}

			for(j=0; j<=(nb-1); j++)
			{
				m=j*3;
				_nFi[m]  =(byte)((j +C1)   % nb);
				_nFi[m+1]=(byte)((j +C2)   % nb);
				_nFi[m+2]=(byte)((j +C3)   % nb);
				_nRi[m]  =(byte)((nb+j-C1) % nb);
				_nRi[m+1]=(byte)((nb+j-C2) % nb);
				_nRi[m+2]=(byte)((nb+j-C3) % nb);
			}

			N=_nNb*(_nNr+1);

			for(i=0; i<=(_nNk-1); i++)
			{
				j=i*4;
				CipherKey[i]= PackFrom(KEY, j);
			}

			for(i=0; i<=(_nNk-1); i++)
			{
				_nFKey[i]=CipherKey[i];
			}

			j=_nNk;
			k=0;
			while(j<N)
			{
				_nFKey[j]=_nFKey[j-_nNk] ^ SubByte(RotateLeft(_nFKey[j-1], 24)) ^ _nRCo[k];
				if(_nNk<=6)
				{
					i=1;
					while((i<_nNk) && ((i+j)< N))
					{
						_nFKey[i+j]=_nFKey[i+j-_nNk] ^ _nFKey[i+j-1];
						i=i+1;
					}
				}
				else
				{
					// Problem fixed here
					i=1;
					while((i<4) && (i+j)<N)
					{
						_nFKey[i+j]=_nFKey[i+j-_nNk] ^ _nFKey[i+j-1];
						i=i+1;
					}
					if((j+4)<N)
					{
						_nFKey[j+4]=_nFKey[j+4-_nNk] ^ SubByte(_nFKey[j+3]);
					}
				
					i = 5;
					while((i<_nNk) && (i+j)<N)
					{
						_nFKey[i+j]=_nFKey[i+j-_nNk] ^ _nFKey[i+j-1];
						i=i+1;
					}
				}

				j=j+_nNk;
				k=k+1;
			}

			for(j=0; j<=(_nNb-1); j++)
			{
				_nRKey[j+N-nb]=_nFKey[j];
			}

			i = _nNb;
			while(i<(N-_nNb))
			{
				k=N-_nNb-i;
				for(j=0; j<=(_nNb-1); j++)
				{
					_nRKey[k+j]=InvMixCol(_nFKey[i+j]);
				}
				i=i+_nNb;
			}

			j=N-_nNb;
			while(j<N)
			{
				_nRKey[j-N+_nNb]=_nFKey[j];
				j=j+1;
			}
		}

		//*******************************************************************************
		// encrypt (SUB)
		//*******************************************************************************
		private void Encrypt(byte[] buff)
		{
			int i=0, j=0, k=0, m=0;
			int[] a=new int[8];
			int[] b=new int[8];
			int[] x, Y, t;
			
			for(i=0; i<=(_nNb-1); i++)
			{
				j=i*4;
				a[i]=PackFrom(buff, j);
				a[i]=a[i] ^ _nFKey[i];
			}

			k=_nNb;
			x=a;
			Y=b;

			for(i=1; i<=(_nNr-1); i++)
			{
				for(j=0; j<=(_nNb-1); j++)
				{
					m=j*3;
					Y[j]=_nFKey[k] ^ _nFTable[x[j] & _nOnBits[7]] 
						^ RotateLeft(_nFTable[RShift(x[_nFi[m]], 8) & _nOnBits[7]], 8)
						^ RotateLeft(_nFTable[RShift(x[_nFi[m+1]], 16) & _nOnBits[7]], 16) 
						^ RotateLeft(_nFTable[RShift(x[_nFi[m+2]], 24) & _nOnBits[7]], 24);
					k=k+1;
				}
				t=x;
				x=Y;
				Y=t;
			}

			for(j=0; j<=(_nNb-1); j++)
			{
				m=j*3;
				Y[j]=_nFKey[k] ^ _nFbSub[x[j] & _nOnBits[7]]
					^ RotateLeft(_nFbSub[RShift(x[_nFi[m]], 8) & _nOnBits[7]], 8)
					^ RotateLeft(_nFbSub[RShift(x[_nFi[m+1]], 16) & _nOnBits[7]], 16)
					^ RotateLeft(_nFbSub[RShift(x[_nFi[m+2]], 24) & _nOnBits[7]], 24);
				k = k + 1;
			}

			for(i=0; i<=(_nNb-1); i++)
			{
				j=i*4;
				UnpackFrom(Y[i], ref buff, j);
				x[i]=0;
				Y[i]=0;
			}
		}

		//*******************************************************************************
		// decrypt (SUB)
		//*******************************************************************************
		private void Decrypt(byte[] buff)
		{
			int i=0, j=0, k=0, m=0;
			int [] a=new int[8];
			int [] b=new int[8];
			int [] x, Y, t;

			for(i=0; i<=(_nNb-1); i++)
			{
				j=i*4;
				a[i]=PackFrom(buff, j);
				a[i]=a[i] ^ _nRKey[i];
			}

			k=_nNb;
			x=a;
			Y=b;

			for(i=1; i<=(_nNr-1); i++)
			{
				for(j=0; j<=(_nNb-1); j++)
				{
					m=j*3;
					Y[j]=_nRKey[k] ^ _nRTable[x[j] & _nOnBits[7]] ^ 
						RotateLeft(_nRTable[RShift(x[_nRi[m]], 8) & _nOnBits[7]], 8) ^
						RotateLeft(_nRTable[RShift(x[_nRi[m+1]], 16) & _nOnBits[7]], 16) ^
						RotateLeft(_nRTable[RShift(x[_nRi[m+2]], 24) & _nOnBits[7]], 24);
					k = k + 1;
				}
				t = x;
				x = Y;
				Y = t;
			}
			
			for(j=0; j<=(_nNb-1); j++)
			{
				m=j*3;
				Y[j]=_nRKey[k] ^ _nRbSub[x[j] & _nOnBits[7]]
					^ RotateLeft(_nRbSub[RShift(x[_nRi[m]], 8) & _nOnBits[7]], 8)
					^ RotateLeft(_nRbSub[RShift(x[_nRi[m+1]], 16) & _nOnBits[7]], 16)
					^ RotateLeft(_nRbSub[RShift(x[_nRi[m+2]], 24) & _nOnBits[7]], 24);
				k = k + 1;
			}

			for(i=0; i<=(_nNb-1); i++)
			{
				j=i*4;
				UnpackFrom(Y[i], ref buff, j);
				x[i]=0;
				Y[i]=0;
			}
		}

		//*******************************************************************************
		// IsInitialized (FUNCTION)
		//*******************************************************************************
		private bool IsInitialized(byte [] bArray)
		{
			return (bArray.Length>0); 
		}

		//*******************************************************************************
		// EncryptData (FUNCTION)
		// Takes the message, whatever the size, and password in one call and does
		// everything for you to return an encoded/encrypted message
		//*******************************************************************************
		public byte[] EncryptData(byte[] bytMessage, byte [] bytPassword)
		{
			byte[] bytIn, bytOut;
			byte[] bytLen=new byte[4];
			byte[] bytKey=new byte[32];
			byte[] bytTemp=new byte[32];
			int lCount=0, lLength=0, lEncodedLength=0;

			if(!IsInitialized(bytMessage))
			{
				return bytMessage; 
			}
			if(!IsInitialized(bytPassword))
			{
				return bytPassword; 
			}

			// Use first 32 bytes of the password for the key
			for(lCount=0; lCount<bytPassword.Length; lCount++)
			{
				bytKey[lCount]=bytPassword[lCount];
				if(lCount==31)
				{
					break;
				}
			}

			// Prepare the key; assume 256 bit block and key size
			GenTables();
			GenKey(8, 8, bytKey);

			// We are going to put the message size on the front of the message
			// in the first 4 bytes. If the length is more than a max int we are
			// in trouble
			lLength=bytMessage.Length;
			lEncodedLength=lLength+4;

			// The encoded length includes the 4 bytes stuffed on the front
			// and is padded out to be modulus 32
			if((lEncodedLength % 32)!= 0)
			{
				lEncodedLength=lEncodedLength+32-(lEncodedLength % 32);
			}

			bytIn=new byte[lEncodedLength];
			bytOut=new byte[lEncodedLength];
			IntToByte(lLength, ref bytIn);
			
			//bytMessage.CopyTo(bytIn, 4);  
			Copy(ref bytIn, 4, bytMessage, 0, lLength);  
			
			for(lCount=0; lCount<=(lEncodedLength-1); lCount=lCount+32)
			{
				Copy(ref bytTemp, 0, bytIn, lCount,32);  
				//Encrypt Block by Block
				Encrypt(bytTemp);
				Copy(ref bytOut, lCount, bytTemp, 0, 32);  
			}

			return bytOut;
		}

		/// <summary>
		/// Decrypt Function /Oposite of Encrypt
		/// </summary>
		/// <param name="bytIn"></param>
		/// <param name="bytPassword"></param>
		/// <returns></returns>
		public byte[] DecryptData(byte[] bytIn, byte[] bytPassword)
		{
			byte[] bytMessage, bytOut;
			byte[] bytLen=new byte[4];
			byte[] bytKey=new byte[32];
			byte[] bytTemp=new byte[32];
			int lCount=0, lLength=0, lEncodedLength=0;

			if(!IsInitialized(bytIn))
			{
				return bytIn; 
			}
			if(!IsInitialized(bytPassword))
			{
				return bytPassword; 
			}

			lEncodedLength=bytIn.Length;
		
			if((lEncodedLength % 32) !=0)
			{
				return bytIn;
			}

			// Use first 32 bytes of the password for the key
			for(lCount=0; lCount<bytPassword.Length; lCount++)
			{
				bytKey[lCount]=bytPassword[lCount];
				if(lCount==31)
				{
					break;
				}
			}

			// Prepare the key; assume 256 bit block and key size
			GenTables();
			GenKey(8, 8, bytKey);

			// The output array needs to be the same size as the input array
			bytOut=new byte[lEncodedLength];

			for(lCount=0; lCount<lEncodedLength; lCount=lCount+32)
			{
				Copy(ref bytTemp, 0, bytIn, lCount, 32); 
				//Decrypt Block by Block
				Decrypt(bytTemp);
				Copy(ref bytOut, lCount, bytTemp, 0, 32); 
			}

			lLength=ByteToInt(bytOut);

			// Make sure the length is consistent with our data
			if(lLength>lEncodedLength-4)
			{
				return bytIn;
			}

			// Prepare the output message byte array
			bytMessage=new byte[lLength];
			Copy(ref bytMessage, 0, bytOut, 4, lLength); 
			
			return bytMessage;
		}
		
		
		//Sum Function to help CopyMemory, Hex, Int, Byte Conversion  
		private void Copy(ref byte[] Destination, int DestIndex, byte[] Source, int SrcIndex, int Length)
		{
			for(int j=0; j<Length; j++)
			{
				Destination[DestIndex+j]=Source[j+SrcIndex];
			}
		}

		private void IntToByte(int nNumber, ref byte[] bytOut)
		{
			string sText=Convert.ToString(nNumber,16);
			
			if(sText.Length<8)
			{
				sText=new String('0',(8-sText.Length))+sText;  
			}
			char[] cChars=sText.ToCharArray();
			byte[] nByteOut=new byte[4];

			for(int nCount=0; nCount<cChars.Length; nCount=nCount+2)
			{
				byte b=(byte)(Convert.ToByte(cChars[nCount].ToString(), 16)<<4); 
				b=(byte)(b | Convert.ToByte(cChars[nCount+1].ToString(), 16) & 0x0F); 
				nByteOut[nCount/2]=b;
			}
			bytOut[3]=nByteOut[0];
			bytOut[2]=nByteOut[1];
			bytOut[1]=nByteOut[2];
			bytOut[0]=nByteOut[3];
			return;
		}

		private int ByteToInt(byte[] bytIn)
		{
			int nNumber=0;
			nNumber=bytIn[3];
			nNumber=(nNumber<<8) | bytIn[2];
			nNumber=(nNumber<<8) | bytIn[1];
			nNumber=(nNumber<<8) | bytIn[0];
			return nNumber;
		}
		
		public byte[] StringToByte(string sText)
		{
			int nCount=0;
			char[] cChars=new char[sText.Length];
			byte[] nByteOut=new byte[2*cChars.Length];
			cChars=sText.ToCharArray();

			for(nCount=0; nCount<nByteOut.Length; nCount=nCount+2)
			{
				nByteOut[nCount]=(byte)cChars[nCount/2];
			}
			return nByteOut;
		}
		
		public string ByteToHexString(byte[] nBytes)
		{
			char[] HexDigits ={'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
			char[] cChrs = new char[nBytes.Length * 2];
			
			for(int i=0; i<nBytes.Length; i++) 
			{
				int b=nBytes[i];
				cChrs[i*2]=HexDigits[b >> 4];
				cChrs[i*2+1]=HexDigits[b & 0xF];
			}
			return new string(cChrs);
		}

		public string ByteToString(byte[] nBytes)
		{
			char[] cChrs = new char[nBytes.Length/2];
			
			for(int i=0; i<nBytes.Length; i=i+2) 
			{
				cChrs[i/2]=(char)nBytes[i];
			}
			return new string(cChrs);
		}
		public byte[] HexToByte(string sHexData)
		{
			byte[] nByteOut=new byte[sHexData.Length/2];
			char[] cChars=sHexData.ToCharArray();
			for(int nCount=0; nCount<cChars.Length; nCount=nCount+2)
			{
				byte b=(byte)(Convert.ToByte(cChars[nCount].ToString(), 16)<<4); 
				b=(byte)(b | Convert.ToByte(cChars[nCount+1].ToString(), 16) & 0x0F); 
				nByteOut[nCount/2]=b;
			}
			return nByteOut;
		}
	}
}