Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Two Efficient Classes for RC4 and Base64 Stream Cipher Algorithms

4.81/5 (18 votes)
15 Apr 2009CPOL3 min read 80K   2.8K  
Two fast and efficient classes of RC4 and Base64 stream cipher algorithms
Image 1

Introduction

This article provides two efficient and handy wrapping C++ classes of Base64 and RC4 stream cipher algorithms.

Background

I programmed the classes after I searched the internet and found very few implementations are neat and efficient enough for practical use as lower cipher classes in the project.

Introduction of Algorithms 

What is RC4

RC4 was created by Ron Rivest of RSA Security in 1987. It is one of the most widely-used software stream cipher and is used in popular protocols such as Secure Sockets Layer (SSL) (to protect Internet traffic) and WEP (to secure wireless networks). RC4 is used in many commercial software packages such as Lotus Notes and Oracle Secure SQL.

There are two parts in RC4 algorithm, a 'key scheduling algorithm' (KSA) which turns a random key (typically between 40 and 256 bits) into an initial permutation of S-box of N(power of 2). The other part is 'pseudorandom number generator(' PRNG), PRNG uses the permutation to generate a pseudo-random number sequence which is XORed with the plaintext to give the cipher text.

RC4 is a fast cipher algorithm and about 10 times faster than DES(Data Encryption Standard).

This wrapping class CRC4 is a handy version for using by avoiding string terminator ¡®\0¡¯ in the middle of the encoded text data. It is annoying and bug-hidden if you want to handle the encoded text data as a string without knowing that the '\0' character could truncate your cipher text to be incomplete.

The Code of Class CRC4

C++
#define SWAP(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
class CRC4 
{
public:

	  CRC4 () 
	  {
		memset(sbox,0,256);
		memset(key,0,256);
	  }
	  virtual ~CRC4 ()
	  {							
		memset(sbox,0,256);  /* remove Key traces in memory  */
		memset(key,0,256);   
	  }

	  char *Encrypt(char *pszText,const char *pszKey) 
	  {
		i=0, j=0,n = 0;
		ilen = (int)strlen(pszKey);

		for (m = 0;  m < 256; m++)  /* Initialize the key sequence */
		{
			*(key + m)= *(pszKey + (m % ilen));
			*(sbox + m) = m;
		}
		for (m=0; m < 256; m++)
		{
			n = (n + *(sbox+m) + *(key + m)) &0xff;
			SWAP(*(sbox + m),*(sbox + n));
		}

		ilen = (int)strlen(pszText);
		for (m = 0; m < ilen; m++)
		{
			i = (i + 1) &0xff;
			j = (j + *(sbox + i)) &0xff;
			SWAP(*(sbox+i),*(sbox + j));  /* randomly Initialize 
							the key sequence */
			k = *(sbox + ((*(sbox + i) + *(sbox + j)) &0xff ));
			if(k == *(pszText + m))       /* avoid '\0' among the 
							encoded text; */
			       k = 0;
			*(pszText + m) ^=  k;
		}

		return pszText;
	  }

	  char *Decrypt(char *pszText,const char *pszKey)
	  {
	        return Encrypt(pszText,pszKey) ;  /* using the same function 
							as encoding */
	  }

private:
          unsigned char sbox[256];      /* Encryption array             */
          unsigned char key[256],k;     /* Numeric key values           */
	 int  m, n, i, j, ilen;        /* Ambiguously named counters   */
};
;

What is BASE64

Base64 is a different way of interpreting bits of data in order to transmit that data over a text-only medium, such as the body of an e-mail.

The Base64 Content-Transfer-Encoding is designed to represent arbitrary sequences of octets in a form that need not be humanly readable. It is widely used in e-mail encoding and also .NET View state encoding for its efficiency.

Base64 algorithm processes input in 24bit chunks by converting each chunk into 4 bytes of output. It does so by splitting input into four 6 bit groups and using these as indexes in the following substitution table:

C++
const char base64_map[] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

If an input is not a multiple of 3 bytes, it's padded with zeros. In this case, the output bytes that consist entirely of the pad data are replaced with '='.

Example of Base64

An input of 0x00 0x45 0xF2 is equivalent to 00000000 01000101 11110010 bit sequence, which is then split into 000000 000100 010111 110010 and these are substituted to produce the following base64 encoding 'A' 'E' 'X' 'y'.

