The Book Cipher Algorithm
by Dejan Ristanovic and Jelica Protic

Listing One

// bkadd
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>

#define MAX_WORD_LEN 100

int main(int argc, char *argv[])
{
   FILE *fp_cod, *fp_book;
   int  ch, charno;
   char word[MAX_WORD_LEN];
   int  fromstart = 1;
   int  wlen = 0;
   // Argument processing
   char code[_MAX_PATH], book[_MAX_PATH];
   char drive[_MAX_DRIVE];
   char dir[_MAX_DIR];
   char fname[_MAX_FNAME];
   char ext[_MAX_EXT];

   if (argc != 3 && argc != 4) goto error1;
   _splitpath(argv[1], drive, dir, fname, ext );
   if (strlen(ext) == 0) strcpy(ext, "cod");
   _makepath(code, drive, dir, fname, ext);

   _splitpath(argv[2], drive, dir, fname, ext );
   if (strlen(ext) == 0) strcpy(ext, "txt");
   _makepath(book, drive, dir, fname, ext);

   if (argc == 3 ||(sscanf(argv[3], "%d", &charno) != 1)
                 || (charno == 0)) charno=1;
   if (charno < 0) { fromstart = 0; charno = -charno; }

   // File opening

   if ((fp_cod  = fopen(code, "a")) == NULL) goto error2;
   if ((fp_book = fopen(book, "r")) == NULL) goto error3;

   // Main loop
   do {
      ch = getc(fp_book);
      if (isalpha(ch))
         word[wlen++] = ch;
      else {
         if (charno <= wlen)
            putc(toupper(word[fromstart ?
            (charno - 1) : (wlen - charno)]), fp_cod);
         wlen = 0;
      }
   } while (!feof(fp_book));
   // Termination
   fclose(fp_book); fclose(fp_cod); return 0;
// Error handling
error1: printf("USAGE: bkadd codfile bookfile [charno]\n"); return 1;
error2: printf("Can not open code file %s\n", argv[1]); return 1;
error3: fclose(fp_cod);
        printf("Can not open book file %s\n", argv[2]); return 1;
}


   Listing Two

// bkcode

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define N_CAPITAL_LETTERS 26
#define LTRTOIDX(x) (x-'A')

int main(int argc, char *argv[])
{
    char plain[_MAX_PATH], codfile[_MAX_PATH];
    char cipher[_MAX_PATH], positions[_MAX_PATH];
    char drive[_MAX_DRIVE];
    char dir[_MAX_DIR];
    char fname[_MAX_FNAME];
    char ext[_MAX_EXT];

    FILE *fp_plain, *fp_cod, *fp_cipher, *fp_pos;
    long pos[N_CAPITAL_LETTERS];
    int  ch_plain, ch_cod;

    // Argument processing
    if (argc != 3) goto error1;
    _splitpath(argv[1], drive, dir, fname, ext );
    if (strlen(ext) == 0) strcpy(ext, "cod");
    _makepath(codfile, drive, dir, fname, ext);
    _makepath(positions, drive, dir, fname, "pos");
    _splitpath(argv[2], drive, dir, fname, ext );
    if (strlen(ext) == 0) strcpy(ext, "txt");
    _makepath(plain, drive, dir, fname, ext);
    _makepath(cipher, drive, dir, fname, "cry");

    // File opening
    if ((fp_plain  = fopen(plain, "r")) == NULL) goto error3;
    if ((fp_cod = fopen(codfile, "r")) == NULL) goto error3;
    if ((fp_cipher = fopen(cipher, "w")) == NULL) goto error3;
    fp_pos = fopen(positions, "rb+");

    // Position array intialization
    if (fp_pos == NULL) memset(pos, 0, sizeof(pos));
    else {
       fread(pos, sizeof(long), N_CAPITAL_LETTERS, fp_pos);
       fclose(fp_pos);
    }
    // Main loop
    do {
         ch_plain = toupper(getc(fp_plain));
         if (isalpha(ch_plain))
         {
            fseek(fp_cod, pos[LTRTOIDX(ch_plain)], SEEK_SET);
            do {
               ch_cod = getc(fp_cod);
            } while (!(ch_cod == ch_plain || ch_cod == EOF));
            if (ch_cod == ch_plain) {
               pos[LTRTOIDX(ch_plain)] = ftell(fp_cod);
               fprintf (fp_cipher, "%1ld ", pos[LTRTOIDX(ch_plain)]);
            } else goto error2;
         }
    } while (ch_plain != EOF);
    // Termination
    fp_pos = fopen(positions, "wb");
    fwrite (pos, sizeof(long), N_CAPITAL_LETTERS, fp_pos);
    fclose(fp_plain); fclose(fp_cod); fclose(fp_cipher); fclose(fp_pos);
    return 0;
// Error handling
error1: printf ("USAGE: bkcode codfile message\n"); return 1;
error2: printf ("Run out of letters %c!\n", ch_plain);
        fclose(fp_plain); fclose(fp_cod);
        fclose(fp_cipher); remove(cipher); return 1;
error3: printf ("Can not open files\n"); return 1;
}


   Listing Three

// bkdecode
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[])
{
    char codfile[_MAX_PATH];
    char cipher[_MAX_PATH], decoded[_MAX_PATH];
    char drive[_MAX_DRIVE];
    char dir[_MAX_DIR];
    char fname[_MAX_FNAME];
    char ext[_MAX_EXT];

    FILE *fp_cipher, *fp_cod, *fp_decoded;
    long position, cod_size;

    // Argument processing
    if (argc!=3) goto error1;
    _splitpath(argv[1], drive, dir, fname, ext );
    if (strlen(ext) == 0) strcpy(ext, "cod");
    _makepath(codfile, drive, dir, fname, ext);
    _splitpath(argv[2], drive, dir, fname, ext );
    _makepath(cipher, drive, dir, fname, "cry");
    _makepath(decoded, drive, dir, fname, "txt");

    // File opening
    if ((fp_cipher  = fopen(cipher, "r")) == NULL) goto error3;
    if ((fp_cod = fopen(codfile, "r")) == NULL) goto error3;
    if ((fp_decoded = fopen(decoded, "w")) == NULL) goto error3;

    // Determine codfile size
    fseek(fp_cod, 0, SEEK_END);
    cod_size = ftell(fp_cod);

    // Main loop
    while ((fscanf(fp_cipher, "%ld", &position) != EOF)) {
        if (--position <= cod_size) {
           fseek(fp_cod, position, SEEK_SET);
           putc(getc(fp_cod), fp_decoded);
        }
        else goto error2;
    }
    // Termination
    fclose(fp_cipher); fclose(fp_cod);
    fclose(fp_decoded);
    return 0;
// Error handling
error1: printf ("USAGE: bkdecode codfile cipher \n"); return 1;
error2: printf ("Invalid ciphertext\n");
        fclose(fp_cipher); fclose(fp_cod);
        fclose(fp_decoded); remove (decoded); return 1;
error3: printf ("Can not open files\n"); return 1;
}




1


