/**@@@+++@@@@******************************************************************
**
** Microsoft Windows Media
** Copyright (C) Microsoft Corporation. All rights reserved.
**
***@@@---@@@@******************************************************************
*/

#include <drmcommon.h>
#include <drmrc4.h>
#if defined(DX_SEP_CC50) && defined(WMDRM_ON_SEP)

#define CRYS_RC4_Init WA_CRYS_RC4_Init
#define CRYS_RC4_Stream WA_CRYS_RC4_Stream
#endif
#ifndef DX_WMDRM_USE_CRYS
/******************************************************************************/
DRM_VOID DRM_API DRM_RC4_KeySetup(
        OUT   RC4_KEYSTRUCT  *pKS,
    IN        DRM_DWORD       cbKey,
    IN  const DRM_BYTE       *pbKey )
{
    DRM_BYTE j;
    DRM_BYTE k;
    DRM_BYTE t;
    DRM_INT  i;

    for (i=0;i<RC4_TABLESIZE;i++)
    {
        PUT_BYTE( pKS->S, i, (DRM_BYTE)i);
    }
    
    pKS->i = 0;
    pKS->j = 0;
    j      = 0;
    k      = 0;
    for (i=0;i<RC4_TABLESIZE;i++)
    {
        t = GET_BYTE(pKS->S,i);
        j = (DRM_BYTE)((j + t + GET_BYTE(pbKey, k)) % RC4_TABLESIZE);        
        PUT_BYTE( pKS->S, i, GET_BYTE(pKS->S, j) );
        PUT_BYTE(pKS->S, j, t);
        k = (DRM_BYTE) ((k + 1) % cbKey);
    }
}

/******************************************************************************/
DRM_VOID DRM_API DRM_RC4_Cipher(
    IN OUT RC4_KEYSTRUCT *pKS,
    IN     DRM_UINT       cbBuffer,
    IN OUT DRM_BYTE      *pbBuffer )
{
    DRM_BYTE  i = pKS->i;
    DRM_BYTE  j = pKS->j;    
    DRM_BYTE *p = pKS->S;
    DRM_DWORD ib = 0;

    while (cbBuffer--)
    {
        DRM_BYTE bTemp1 = 0;
        DRM_BYTE bTemp2 = 0;

        i = ((i + 1) & (RC4_TABLESIZE - 1));
        bTemp1 = GET_BYTE(p,i);
        j = ((j + bTemp1) & (RC4_TABLESIZE - 1));
        
        PUT_BYTE(p,i,GET_BYTE(p,j));
        PUT_BYTE(p,j,bTemp1);
        bTemp2 = GET_BYTE(pbBuffer,ib);

        bTemp2 ^= GET_BYTE(p, (GET_BYTE(p,i) + bTemp1) & (RC4_TABLESIZE - 1));
        PUT_BYTE(pbBuffer,ib,bTemp2);
        ib++;
    }

    pKS->i = i;
    pKS->j = j;
}

#else /*DX_WMDRM_USE_CRYS*/
/******************************************************************************/
/*software function for key larger than 16 bytes and less than 4 bytes*/
static DRM_VOID DRM_API DRM_RC4_KeySetup_SW(
        OUT   RC4_KEYSTRUCT  *pKS,
    IN        DRM_DWORD       cbKey,
    IN  const DRM_BYTE       *pbKey )
{
    DRM_BYTE j;
    DRM_BYTE k;
    DRM_BYTE t;
    DRM_INT  i;

    for (i=0;i<RC4_TABLESIZE;i++)
    {
        PUT_BYTE( pKS->rc4CTX.rc4Sw.S, i, (DRM_BYTE)i);
    }
    
    pKS->rc4CTX.rc4Sw.i = 0;
    pKS->rc4CTX.rc4Sw.j = 0;
    j      = 0;
    k      = 0;
    for (i=0;i<RC4_TABLESIZE;i++)
    {
        t = GET_BYTE(pKS->rc4CTX.rc4Sw.S,i);
        j = (DRM_BYTE)((j + t + GET_BYTE(pbKey, k)) % RC4_TABLESIZE);        
        PUT_BYTE( pKS->rc4CTX.rc4Sw.S, i, GET_BYTE(pKS->rc4CTX.rc4Sw.S, j) );
        PUT_BYTE(pKS->rc4CTX.rc4Sw.S, j, t);
        k = (DRM_BYTE) ((k + 1) % cbKey);
    }
}

/******************************************************************************/
static DRM_VOID DRM_API DRM_RC4_Cipher_SW(
    IN OUT RC4_KEYSTRUCT *pKS,
    IN     DRM_UINT       cbBuffer,
    IN OUT DRM_BYTE      *pbBuffer )
{
    DRM_BYTE  i = pKS->rc4CTX.rc4Sw.i;
    DRM_BYTE  j = pKS->rc4CTX.rc4Sw.j;    
    DRM_BYTE *p = pKS->rc4CTX.rc4Sw.S;
    DRM_DWORD ib = 0;

    while (cbBuffer--)
    {
        DRM_BYTE bTemp1 = 0;
        DRM_BYTE bTemp2 = 0;

        i = ((i + 1) & (RC4_TABLESIZE - 1));
        bTemp1 = GET_BYTE(p,i);
        j = ((j + bTemp1) & (RC4_TABLESIZE - 1));
        
        PUT_BYTE(p,i,GET_BYTE(p,j));
        PUT_BYTE(p,j,bTemp1);
        bTemp2 = GET_BYTE(pbBuffer,ib);

        bTemp2 ^= GET_BYTE(p, (GET_BYTE(p,i) + bTemp1) & (RC4_TABLESIZE - 1));
        PUT_BYTE(pbBuffer,ib,bTemp2);
        ib++;
    }

    pKS->rc4CTX.rc4Sw.i = i;
    pKS->rc4CTX.rc4Sw.j = j;
}


DRM_VOID DRM_API DRM_RC4_KeySetup(
        OUT   RC4_KEYSTRUCT  *pKS,
    IN        DRM_DWORD       cbKey,
    IN  const DRM_BYTE       *pbKey )
{
/*If the CRYS RC4 engine is software we can use CRYS without key restriction*/
#if (LLF_RC4_ENGINE_TYPE==CRYS_DEFS_SW_ENGINE_TYPE)
		CRYS_RC4_Init(&pKS->rc4CTX.rc4Hw,(DxUint8_t*)pbKey,cbKey);
		pKS->rc4Type = DRM_RC4_HW;
#else
	if((cbKey > 16)||(cbKey < 4 ))
	{
		DRM_RC4_KeySetup_SW(pKS,cbKey,pbKey);
		pKS->rc4Type = DRM_RC4_SW;
	}
	else
	{
		CRYS_RC4_Init(&pKS->rc4CTX.rc4Hw,(DxUint8_t*)pbKey,cbKey);
		pKS->rc4Type = DRM_RC4_HW;

	}
#endif	
	return;
}

/******************************************************************************/
DRM_VOID DRM_API DRM_RC4_Cipher(
    IN OUT RC4_KEYSTRUCT *pKS,
    IN     DRM_UINT       cbBuffer,
    IN OUT DRM_BYTE      *pbBuffer )
{
	if(pKS->rc4Type != DRM_RC4_HW)
	{
		DRM_RC4_Cipher_SW(pKS,cbBuffer,pbBuffer);
	}
	else
	{
#ifdef DX_ARM_INTEGRATOR_DEBUG
		DRM_DWORD loop;
		DRM_DWORD dataLen;
		loop = cbBuffer/0x4000;
		if(cbBuffer%0x4000)
		{
			loop++;
		}
		while(loop)
		{
			if(cbBuffer > 0x4000)
			{
				dataLen = 0x4000;	
			}
			else
			{
				dataLen = cbBuffer;	
			}
			
			CRYS_RC4_Stream(&pKS->rc4CTX.rc4Hw,pbBuffer,dataLen,pbBuffer);
			pbBuffer = pbBuffer + dataLen;
			cbBuffer = cbBuffer - dataLen;
			loop--;
		}
#else
		CRYS_RC4_Stream(&pKS->rc4CTX.rc4Hw,pbBuffer,cbBuffer,pbBuffer);

#endif	
	}
	return;
}



#endif