The code of class CBase64

C++
class CBase64
{
public:
	CBase64(){}

	char *Encrypt(const char * srcp, int len, char * dstp)
	{
		register int i = 0;
		char *dst = dstp;

		for (i = 0; i < len - 2; i += 3)
		{
			*dstp++ = *(base64_map + ((*(srcp+i)>>2)&0x3f));
			*dstp++ = *(base64_map + ((*(srcp+i)<< 4)&0x30 | (
                                *(srcp+i+1)>>4)&0x0f ));
			*dstp++ = *(base64_map + ((*(srcp+i+1)<<2)&0x3C | (
                                *(srcp+i+2)>>6)&0x03));
			*dstp++ = *(base64_map + (*(srcp+i+2)&0x3f));
		}
		srcp += i;
		len -= i;

		if(len & 0x02 ) /* (i==2) 2 bytes left,pad one byte of '=' */
		{      
			*dstp++ = *(base64_map + ((*srcp>>2)&0x3f));
			*dstp++ = *(base64_map + ((*srcp<< 4)&0x30 | (
                                *(srcp+1)>>4)&0x0f ));
			*dstp++ = *(base64_map + ((*(srcp+1)<<2)&0x3C) );
			*dstp++ = '=';
		}
		else if(len & 0x01 )  /* (i==1) 1 byte left,pad two bytes of '='  */
		{ 
			*dstp++ = *(base64_map + ((*srcp>>2)&0x3f));
			*dstp++ = *(base64_map + ((*srcp<< 4)&0x30));
			*dstp++ = '=';
			*dstp++ = '=';
		}

		*dstp = '\0';

		return dst;
	}

	void *Decrypt(const char * srcp, int len, char * dstp)
	{
		register int i = 0;
		void *dst = dstp;

		while(i < len)
		{
			*dstp++ = (B64_offset[*(srcp+i)] <<2 | 
                                B64_offset[*(srcp+i+1)] >>4);
			*dstp++ = (B64_offset[*(srcp+i+1)]<<4 | 
                                B64_offset[*(srcp+i+2)]>>2);
			*dstp++ = (B64_offset[*(srcp+i+2)]<<6 |
                                B64_offset[*(srcp+i+3)] );
			i += 4;
		}
		srcp += i;
		
		if(*(srcp-2) == '=')  /* remove 2 bytes of '='  padded while encoding */
		{	 
			*(dstp--) = '\0';
			*(dstp--) = '\0';
		}
		else if(*(srcp-1) == '=') /* remove 1 byte of '='  padded while encoding */
			*(dstp--) = '\0';

		*dstp = '\0';

		return dst;
	};

	size_t B64_length(size_t len)
	{
		size_t  npad = len%3;
                // padded for multiple of 3 bytes
		size_t  size = (npad > 0)? (len +3-npad ) : len;
         return  (size*8)/6;
	}

	size_t Ascii_length(size_t len)
	{
		return  (len*6)/8;
	}

};

Using the Code

If you want to use the code in your project, just copy the code directly from this page and paste into your source file or copy Base64_RC4.h into your project folder and insert a header line.

C++
#include "Base64_RC4.h" 

A Demo of Using the Classes

C++
#include "Base64_RC4.h"
void main()
{
	char str[64] = "This is a test for RC4 cypher";
/* Test rc4 encoding and decoding here */
	CRC4 rc4;
	printf("Demo for RC4 \n\n");
	printf("Plain text: %s \n",str);
	rc4.Encrypt(str,"Key");
	printf("Encoded string: %s \n",str);
	rc4.Decrypt(str,"Key");
	printf("Decoded string: %s \n",str);
/* Test Base64  encoding and decoding here */
	strcpy(str, "This is a test for Base64 cypher");
	CBase64  base64;
	char *dst;
	dst = (char*)malloc( base64.B64_length(strlen(str))+1);
	if(dst == NULL)
		return;
	printf("\n\nDemo for Base64 \n\n");
	printf("Plain text: %s \n",str);
	base64.Encrypt(str,strlen(str),dst);
	printf("Encoded string: %s\n",dst);
	memset(str,0,sizeof(str));
	base64.Decrypt(dst,strlen(dst),str);
	printf("Decoded string: %s\n",str);
	free(dst);
	getchar();
}

Points of Interest

Encoding/decoding is a lot of fun and critical for security, try to use it and feel its magic.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)