Crypt-Rainbow
view release on metacpan or search on metacpan
/*****************************************************
* Rainbow Cipher header file for ANSI C *
* Chang-Hyi Lee and Jeong-Soo Kim *
* Digital Communication Lab., *
* SAIT, Samsung Advanced Institute of Technology *
*****************************************************/
#undef BIG_ENDIAN
#ifndef LITTLE_ENDIAN /* jcd */
#define LITTLE_ENDIAN
#endif
#include <stdio.h>
/* #include <stdlib.h> */
#include <time.h>
#include <memory.h>
/* #include <assert.h> */
#include <string.h>
/* Defines: */
#define BITSPERBLOCK 128 /* Number of bits in a cipher block */
#define BLOCKSIZE (BITSPERBLOCK/8) /* # bytes in a cipher block */
#define BLOCK_WSIZE (BITSPERBLOCK/32) /* # WORD32's in a cipher block */
#define DIR_ENCRYPT 0 /* Are we encrpyting? */
#define DIR_DECRYPT 1 /* Are we decrpyting? */
#define MODE_ECB 1 /* Are we ciphering in ECB mode? */
#define MODE_CBC 2 /* Are we ciphering in CBC mode? */
#define MODE_CFB1 3 /* Are we ciphering in 1-bit CFB mode? */
#define R_TRUE 1
#define R_FALSE 0
/* Error Codes : */
#define BAD_KEY_DIR -1 /* Key direction is invalid, e.g.,
unknown value */
#define BAD_KEY_MAT -2 /* Key material not of correct
length */
#define BAD_KEY_INSTANCE -3 /* Key passed is not valid */
#define BAD_KEY_LENGTH -4 /* Key size in bits is wrong */
#define BAD_CIPHER_MODE -5 /* Params struct passed to
cipherInit invalid */
#define BAD_CIPHER_STATE -6 /* Cipher in wrong state (e.g., not
initialized) */
#define BAD_CIPHER_INPUT -7 /* Wrong cipher input length */
#define MAX_KEY_SIZE 32 /* # of ASCII char's needed to
represent a key */
#define MAX_IV_SIZE 16 /* # bytes needed to
represent an IV */
#define SCHEDULE_KEY_SIZE 16*2*(R+1) /* total size of scheduled key */
#define R 7 /* proposed encryption round */
/* Typedefs: */
typedef unsigned char BYTE; /* 8 bit */
typedef unsigned short WORD16; /* 16 bit */
#ifdef __alpha
typedef unsigned int WORD32; /* 32 bit */
#else /* !__alpha */
typedef unsigned long WORD32; /* 32 bit */
#endif /* :__alpha */
/* The structure for key information */
typedef struct keyInstance {
BYTE direction; /* In our case this is negligible, since this
structure involve both enc/dec Keys */
int keyLen; /* Length of the key */
char keyMaterial[MAX_KEY_SIZE+1]; /* Raw key data in ASCII */
BYTE KS_Enc[SCHEDULE_KEY_SIZE]; /* encryption key */
BYTE KS_Dec[SCHEDULE_KEY_SIZE]; /* decryption key */
} keyInstance;
/* The structure for cipher information */
typedef struct cipherInstance {
BYTE mode; /* MODE_ECB, MODE_CBC, or MODE_CFB1 */
BYTE IV[MAX_IV_SIZE]; /* A possible Initialization Vector for
ciphering */
BYTE RED[512]; /* The S-box table RED=[f]|[f^(-1)] */
int blockSize; /* Here It is fixed : 128 */
} cipherInstance;
/* Function protoypes */
int makeKey(keyInstance *key, BYTE direction, int keyLen,
char *keyMaterial);
int cipherInit(cipherInstance *cipher, BYTE mode, char *IV);
int blockEncrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
int inputLen, BYTE *outBuffer);
int blockDecrypt(cipherInstance *cipher, keyInstance *key, BYTE *input,
int inputLen, BYTE *outBuffer);
#define WD(a) ((WORD32 *)(a)) /* for utility */
/* platform endianness: */
#if !defined(LITTLE_ENDIAN) && !defined(BIG_ENDIAN)
# if defined(_M_IX86) || defined(_M_I86) || defined(__alpha)
# define LITTLE_ENDIAN
# else
# error "Either LITTLE_ENDIAN or BIG_ENDIAN must be defined"
# endif
#elif defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
# error "LITTLE_ENDIAN and BIG_ENDIAN must not be simultaneously defined"
#endif /* !LITTLE_ENDIAN && !BIG_ENDIAN */
/* Microsoft C / Intel x86 optimizations: */
#if defined(_MSC_VER) && defined(_M_IX86)
# define HARDWARE_ROTATIONS
# define ASSEMBLER_CORE
#endif /* :(_MSC_VER && _M_IX86) */
#ifdef HARDWARE_ROTATIONS
# define ROTL(x, s) (_lrotl ((x), (s)))
# define ROTR(x, s) (_lrotr ((x), (s)))
#else /* !HARDWARE_ROTATIONS */
# define ROTL(x, s) (((x) << (s)) | ((x) >> (32 - (s))))
# define ROTR(x, s) (((x) >> (s)) | ((x) << (32 - (s))))
#endif /* :HARDWARE_ROTATIONS */
#ifdef LITTLE_ENDIAN
# ifdef MASKED_BYTE_EXTRACTION
# define GETB0(x) (((x) ) & 0xffU)
# define GETB1(x) (((x) >> 8) & 0xffU)
# define GETB2(x) (((x) >> 16) & 0xffU)
# define GETB3(x) (((x) >> 24) & 0xffU)
# else /* !MASKED_BYTE_EXTRACTION */
# define GETB0(x) ((BYTE) ((x) ))
# define GETB1(x) ((BYTE) ((x) >> 8))
# define GETB2(x) ((BYTE) ((x) >> 16))
# define GETB3(x) ((BYTE) ((x) >> 24))
# endif /* :MASKED_BYTE_EXTRACTION */
(data[2] & key[(RN)][0])^ \
(data[3] & key[(RN)][1]); \
tmp[3] = (data[0] & key[(RN)][3])^\
(data[1] & key[(RN)][0])^ \
(data[2] & key[(RN)][1])^ \
(data[3] & key[(RN)][2]); \
}
#define R_function(TABLE) \
{ /* R-layer */ \
data[0] = PUTB1((TABLE)[GETB0(tmp[0])])| \
PUTB0((TABLE)[256+GETB1(tmp[0])])| \
PUTB3((TABLE)[GETB2(tmp[0])])| \
PUTB2((TABLE)[256+GETB3(tmp[0])]); \
data[1] = PUTB2((TABLE)[GETB0(tmp[1])])| \
PUTB0((TABLE)[256+GETB2(tmp[1])])| \
PUTB3((TABLE)[GETB1(tmp[1])])| \
PUTB1((TABLE)[256+GETB3(tmp[1])]); \
data[2] = PUTB3((TABLE)[GETB0(tmp[2])])| \
PUTB0((TABLE)[256+GETB3(tmp[2])])| \
PUTB2((TABLE)[GETB1(tmp[2])])| \
PUTB1((TABLE)[256+GETB2(tmp[2])]); \
data[3] = PUTB2((TABLE)[GETB0(tmp[3])])| \
PUTB0((TABLE)[256+GETB2(tmp[3])])| \
PUTB3((TABLE)[GETB1(tmp[3])])| \
PUTB1((TABLE)[256+GETB3(tmp[3])]); \
}
#define ROUND_function(key_num) \
{ /* one round process 'F_function' in the document */ \
G_function(key_num); \
B_function(key_num+1); \
R_function(SBox); \
}
#define ONEBLOCK_CIPH /* here : only for the blockLen=16bytes */ \
{ /* one block encryption */ \
ROUND_function(0); \
ROUND_function(2); \
ROUND_function(4); \
ROUND_function(6); \
ROUND_function(8); \
ROUND_function(10); \
ROUND_function(12); \
G_function(14); \
B_function(15); \
COPY_BLOCK(data,tmp);\
}
int blockEncrypt (cipherInstance *cipher, keyInstance *keys, BYTE *input,
int inputLen, BYTE *outBuffer)
{
if (cipher == NULL) return BAD_CIPHER_STATE;
if (keys == NULL) return BAD_KEY_INSTANCE;
if (inputLen%128) return BAD_CIPHER_INPUT;
if (cipher->mode == MODE_ECB) {
RB_Enc_ecb (cipher->RED, keys->KS_Enc, input, inputLen, outBuffer);
return R_TRUE;
}
if (cipher->mode == MODE_CBC) {
RB_Enc_cbc (cipher->RED, keys->KS_Enc,cipher->IV, input, inputLen, outBuffer);
return R_TRUE;
}
if (cipher->mode == MODE_CFB1) {
RB_Enc_cfb1 (cipher->RED, keys->KS_Enc,cipher->IV, input, inputLen, outBuffer);
return R_TRUE;
}
return BAD_CIPHER_MODE;
}
/* ECB-mode encryption */
static void RB_Enc_ecb (BYTE *table, BYTE *cipherKey, BYTE *input, int inputLen,
BYTE *outBuffer)
{
WORD32 tmp[4], data[4], key[2*(R+1)][4];
WORD32 *scan, *tar;
BYTE *SBox;
int i, ib;
SBox = table;
scan = WD(cipherKey);
for (i=0; i<2*(R+1); i++) {
COPY_BLOCK(key[i], scan);
scan += 4;
}
ib = inputLen/BITSPERBLOCK; /* check # of cyphering blocks */
scan = WD(input);
tar = WD(outBuffer);
for (i=0; i<ib; i++) {
COPY_BLOCK(data, scan);
ONEBLOCK_CIPH; /* encrypt */
COPY_BLOCK(tar, data);
scan += BLOCK_WSIZE;
tar += BLOCK_WSIZE;
}
}
#define BLOCK_XOR(B, A) \
{ \
B[0] ^= A[0];\
B[1] ^= A[1];\
B[2] ^= A[2];\
B[3] ^= A[3];\
}
/* CBC-mode encryption */
static void RB_Enc_cbc (BYTE *table, BYTE *cipherKey, BYTE *iv, BYTE *input, int inputLen,
BYTE *outBuffer)
{
WORD32 tmp[4], data[4], key[2*(R+1)][4];
WORD32 *scan, *tar;
BYTE *SBox;
int i, ib;
SBox = table;
scan = WD(cipherKey);
for (i=0; i<2*(R+1); i++) {
COPY_BLOCK(key[i], scan);
scan += 4;
}
ib = inputLen/BITSPERBLOCK; /* check # of cyphering blocks */
scan = WD(input);
tar = WD(outBuffer);
COPY_BLOCK(data, scan);
BLOCK_XOR(data, WD(iv)); /* added initial vector */
ONEBLOCK_CIPH; /* encrypt */
COPY_BLOCK(tar, data);
for (i=1; i<ib; i++) {
scan += BLOCK_WSIZE;
tar += BLOCK_WSIZE;
BLOCK_XOR(data, scan); /* cipher block chaining */
ONEBLOCK_CIPH; /* encrypt */
COPY_BLOCK(tar, data);
}
}
#define LSHIFT_PAST(D, b) \
{ /* shift by 1bit of and paste 1bit to cipher input data */ \
dt = D[0]>>31; \
D[0] = (D[0]<<1)|b; \
df = (D[1]<<1)|dt; \
dt = D[1]>>31; \
D[1] = df; \
df = (D[2]<<1)|dt; \
dt = D[2]>>31; \
D[2] = df; \
D[3] = (D[3]<<1)|dt; \
}
/* CFB1-mode encryption */
static void RB_Enc_cfb1 (BYTE *table, BYTE *cipherKey, BYTE *iv, BYTE *input, int inputLen,
BYTE *outBuffer)
{
WORD32 tmp[4], data[4], feed[4], key[2*(R+1)][4], df,dt, *cnv;
BYTE *scan, *tar, *SBox;
register BYTE grab, bit, fback;
int i, j;
SBox = table;
cnv = WD(cipherKey);
for (i=0; i<2*(R+1); i++) {
COPY_BLOCK (key[i], cnv);
cnv += 4;
tmp[3] = (data[0] & key[(RN)][3])^\
(data[1] & key[(RN)][0])^ \
(data[2] & key[(RN)][1])^ \
(data[3] & key[(RN)][2]); \
}
//#define R_function(TABLE)
#define R_function(TABLE) \
{ /* R-layer */ \
data[0] = PUTB1((TABLE)[GETB0(tmp[0])])| \
PUTB0((TABLE)[256+GETB1(tmp[0])])| \
PUTB3((TABLE)[GETB2(tmp[0])])| \
PUTB2((TABLE)[256+GETB3(tmp[0])]); \
data[1] = PUTB2((TABLE)[GETB0(tmp[1])])| \
PUTB0((TABLE)[256+GETB2(tmp[1])])| \
PUTB3((TABLE)[GETB1(tmp[1])])| \
PUTB1((TABLE)[256+GETB3(tmp[1])]); \
data[2] = PUTB3((TABLE)[GETB0(tmp[2])])| \
PUTB0((TABLE)[256+GETB3(tmp[2])])| \
PUTB2((TABLE)[GETB1(tmp[2])])| \
PUTB1((TABLE)[256+GETB2(tmp[2])]); \
data[3] = PUTB2((TABLE)[GETB0(tmp[3])])| \
PUTB0((TABLE)[256+GETB2(tmp[3])])| \
PUTB3((TABLE)[GETB1(tmp[3])])| \
PUTB1((TABLE)[256+GETB3(tmp[3])]); \
}
/*
#define ROUND_function(key_num) \
{ \
G_function((key_num)); \
B_function((key_num+1)); \
R_function(SBox); \
}
*/
#define ONEBLOCK_CIPH /* here : only for the blockLen=16bytes */\
{ /* one block encryption */ \
ROUND_function(0); \
ROUND_function(2); \
ROUND_function(4); \
ROUND_function(6); \
ROUND_function(8); \
ROUND_function(10); \
ROUND_function(12); \
G_function(14); \
B_function(15); \
COPY_BLOCK(data,tmp);\
}
int blockDecrypt (cipherInstance *cipher, keyInstance *keys, BYTE *input,
int inputLen, BYTE *outBuffer)
{
if (cipher == NULL) return BAD_CIPHER_STATE;
if (keys == NULL) return BAD_KEY_INSTANCE;
if (inputLen%128) return BAD_CIPHER_INPUT;
if (cipher->mode == MODE_ECB) {
RB_Dec_ecb (cipher->RED, keys->KS_Dec, input, inputLen, outBuffer);
return R_TRUE;
}
if (cipher->mode == MODE_CBC) {
RB_Dec_cbc (cipher->RED, keys->KS_Dec, cipher->IV, input, inputLen, outBuffer);
return R_TRUE;
}
if (cipher->mode == MODE_CFB1) {
RB_Dec_cfb1 (cipher->RED, keys->KS_Enc,cipher->IV, input, inputLen, outBuffer);
return R_TRUE;
}
return BAD_CIPHER_MODE;
}
/* ECB-mode encryption */
static void RB_Dec_ecb (BYTE *table, BYTE *cipherKey, BYTE *input, int inputLen, BYTE *outBuffer)
{
WORD32 tmp[4], data[4],key[2*(R+1)][4];
WORD32 *scan, *tar;
BYTE *SBox;
int i, ib;
SBox = table;
scan = WD(cipherKey);
for (i=0; i<2*(R+1); i++) {
COPY_BLOCK (key[i], scan);
scan += 4;
}
ib = inputLen/BITSPERBLOCK; /* check # of cyphering blocks */
scan = WD(input);
tar = WD(outBuffer);
for (i=0; i<ib; i++) {
COPY_BLOCK (data, scan);
ONEBLOCK_CIPH ;
COPY_BLOCK (tar, data);
scan += BLOCK_WSIZE;
tar += BLOCK_WSIZE;
}
}
/*
#define BLOCK_XOR(B, A) \
{ \
B[0] ^= A[0]; \
B[1] ^= A[1]; \
B[2] ^= A[2]; \
B[3] ^= A[3]; \
}
*/
/* CBC-mode encryption */
static void RB_Dec_cbc (BYTE *table, BYTE *cipherKey, BYTE *iv, BYTE *input, int inputLen,
BYTE *outBuffer)
{
WORD32 tmp[4], data[4], key[2*(R+1)][4], pred[4];
WORD32 *scan, *tar;
BYTE *SBox;
int i, ib;
SBox = table;
scan = WD(cipherKey);
for (i=0; i<2*(R+1); i++) {
COPY_BLOCK (key[i], scan);
scan += 4;
}
ib = inputLen/BITSPERBLOCK; /* check # of cyphering blocks */
scan = WD(input);
tar = WD(outBuffer);
COPY_BLOCK(data, scan);
COPY_BLOCK(pred, data); /* grab into 'pred' to recover
the next ciphertext */
ONEBLOCK_CIPH; /* decrypt */
BLOCK_XOR(data, WD(iv)); /* added initial vector to recover
original plaintext */
COPY_BLOCK(tar, data);
for (i=1; i<ib; i++) {
scan += BLOCK_WSIZE;
tar += BLOCK_WSIZE;
COPY_BLOCK(data, scan);
ONEBLOCK_CIPH; /* decrypt */
BLOCK_XOR(data, pred); /* recover plaintext using predecessor */
COPY_BLOCK(tar, data);
COPY_BLOCK(pred, scan);
}
}
#define LSHIFT_PAST(D, b) \
{ /* shift by 1bit of and paste 1bit to cipher input data */ \
dt = D[0]>>31; \
D[0] = (D[0]<<1)|b; \
df = (D[1]<<1)|dt; \
dt = D[1]>>31; \
D[1] = df; \
df = (D[2]<<1)|dt; \
dt = D[2]>>31; \
D[2] = df; \
D[3] = (D[3]<<1)|dt; \
}
/* CFB1-mode encryption */
static void RB_Dec_cfb1 (BYTE *table, BYTE *cipherKey, BYTE *iv, BYTE *input, int inputLen,
BYTE *outBuffer)
{
WORD32 tmp[4], data[4],feed[4], key[2*(R+1)][4], df,dt, *cnv;
BYTE *scan, *tar, *SBox;
register BYTE grab, bit, pred;
int i, j;
SBox = table;
LSHIFT_PAST(feed, pred); /* preparing cipher input block */
COPY_BLOCK(data, feed);
ONEBLOCK_CIPH ; /* decrypt */
bit =(BYTE)(data[3]>>31);
}
*tar = grab;
scan++;
tar++;
}
}
#define ITERATIONS 1024
void blockPrint(char *buf, int length);
static void cipher_correct_test(void);
static void cipher_speed_test(void);
static const BYTE plainSrc[1024] = {0, };
int main (void)
{
cipher_correct_test();
cipher_speed_test();
return 0;
}
void cipher_correct_test(void)
{
keyInstance keys;
cipherInstance ciph;
BYTE ptext[1024], ctext[1024], keySrc[MAX_KEY_SIZE], inV[MAX_IV_SIZE];
int i, textLen=1024*8, keySrcLen=16*8, status;
for (i=0; i<1024; i++) {
ptext[i] = 0;
ctext[i] = 0;
}
for (i=0; i<MAX_KEY_SIZE; i++) keySrc[i] = 0;
for (i=0; i<MAX_IV_SIZE; i++) inV[i] = 1;
status = makeKey(&keys, DIR_ENCRYPT, keySrcLen, (char *)keySrc);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
/* ECB TEST start-- */
status = cipherInit(&ciph, MODE_ECB, (char *)inV);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
status =blockEncrypt(&ciph, &keys, (BYTE *)ptext, textLen,(BYTE *)ctext);
status =blockDecrypt(&ciph, &keys, (BYTE *)ctext, textLen,(BYTE *)ptext);
if (strncmp(plainSrc,ptext,1024)==0) printf("----ECB : OK!----\n");
else printf("----ECB : FAIL!-----\n");
/* CBC TEST start--- */
status = cipherInit(&ciph, MODE_CBC, (char *)inV);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
status =blockEncrypt(&ciph, &keys, (BYTE *)ptext, textLen,(BYTE *)ctext);
status =blockDecrypt(&ciph, &keys, (BYTE *)ctext, textLen,(BYTE *)ptext);
if (strncmp(plainSrc,ptext,1024)==0) printf("----CBC : OK!----\n");
else printf("----CBC : FAIL!-----\n");
/* CFB1 TEST start--- */
status = cipherInit(&ciph, MODE_CFB1, (char *)inV);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
status =blockEncrypt(&ciph, &keys, (BYTE *)ptext, textLen,(BYTE *)ctext);
status =blockDecrypt(&ciph, &keys, (BYTE *)ctext, textLen,(BYTE *)ptext);
if (strncmp(plainSrc,ptext,1024)==0) printf("----CFB1 : OK!----\n");
else printf("----CFB1 : FAIL!-----\n");
}
void blockPrint(char *buf, int length)
{
int i;
for (i=0; i<length; i++) {
printf("%02x",buf[i]&0xff);
}
printf("\n");
}
static void cipher_speed_test(void)
{
keyInstance keys;
cipherInstance ciph;
BYTE ptext[1024], ctext[1024], keySrc[MAX_KEY_SIZE], inV[MAX_IV_SIZE];
int i, textLen=1024*8, keySrcLen=16*8, status;
clock_t elapsed;
double sec;
for (i=0; i<1024; i++) {
ptext[i] = 0;
ctext[i] = 0;
}
for (i=0; i<MAX_KEY_SIZE; i++) keySrc[i] = 0;
for (i=0; i<MAX_IV_SIZE; i++) inV[i] = 1;
status = makeKey(&keys, DIR_ENCRYPT, keySrcLen, (char *)keySrc);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
status = cipherInit(&ciph, MODE_ECB, (char *)inV);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
elapsed = -clock();
for (i=0; i<ITERATIONS; i++) {
status =blockEncrypt(&ciph, &keys, (BYTE *)ptext, textLen,(BYTE *)ctext);
strncpy (ctext, ptext, 1024);
}
elapsed += clock ();
sec = elapsed ? (double) elapsed / CLOCKS_PER_SEC : 1.0;
printf("****ECB_speed.... ");
printf (" %.4f sec(1Mbytes), %.4f Mbytes/sec.\n",
sec, 1./sec);
status = cipherInit(&ciph, MODE_CBC, (char *)inV);
if (status != R_TRUE) {
printf("Error Occured!__er_code=%d\n",status);
exit(1);
}
elapsed = -clock();
for (i=0; i<ITERATIONS; i++) {
status =blockEncrypt(&ciph, &keys, (BYTE *)ptext, textLen,(BYTE *)ctext);
strncpy (ctext, ptext, 1024);
}
elapsed += clock ();
sec = elapsed ? (double) elapsed / CLOCKS_PER_SEC : 1.0;
printf("****CBC_speed.... ");
printf (" %.4f sec(1Mbytes), %.4f Mbytes/sec.\n",
sec, 1./sec);
}
( run in 0.581 second using v1.01-cache-2.11-cpan-e1769b4cff6 )