** NOTICE ** This source code does not include RC4. You must write rc4_init() and rc4_cipher by yourself. ************ /* * cs1.c - The CipherSaber encryption program. * * This program is originally written by Hiroshi Yuki . * http://www.hyuki.com/cs/ * * You may freely use, distribute, and modify this code itself. * But, use or distribution of RC4 may be controlled or restricted * in some country. Use at your own risk. * RC4 encryption algorithm is created by Ronald L. Rivest of RSA. * RC4 is published in the 2nd edition of Bruce Schneier's Applied Cryptography. * RC4 is a trademark of the RSA Division of Security Dynamics. * * The CipherSaber concept is by Arnold G. Reinhold . * http://ciphersaber.gurus.com/ * * CipherSaber, CS1, CS2, and CipherKnight are trademarks of Arnold G. Reinhold. * A free, nonexclusive license is hereby granted to use the marks CipherSaber, * CS1 and CS2 on any product that is interoperable with CipherSaber * as demonstrated by the ability to decrypt the test samples supplied and * to produce files readable by other implementations of CipherSaber. * The marks may also be used in supporting material that promotes CipherSaber. */ #include #include /* for getch (non echoback, non buffered getchar) */ unsigned char *usage[] = { "This is CipherSaber, version 1.0.1.", "", "This program is originally written by Hiroshi Yuki .", "Created: January 29th, 1999.", "Last update: May 9th, 2000.", "http://www.hyuki.com/cs/ (RC4 is not distributed here)", "", "You may freely use, distribute, and modify this code itself.", "But, use or distribution of RC4 may be controlled or restricted", "in some country. Use at your own risk.", "RC4 encryption algorithm is created by Ronald L. Rivest of RSA.", "RC4 is published in the 2nd edition of Bruce Schneier's Applied Cryptography.", "RC4 is a trademark of the RSA Division of Security Dynamics.", "", "The CipherSaber concept is by Arnold G. Reinhold .", "http://ciphersaber.gurus.com/", "", "CipherSaber, CS1, CS2, and CipherKnight are trademarks of Arnold G. Reinhold.", "", "Usage: cs1 -e infile outfile for encryption", "Usage: cs1 -d infile outfile for decryption", NULL, }; /* prototypes */ void rc4_init(unsigned char *key, size_t len); void rc4_cipher(unsigned char *buffer, size_t len); void rc4_exit(void); int rc4_selftest(void); void cs_encryptfile(char *infile, char *outfile); void cs_decryptfile(char *infile, char *outfile); void main(int argc, char *argv[]); int get_password(unsigned char *prompt, unsigned char *buf, int len); void burn_it(unsigned char *buf, int len); void get_random(unsigned char *buf, int len); /* Max length of password */ #define PASS 245 /* A big buffer for disk I/O */ #define BIGBUFFER (32*1024) static unsigned char bigbuffer[BIGBUFFER]; /* * RC4 test vector. * It is to verify the code is correctly implemented. * To test, use rc4_selftest() function. */ /* The length of each data size (length of key, plaintext, and ciphertext) */ #define RC4_TESTDATA 10 typedef struct { int keysize; unsigned char key[RC4_TESTDATA]; int plainsize; unsigned char plain[RC4_TESTDATA]; int ciphersize; unsigned char cipher[RC4_TESTDATA]; } RC4_TEST; /* The number of test vectors */ #define RC4_TESTSIZE 4 RC4_TEST rc4_test[RC4_TESTSIZE] = { { 8, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, 8, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, 8, { 0x75, 0xB7, 0x87, 0x80, 0x99, 0xE0, 0xC5, 0x96 }, }, { 8, { 0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF }, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8, { 0x74, 0x94, 0xC2, 0xE7, 0x10, 0x4B, 0x08, 0x79 }, }, { 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8, { 0xDE, 0x18, 0x89, 0x41, 0xA3, 0x37, 0x5D, 0x3A }, }, { 4, { 0xEF, 0x01, 0x23, 0x45 }, 10, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 10, { 0xD6, 0xA1, 0x41, 0xA7, 0xEC, 0x3C, 0x38, 0xDF, 0xBD, 0x61 }, }, }; /* * Initialize rc4_... variables with the given key. * You must call this function before calling rc4_cipher(). */ void rc4_init(unsigned char *key, size_t len) { You must write this function by yourself. } /* * The core part of RC4. * You must call rc4_init() before using this. * The given buffer is overwritten. */ void rc4_cipher(unsigned char *buffer, size_t len) { You must write this function by yourself. } /* * Dispose used variables. * You must call this function * after encryption or decryption ends. */ void rc4_exit(void) { rc4_init("burn", 4); } /* * Self test of RC4 encryption algorithm. * It returns 0 if it is no good, returns 1 if it is okay. */ int rc4_selftest(void) { int i; unsigned char work[RC4_TESTDATA]; RC4_TEST *t = 0; int good = 1; for (i = 0; i < RC4_TESTSIZE; i++) { t = &rc4_test[i]; /* encrypt check */ rc4_init(t->key, t->keysize); memcpy(work, t->plain, t->plainsize); rc4_cipher(work, t->plainsize); if (memcmp(work, t->cipher, t->ciphersize) != 0) { good = 0; } rc4_exit(); /* decrypt check */ rc4_init(t->key, t->keysize); rc4_cipher(work, t->ciphersize); if (memcmp(work, t->plain, t->plainsize) != 0) { good = 0; } rc4_exit(); } return good; } /* * CipherSaber file encryption. */ void cs_encryptfile(char *infile, char *outfile) { FILE *infp = 0; FILE *outfp = 0; unsigned char pass1[PASS+1]; unsigned char pass2[PASS+1]; unsigned char key[256]; unsigned char random_ten[10]; size_t rlen; int passlen; /* open input file */ infp = fopen(infile, "rb"); if (!infp) { printf("I cannot find %s.\n", infile); return; } /* open output file */ outfp = fopen(outfile, "wb"); if (!outfp) { printf("I cannot create %s.\n", outfile); return; } /* get randomized initial vector for CipherSaber */ get_random(random_ten, 10); /* * get a password from user twice, * and check if the two are the same */ if (get_password("Enter passphrase:", pass1, PASS) == 0) { goto err; } if (get_password("Enter passphrase again:", pass2, PASS) == 0) { goto err; } if (strcmp(pass1, pass2) != 0) { printf("The two passphrases are not same.\n"); goto err; } /* * create CipherSaber key from * the password and randomized initial vector. */ passlen = strlen(pass1); memcpy(key, pass1, passlen); memcpy(key + passlen, random_ten, 10); /* Read, encrypt and write. */ rc4_init(key, passlen + 10); fwrite(random_ten, 1, 10, outfp); while ((rlen = fread(bigbuffer, 1, BIGBUFFER, infp)) > 0) { rc4_cipher(bigbuffer, rlen); fwrite(bigbuffer, 1, rlen, outfp); } rc4_exit(); /* close */ fclose(infp); infp = 0; fclose(outfp); outfp = 0; /* TODO:You must check decryption here */ err: if (infp) fclose(infp); if (outfp) fclose(outfp); burn_it(pass1, PASS+1); burn_it(pass2, PASS+1); burn_it(key, 256); burn_it(random_ten, 10); burn_it(bigbuffer, BIGBUFFER); } /* * CipherSaber file decryption. */ void cs_decryptfile(char *infile, char *outfile) { FILE *infp = 0; FILE *outfp = 0; unsigned char pass1[PASS+1]; unsigned char key[256]; unsigned char random_ten[10]; size_t rlen; int passlen; /* open input file */ infp = fopen(infile, "rb"); if (!infp) { printf("I cannot find %s.\n", infile); return; } /* open output file */ outfp = fopen(outfile, "wb"); if (!outfp) { printf("I cannot create %s.\n", outfile); return; } /* get password from user */ if (get_password("Enter passphrase:", pass1, PASS) == 0) { goto err; } /* read initial vector from infile */ if (fread(random_ten, 1, 10, infp) != 10) { printf("I cannot read enough data from %s.\n", infile); goto err; } /* * create CipherSaber key from * the password and initial vector from file. */ passlen = strlen(pass1); memcpy(key, pass1, passlen); memcpy(key + passlen, random_ten, 10); /* Read, decrypt and write. */ rc4_init(key, passlen + 10); while ((rlen = fread(bigbuffer, 1, BIGBUFFER, infp)) > 0) { rc4_cipher(bigbuffer, rlen); fwrite(bigbuffer, 1, rlen, outfp); } rc4_exit(); /* close */ fclose(infp); infp = 0; fclose(outfp); outfp = 0; err: if (infp) { fclose(infp); infp = 0; } if (outfp) { fclose(outfp); outfp = 0; } burn_it(pass1, PASS+1); burn_it(key, 256); burn_it(random_ten, 10); burn_it(bigbuffer, BIGBUFFER); } /* * Ok, this is the main function. */ void main(int argc, char *argv[]) { char *infile = 0; char *outfile = 0; int i; if (argc != 4) { for (i = 0; usage[i] != 0; i++) { printf("%s\n", usage[i]); } exit(-1); } infile = argv[2]; outfile = argv[3]; if (!rc4_selftest()) { printf("RC4 self test is failed.\nDo not use this program.\n"); exit(-1); } if (stricmp(argv[1], "-e") == 0) { printf("Encrypt %s into %s.\n", infile, outfile); cs_encryptfile(infile, outfile); } else { printf("Decrypt %s into %s.\n", infile, outfile); cs_decryptfile(infile, outfile); } } /* * getting password. */ int get_password(unsigned char *prompt, unsigned char *buf, int len) { int i = 0; printf("%s", prompt); fflush(stdout); for (;;) { int c = getch(); if (i + 1 >= len) { printf("Too long passphrase.\n"); return -1; } if (c == EOF || c == '\033') { burn_it(buf, len); return 0; } if (c == EOF || c == '\r' || c == '\n' || c == '\033') { buf[i] = '\0'; break; } if (c == '\b') { if (i > 0) { i--; buf[i] = '\0'; } continue; } buf[i] = c; i++; } printf("\n"); return strlen(buf); } void burn_it(unsigned char *buf, int len) { memset(buf, '\0', len); } /* * get_random fills buf with (pseudo) random bytes. */ void get_random(unsigned char *buf, int len) { int i; srand(time(NULL)); /* You should choose better seed. */ for (i = 0; i < len; i++) { buf[i] = (unsigned char)(rand() % 256); } }