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);
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++)
{
*(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));
k = *(sbox + ((*(sbox + i) + *(sbox + j)) &0xff ));
if(k == *(pszText + m))
k = 0;
*(pszText + m) ^= k;
}
return pszText;
}
char *Decrypt(char *pszText,const char *pszKey)
{
return Encrypt(pszText,pszKey) ;
}
private:
unsigned char sbox[256];
unsigned char key[256],k;
int m, n, i, j, ilen;
};
;
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 )
{
*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 )
{
*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) == '=')
{
*(dstp--) = '\0';
*(dstp--) = '\0';
}
else if(*(srcp-1) == '=')
*(dstp--) = '\0';
*dstp = '\0';
return dst;
};
size_t B64_length(size_t len)
{
size_t npad = len%3;
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";
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);
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.