Click here to Skip to main content
Click here to Skip to main content

Two Efficient Classes for RC4 and Base64 Stream Cipher Algorithms

, 15 Apr 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Two fast and efficient classes of RC4 and Base64 stream cipher algorithms

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

#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:

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

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.

#include "Base64_RC4.h" 

A Demo of Using the Classes

#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)

Share

About the Author

Jerry Jiang
Founder Maple Technology Software
Canada Canada
Jerry Jiang(BOLIANG JIANG)
 
Education:Master of Computer Science.
 
A passionate software developer since 1992,now lives in Vancouver.
 
jerry@mptsoft.com

Comments and Discussions

 
NewsYour RC4 Decript function maybe incorrect. PinmemberNullMiracle4-May-14 22:44 
QuestionSwap Problem [modified] PinmemberSee_Sharp4-Sep-12 9:04 
Just one comment regarding your swap:
<pre>
#define SWAP(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
</pre>
 
I have used your code, and the swap is fine, but if you are swapping sbox[i] and sbox[j], where i == j, you are zeroing the values out.
 
Because of this, I think you need to add into your code:
 
<pre>
if (i != j) SWAP(sbox[i], sbox[j])
</pre>
 
Or modify the swap to use a temp variable. I'm not sure if the VS C++ compiler will optimize the trivial swap with a temp variable.
 
I used this to generate millions of bits, and I noticed the sbox elements began zeroing out, and this fixed the problem Smile | :)

-- modified 4-Sep-12 14:13pm.
AnswerRe: Swap Problem PinmemberJerry Jiang17-Sep-12 21:07 
QuestionSeems to mess up on a NULL PinmemberMember 85519101-Jul-12 10:32 
AnswerRe: Seems to mess up on a NULL PinmemberMember 85519101-Jul-12 10:38 
GeneralRe: Seems to mess up on a NULL PinmemberJerry Jiang17-Sep-12 21:19 
QuestionQuery on the key. PinmemberSnehamoy Banerjee21-Aug-11 3:05 
AnswerRe: Query on the key. PinmemberJerry Jiang24-Sep-11 23:19 
GeneralNew code snippet for char *Encrypt(char *pszText,const char *pszKey) in class CRC4 PinmemberJerry Jiang10-Jul-09 9:22 
Generalneeds a lot more. Pinmembermadicursar13-Apr-09 23:56 
GeneralRe: needs a lot more. [modified] PinmemberJerry Jiang14-Apr-09 10:52 
GeneralMy vote of 2 PinmemberNick Kulikovsky13-Apr-09 15:41 
GeneralRe: My vote of 2 [modified] PinmemberJerry Jiang13-Apr-09 17:50 
GeneralRe: My vote of 2 Pinmemberyafan15-Apr-09 12:42 
GeneralRe: My vote of 2 [modified] PinmemberJerry Jiang15-Apr-09 18:05 
GeneralMy vote of 2 Pinmembersurajfrommumbai12-Apr-09 19:16 
GeneralRe: My vote of 2 [modified] PinmemberJerry Jiang12-Apr-09 20:08 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 15 Apr 2009
Article Copyright 2009 by Jerry Jiang
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid