1996-10-30 - [CRYPTO] Cryptography Of A Sort (COAS) update

Header Data

From: Dale Thorn <dthorn@gte.net>
To: coderpunks@toad.com
Message Hash: 7b926e1194d57b12a9aa5e177e569b9f138d93cb1f827698ff597e78d87d8e7f
Message ID: <32776CB4.673A@gte.net>
Reply To: N/A
UTC Datetime: 1996-10-30 15:01:35 UTC
Raw Date: Wed, 30 Oct 1996 07:01:35 -0800 (PST)

Raw message

From: Dale Thorn <dthorn@gte.net>
Date: Wed, 30 Oct 1996 07:01:35 -0800 (PST)
To: coderpunks@toad.com
Subject: [CRYPTO] Cryptography Of A Sort (COAS) update
Message-ID: <32776CB4.673A@gte.net>
MIME-Version: 1.0
Content-Type: text/plain

[note: last post didn't have attachment]

Per suggestions received for this project, I've added code to "pad" 8th bits in a
"7-bit" text file, i.e., to "normalize" the ratio of zero-bits and one-bits somewhat.

Bit-padding prior to encryption does not change the central imperative of the program,
which is to never change any bits in a file, since bit-padding is a separate option.

Attached are:  CCRP.H   ('C'-language header)
               CCRP.C   ('C'-language code)
               CCRP.DOC (instructions)
               CCRP.FAQ (f.a.q.)

Suggested procedure:  Start with any file; if "7-bit" ASCII, try bit-padding first.
                      Next, perform encryption at least half a dozen times, with
                      different pass-phrases.
                      To decrypt, perform all steps in reverse, per documentation.

Comments and questions are welcome.


/* CCRP.H  28.10.1996 */

typedef char     C;                       /* char (strings, null-terminated) */
typedef double   D;                       /* double float (double precision) */
typedef float    F;                              /* float (single precision) */
typedef int      I;                                /* short integer (signed) */
typedef long     L;                                 /* long integer (signed) */
typedef unsigned int U;                          /* short integer (unsigned) */
typedef unsigned char UC;                              /* unsigned character */
typedef void     V;                                        /* void data type */

I bitget(C *cstr, I ibit);
V bitput(C *cstr, I ibit, I iput);
V ifn_cryp(I *int1, I *int2, I *istk, C *cbuf, C *ctmp, I ibit, I ilen, I iopr);
V ifn_msgs(C *cmsg, I iofs, I irow, I icol, I ibrp, I iext);
V ifn_pack(C *cbuf, L llof, U ibuf, I iopr, struct _iobuf *ebuf);
V ifn_read(C *cbuf, L lbyt, U ibuf, struct _iobuf *ebuf);
V ifn_sort(I *int1, I *int2, I *istk, I imax);
V ifn_write(C *cbuf, L lbyt, U ibuf, struct _iobuf *ebuf);
U io_vadr(I inop);
V io_vcls(I iclr);
V io_vcsr(I irow, I icol, I icsr);
V io_vdsp(C *cdat, I irow, I icol, I iclr);

union REGS rg;                          /* DOS registers declaration (video) */
U _far *uvadr = 0;                                  /* video display pointer */
*******************************************************************************
*******************************************************************************
*******************************************************************************
/* CCRP.C  Encrypt/Decrypt a DOS file */
/*         By: Dale Thorn             */
/*         Version 3.1                */
/*         Rev. 29.10.1996            */

#include "stdlib.h"
#include "string.h"
#include "stdio.h"
#include "dos.h"
#include "io.h"
#include "ccrp.h"

V main(I argc, C **argv) {     /* command-line arguments (input file/offset) */
   C cmsg[23];                         /* initialize the User message string */
   U ibit = 0;                          /* initialize the bit offset in cbuf */
   U ibuf = 2048;                          /* set maximum file buffer length */
   U idot;                    /* initialize the filename extension separator */
   I ieof = 0;                                    /* initialize the EOF flag */
   U ilen;                         /* initialize a temporary length variable */
   U indx;                           /* initialize a temporary loop variable */
   I iopr;                                  /* initialize the operation code */
   U irnd = 0;                             /* initialize the randomizer seed */
   L lbyt;                           /* initialize the file pointer variable */
   L llof;                            /* initialize the file length variable */
   L lrnd = 0;                      /* initialize the randomizer accumulator */
   U _far *uvadr = 0;                               /* video display pointer */
   struct _iobuf *ebuf;                      /* source file access structure */

   C *cbuf = (C *)malloc(2048);                /* initialize the file buffer */
   C *ctmp = (C *)malloc(2048);                /* initialize the temp buffer */
   I *int1 = (I *)malloc(3074);             /* allocate the sort index array */
   I *int2 = (I *)malloc(3074);     /* allocate the sort random number array */
   I *istk = (I *)malloc(3074);             /* allocate the sort stack array */

   if (argc == 1) {                       /* a command line was not supplied */
      ifn_msgs("Usage:  CCRP(v3.1)  filename  [/e /d /p /u]  [key]",\
               4, 24, 79, 0, 1);   /* display usage message [above] and exit */
   }
   if (argc < 3 || argc > 4) {     /* no. of parameters should be one or two */
      ifn_msgs("Invalid number of parameters", 4, 24, 79, 1, 1);
   }                   /* display no.-of-parameters message [above] and exit */
   if (argv[2][0] != '/') {             /* slash preceding parameter missing */
      ifn_msgs("Invalid operation parameter", 4, 24, 79, 1, 1);
   }                   /* display invalid-parameter message [above] and exit */
   strupr(argv[1]);                                /* uppercase the filename */
   strupr(argv[2]);                          /* uppercase the operation code */
   if (strchr("DEPU", argv[2][1]) == NULL) {            /* invalid parameter */
      ifn_msgs("Invalid operation parameter", 4, 24, 79, 1, 1);
   }                   /* display invalid-parameter message [above] and exit */
   idot = strcspn(argv[1], "."); /* position of filename extension separator */
   ilen = strlen(argv[1]);                             /* length of filename */
   if (idot == 0 || idot > 8 || ilen - idot > 4) {     /* filename tests bad */
      ifn_msgs("Invalid filename", 4, 24, 79, 1, 1);
   }                    /* display invalid-filename message [above] and exit */
   if (idot < ilen) {                 /* filename extension separator found! */
      if (strcspn(argv[1] + idot + 1, ".") < ilen - idot - 1) {/* 2nd found! */
         ifn_msgs("Invalid filename", 4, 24, 79, 1, 1);
      }                 /* display invalid-filename message [above] and exit */
   }
   strcpy(cmsg, argv[1]);                        /* copy filename to message */
   strcat(cmsg, " not found");                 /* add "not found" to message */
   ebuf = fopen(argv[1], "rb+");                   /* open the selected file */
   llof = filelength(fileno(ebuf));           /* filelength of selected file */
   if (ebuf == NULL || llof == -1L || llof == 0) {/* length=0 or call failed */
      fclose(ebuf);                                        /* close the file */
      remove(argv[1]);                          /* kill the zero-length file */
      ifn_msgs(cmsg, 4, 24, 79, 1, 1);           /* display message and exit */
   }
   iopr = argv[2][1] - 68;     /* opcode (1=encrypt, 0=decrypt, 12=pad bits) */
   if (argc == 4) {                               /* a seed key was supplied */
      ilen = strlen(argv[3]);                 /* length of optional seed key */
      for (indx = 0; indx < ilen; indx++) {     /* loop through the seed key */
         irnd = argv[3][indx];                 /* character at byte position */
         switch (indx % 3) {                  /* select on byte significance */
            case 0:                                /* least significant byte */
               lrnd += irnd;                     /* add to randomizer accum. */
               break;
            case 1:                            /* 2nd least significant byte */
               lrnd += (L)irnd * 256;            /* add to randomizer accum. */
               break;
            case 2:                                 /* most significant byte */
               lrnd += (L)irnd * 65536;          /* add to randomizer accum. */
               break;
            default:
               break;
         }
      }
      irnd = (U)(lrnd % 32640) + 1;       /* mod randomizer seed to <= 32640 */
   }
   ifn_msgs("Please standby", 4, 24, 79, 0, 0);           /* standby message */

   if (iopr > 1) {                           /* operation code is 'P' or 'U' */
      ifn_pack(cbuf, llof, ibuf, iopr, ebuf);  /* add 8th bits if 7-bit file */
   }                                  /* NOTE: ifn_pack does NOT return here */
   srand(irnd);                    /* initialize the random number generator */
   for (lbyt = 0; lbyt < llof; lbyt += ibuf) {   /* process in ibuf segments */
      if (lbyt + ibuf >= llof) {    /* current file pointer + ibuf spans EOF */
         ibuf = (U)(llof - lbyt);        /* reset maximum file buffer length */
         ieof = 1;                                    /* set the EOF flag ON */
      }
      ifn_read(cbuf, lbyt, ibuf, ebuf);    /* read data into the file buffer */
      while (1) {                      /* loop to process bit groups in cbuf */
         ilen = (rand() / 26) + 256;/* buffer seg. bit-len.: 256<=ilen<=1536 */
         if (ibit + ilen > ibuf * 8) {/* current bit-pointer+ilen spans cbuf */
            if (ieof) {                                    /* EOF flag is ON */
               ilen = ibuf * 8 - ibit; /* reset bit-length of buffer segment */
            } else {                 /* EOF flag is OFF; adjust file pointer */
               ifn_write(cbuf, lbyt, ibuf, ebuf);  /* write data to the file */
               lbyt -= (ibuf - ibit / 8);/* set file ptr to reload from ibit */
               ibit %= 8;            /* set ibit to first byte of <new> cbuf */
               break;                  /* exit loop to reload cbuf from lbyt */
            }
         }                 /* encrypt or decrypt the current segment [below] */
         ifn_cryp(int1, int2, istk, cbuf, ctmp, (I)ibit, ilen, iopr);
         ibit += ilen;                 /* increment ibit to next bit-segment */
         if (ibit == ibuf * 8) {        /* loop until ibit == length of cbuf */
            ifn_write(cbuf, lbyt, ibuf, ebuf);     /* write data to the file */
            ibit = 0;                /* set ibit to first byte of <new> cbuf */
            break;
         }
      }
   }
   ifn_msgs("Translation complete", 4, 24, 79, 0, 1);/* disp. message & exit */
}

I bitget(C *cstr, I ibit) {                 /* get a bit-value from a string */
   I ival;                                       /* initialize the bit value */

   switch (ibit % 8) {                    /* switch on bit# within character */
      case 0:                                  /* bit #0 in target character */
         ival = 1;                                        /* value of bit #0 */
         break;
      case 1:                                  /* bit #1 in target character */
         ival = 2;                                        /* value of bit #1 */
         break;
      case 2:                                  /* bit #2 in target character */
         ival = 4;                                        /* value of bit #2 */
         break;
      case 3:                                  /* bit #3 in target character */
         ival = 8;                                        /* value of bit #3 */
         break;
      case 4:                                  /* bit #4 in target character */
         ival = 16;                                       /* value of bit #4 */
         break;
      case 5:                                  /* bit #5 in target character */
         ival = 32;                                       /* value of bit #5 */
         break;
      case 6:                                  /* bit #6 in target character */
         ival = 64;                                       /* value of bit #6 */
         break;
      case 7:                                  /* bit #7 in target character */
         ival = 128;                                      /* value of bit #7 */
         break;
      default:
         break;
   }
   return ((cstr[ibit / 8] & ival) != 0);      /* return value of target bit */
}

V bitput(C *cstr, I ibit, I iput) {           /* put a bit-value to a string */
   I ival;                                       /* initialize the bit value */
   I ipos = ibit / 8;                     /* position of 8-bit char. in cstr */

   switch (ibit % 8) {                    /* switch on bit# within character */
      case 0:                                  /* bit #0 in target character */
         ival = 1;                                        /* value of bit #0 */
         break;
      case 1:                                  /* bit #1 in target character */
         ival = 2;                                        /* value of bit #1 */
         break;
      case 2:                                  /* bit #2 in target character */
         ival = 4;                                        /* value of bit #2 */
         break;
      case 3:                                  /* bit #3 in target character */
         ival = 8;                                        /* value of bit #3 */
         break;
      case 4:                                  /* bit #4 in target character */
         ival = 16;                                       /* value of bit #4 */
         break;
      case 5:                                  /* bit #5 in target character */
         ival = 32;                                       /* value of bit #5 */
         break;
      case 6:                                  /* bit #6 in target character */
         ival = 64;                                       /* value of bit #6 */
         break;
      case 7:                                  /* bit #7 in target character */
         ival = 128;                                      /* value of bit #7 */
         break;
      default:
         break;
   }
   if (iput) {                                       /* OK to set the bit ON */
      if (!(cstr[ipos] & ival)) {                   /* bit is NOT already ON */
         cstr[ipos] += ival;                    /* set bit ON by adding ival */
      }
   } else {                                         /* OK to set the bit OFF */
      if (cstr[ipos] & ival) {                     /* bit is NOT already OFF */
         cstr[ipos] -= ival;                    /* set bit OFF by subt. ival */
      }
   }
}

V ifn_cryp(I *int1, I *int2, I *istk, C *cbuf, C *ctmp, I ibit, I ilen, I iopr) {
   I indx;                           /* initialize the for-next loop counter */

   for (indx = 0; indx < ilen; indx++) { /* loop through ilen array elements */
      int1[indx] = indx;             /* bit offsets from current ibit offset */
      int2[indx] = rand();         /* random number values for sort function */
   }
   ifn_sort(int1, int2, istk, ilen - 1);    /* Quicksort by random no. array */
   memcpy(ctmp, cbuf, 2048);  /* copy data buffer to temp destination buffer */
   if (iopr) {                                          /* encrypt operation */
      for (indx = 0; indx < ilen; indx++) { /* loop thru ilen array elements */
         bitput(ctmp, indx + ibit, bitget(cbuf, int1[indx] + ibit));/*encrypt*/
      }
   } else {                                             /* decrypt operation */
      for (indx = 0; indx < ilen; indx++) { /* loop thru ilen array elements */
         bitput(ctmp, int1[indx] + ibit, bitget(cbuf, indx + ibit));/*decrypt*/
      }
   }
   memcpy(cbuf, ctmp, 2048);  /* copy temp destination buffer to data buffer */
}

V ifn_msgs(C *cmsg, I iofs, I irow, I icol, I ibrp, I iext) {/* display msgs */
   io_vcls(7);                                           /* clear the screen */
   io_vdsp(cmsg, 4, iofs, 7);                    /* display the user message */
   if (ibrp) {                              /* OK to sound user-alert (beep) */
      printf("\a");                                  /* sound the user-alert */
   }
   if (iext) {                                     /* OK to exit the program */
      io_vcsr(5, 0, 0);                               /* relocate the cursor */
      fcloseall();                                   /* close all open files */
      exit(0);                                              /* return to DOS */
   } else {                                       /* do NOT exit the program */
      io_vcsr(irow, icol, 0);                           /* 'hide' the cursor */
   }
}

V ifn_pack(C *cbuf, L llof, U ibuf, I iopr, struct _iobuf *ebuf) {
   I ibit;                           /* initialize a temporary loop variable */
   U ichr;                           /* initialize a temporary loop variable */
   U incr;                          /* initialize the bit-pad loop increment */
   U itmp = ibuf;                   /* make a copy of the file buffer length */
   L lbyt;                           /* initialize the file pointer variable */
   L lcnt = 0;                      /* initialize the current total one-bits */
   L ltmp;                    /* initialize a copy of current total one-bits */
   L ltot;                       /* initialize the no. of 8th bits to set ON */

   for (lbyt = 0; lbyt < llof; lbyt += itmp) {   /* process in itmp segments */
      if (lbyt + itmp > llof) {     /* current file pointer + itmp spans EOF */
         itmp = (U)(llof - lbyt);        /* reset maximum file buffer length */
      }
      ifn_read(cbuf, lbyt, itmp, ebuf);    /* read data into the file buffer */
      if (iopr == 17) {                              /* opcode == unpad bits */
         for (ichr = 0; ichr < itmp; ichr++) {      /* process bytes in cbuf */
            bitput(cbuf, ichr * 8 + 7, 0);           /* set each 8th bit OFF */
         }
         ifn_write(cbuf, lbyt, itmp, ebuf);   /* save current buffer to file */
      } else {                       /* opcode == pad bits - validation pass */
         for (ichr = 0; ichr < itmp; ichr++) {      /* process bytes in cbuf */
            for (ibit = 0; ibit < 8; ibit++) {       /* process bits in cbuf */
               lcnt += bitget(cbuf, ichr * 8 + ibit);/* add 0/1 bit to total */
               if (ibit == 7) {               /* this is the 8th bit of ichr */
                  if (bitget(cbuf, ichr * 8 + ibit)) {  /* the 8th bit is ON */
                     ifn_msgs("8th bit(s) are ON - can't do bit-pad", 4, 24, 79, 1, 1);
                  }     /* can't add bits - display message (above) and exit */
               }
            }
         }
      }
   }
   if (iopr == 17) {                                 /* opcode == unpad bits */
      ifn_msgs("Bit-unpadding complete", 4, 24, 79, 0, 1); /* message & exit */
   }
   ltot = llof * 4 - lcnt;      /* set ltot as the no. of 8th bits to set ON */
   if (ltot > 0) {                 /* one-bits < zero bits; commence padding */
      if (ltot > llof) {             /* one-bits required exceed total bytes */
         ltot = llof;                 /* reset one-bits to equal total bytes */
      }

      itmp = ibuf;               /* reset the copy of the file buffer length */
      ltmp = ltot;                  /* make a copy of the 8th bits to set ON */
      for (lbyt = 0; lbyt < llof; lbyt += itmp) {/* process in itmp segments */
         if (lbyt + itmp > llof) {  /* current file pointer + itmp spans EOF */
            itmp = (U)(llof - lbyt);     /* reset maximum file buffer length */
         }
         ifn_read(cbuf, lbyt, itmp, ebuf); /* read data into the file buffer */
         incr = (U)((llof - lbyt) / ltmp); /* set the bit-pad loop increment */
         for (ichr = 0; ichr < itmp; ichr += incr) { /* loop to set 8th bits */
            bitput(cbuf, ichr * 8 + 7, 1);            /* set each 8th bit ON */
            ltmp--;                   /* decrement the total one-bits padded */
            if (ltmp == 0) {                  /* all 8th bits are now set ON */
               break;                /* all 8th bits are ON - exit ichr loop */
            }
         }
         ifn_write(cbuf, lbyt, itmp, ebuf);   /* save current buffer to file */
         if (ltmp == 0) {                     /* all 8th bits are now set ON */
            break;                   /* all 8th bits are ON - exit lbyt loop */
         }
      }
      ifn_msgs("Bit-padding complete", 4, 24, 79, 0, 0);/* disp.message only */
   } else {                     /* one-bits >= zero bits; padding not needed */
      ifn_msgs("Bit-padding not needed", 4, 24, 79, 1, 0);/* disp.msg.& exit */
      ltot = 0;                 /* reset one-bits required for below message */
   }
   io_vcsr(6, 0, 0);                                  /* relocate the cursor */
   printf("%s%ld", "Total bits in source: ", llof * 8);/* total bits in file */
   io_vcsr(8, 0, 0);                                  /* relocate the cursor */
   printf("%s%ld", "Total one-bits begin: ", lcnt);   /* one-bits before pad */
   io_vcsr(10, 0, 0);                                 /* relocate the cursor */
   printf("%s%ld\n", "Total one-bits added: ", ltot);  /* no. one-bits added */
   fcloseall();                                      /* close all open files */
   exit(0);                                                 /* return to DOS */
}

V ifn_sort(I *int1, I *int2, I *istk, I imax) {  /* array Quicksort function */
   I iext;                            /* initialize the outer-loop exit flag */
   I ilow;                               /* initialize the low array pointer */
   I irdx = 0;                                  /* initialize the sort radix */
   I isp1;                               /* initialize the low stack pointer */
   I isp2;                               /* initialize the top stack pointer */
   I itop;                               /* initialize the top array pointer */
   I iva1;                  /* initialize array value from low stack pointer */
   I iva2;                  /* initialize array value from low stack pointer */

   istk[0] = 0;                          /* initialize the low array pointer */
   istk[1] = imax;                       /* initialize the top array pointer */
   while (irdx >= 0) {                          /* loop until sort radix < 0 */
      isp1 = istk[irdx + irdx];                 /* set the low stack pointer */
      isp2 = istk[irdx + irdx + 1];             /* set the top stack pointer */
      irdx--;                                    /* decrement the sort radix */
      iva1 = int1[isp1];           /* get array value from low stack pointer */
      iva2 = int2[isp1];           /* get array value from low stack pointer */
      itop = isp2 + 1;                          /* set the top array pointer */
      ilow = isp1;                              /* set the low array pointer */
      while (1) {                     /* loop to sort within the radix limit */
         itop--;                          /* decrement the top array pointer */
         if (itop == ilow) {         /* top array pointer==low array pointer */
            break;                               /* skip to next radix value */
         }
         if (iva2 > int2[itop]) {   /* value @low pointer>value @top pointer */
            int1[ilow] = int1[itop];        /* swap low and top array values */
            int2[ilow] = int2[itop];        /* swap low and top array values */
            iext = 0;                     /* initialize outer-loop exit flag */
            while (1) {             /* loop to compare and swap array values */
               ilow++;                    /* increment the low array pointer */
               if (itop == ilow) {   /* top array pointer==low array pointer */
                  iext = 1;                   /* set outer-loop exit flag ON */
                  break;                         /* skip to next radix value */
               }
               if (iva2 < int2[ilow]) {   /* value @low ptr.<value @low ptr. */
                  int1[itop] = int1[ilow];  /* swap top and low array values */
                  int2[itop] = int2[ilow];  /* swap top and low array values */
                  break;               /* repeat sort within the radix limit */
               }
            }
            if (iext) {                        /* outer-loop exit flag is ON */
               break;                            /* skip to next radix value */
            }
         }
      }
      int1[ilow] = iva1;           /* put array value from low stack pointer */
      int2[ilow] = iva2;           /* put array value from low stack pointer */
      if (isp2 - ilow > 1) {                     /* low segment-width is > 1 */
         irdx++;                                 /* increment the sort radix */
         istk[irdx + irdx] = ilow + 1;            /* reset low array pointer */
         istk[irdx + irdx + 1] = isp2;            /* reset top array pointer */
      }
      if (itop - isp1 > 1) {                     /* top segment-width is > 1 */
         irdx++;                                 /* increment the sort radix */
         istk[irdx + irdx] = isp1;                /* reset low array pointer */
         istk[irdx + irdx + 1] = itop - 1;        /* reset top array pointer */
      }
   }
}

V ifn_read(C *cbuf, L lbyt, U ibuf, struct _iobuf *ebuf) {  /* read f/binary */
   fseek(ebuf, lbyt, SEEK_SET);               /* set the buffer-read pointer */
   fread((V *)cbuf, 1, ibuf, ebuf);        /* read data from the binary file */
}

V ifn_write(C *cbuf, L lbyt, U ibuf, struct _iobuf *ebuf) {/* write t/binary */
   fseek(ebuf, lbyt, SEEK_SET);              /* set the buffer-write pointer */
   fwrite((V *)cbuf, 1, ibuf, ebuf);        /* write data to the binary file */
}

U io_vadr(I inop) {                      /* get video address (color or b/w) */
   rg.h.ah = 15;                                   /* video-address function */
   int86(0x10, &rg, &rg);                      /* call DOS for video address */
   if (rg.h.al == 7) {                                /* register A-low is 7 */
      return(0xb000);                                  /* return b/w address */
   } else {                                       /* register A-low is NOT 7 */
      return(0xb800);                                /* return color address */
   }
}

V io_vcls(I iclr) {                                 /* clear screen function */
   I irow;                             /* initialize the row number variable */
   C cdat[81];                             /* initialize the row data buffer */

   memset(cdat, ' ', 80);                       /* clear the row data buffer */
   cdat[80] = '\0';                         /* terminate the row data buffer */
   for (irow = 0; irow < 25; irow++) {          /* loop thru the screen rows */
      io_vdsp(cdat, irow, 0, iclr);       /* display each <blank> screen row */
   }
}

V io_vcsr(I irow, I icol, I icsr) {        /* set cursor position [and size] */
   rg.h.ah = 2;                                  /* cursor-position function */
   rg.h.bh = 0;                                           /* video page zero */
   rg.h.dh = (C)irow;                                          /* row number */
   rg.h.dl = (C)icol;                                       /* column number */
   int86(0x10, &rg, &rg);                     /* call DOS to position cursor */
   if (icsr) {                                      /* cursor-size specified */
      rg.h.ah = 1;                                   /* cursor-size function */
      rg.h.ch = (C)(13 - icsr);                     /* set cursor-begin line */
      rg.h.cl = 12;                                   /* set cursor-end line */
      int86(0x10, &rg, &rg);                  /* call DOS to set cursor size */
   }
}

V io_vdsp(C *cdat, I irow, I icol, I iclr) {       /* display data on screen */
   I ilen = strlen(cdat);                /* length of string to be displayed */
   I iptr;                              /* byte-counter for displayed string */
   U uclr = iclr * 256;                /* unsigned attribute high-byte value */

   if (!uvadr) {                            /* video pointer segment not set */
      FP_SEG(uvadr) = io_vadr(0);               /* set video pointer segment */
   }
   FP_OFF(uvadr) = irow * 160 + icol * 2;        /* set video pointer offset */
   for (iptr = 0; iptr < ilen; iptr ++) {      /* loop thru displayed string */
      *uvadr = uclr + (UC)cdat[iptr];            /* put data to video memory */
      uvadr++;                            /* increment video display pointer */
   }
}
*******************************************************************************
*******************************************************************************
*******************************************************************************
New  CCRP  documentation - changes as of 29.10.1996

----------Command----------    ------------------Output-------------------

CCRP                           Usage parameters.

CCRP  filename  /e             Encrypt each byte in 'filename' so that the
                               data cannot be seen, or, if the file was an
                               executable file, it cannot be executed.

CCRP  filename  /d             Decrypt (restore) each byte in 'filename'.

CCRP  filename  /e  key        Encrypt or decrypt 'filename', but add an
CCRP  filename  /d  key        additional factor (a key, or a password)
                               to the encryption and decryption.

                               NOTE 1: The key/password (if used) must be a
                                       contiguous string of characters with
                                       no blank spaces between any characters.

                               NOTE 2: If a key is entered for encryption, the
                                       same key must be entered for decryption.

                               NOTE 3: Encryption may be performed 2 or more
                                       times in sequence before decryption,
                                       using a different key each time, for
                                       additional encryption security.  In
                                       such case, the decryption steps must
                                       be performed in the reverse order
                                       (last encryption/first decryption).

                               NOTE 4: Encryption and decryption are mere
                                       complementary processes, so that if
                                       the decryption step were performed
                                       first, followed by encryption, the
                                       end effect would be the same.

CCRP  filename  /p             'Pad' 8th bits in 'filename', which must be a
                               '7-bit' ASCII file.  If any 8th bits were set
                               before this option is invoked, a message will
                               be displayed to that effect and changes will
                               not occur.  If all bytes in 'filename' have
                               ASCII values less than 128, then no 8th bits
                               are currently set in that file.

                               If the total number of 1-bits in 'filename' are
                               greater than or equal to the number of 0-bits
                               in the file, a message will be displayed to that
                               effect and, as above, changes will not occur.

                               This option will set only enough 8th bits to
                               equalize the 1-bits and 0-bits in the file,
                               or as many 8th bits as possible if the total
                               bytes in the file (only the 8th bit can be set)
                               are less than the number of 0-bits minus the
                               number of 1-bits in the file.

                               The purpose of bit-padding is to 'normalize' the
                               number of 1-bits in a file before encryption, to
                               further obscure the nature of the source text.

                               The intent of CCRP is actually to NOT alter any
                               bits during encryption, but rather to move them
                               into random positions within the file, so that
                               attackers cannot determine which bits belong to
                               which bytes, etc.  Bit-padding gets around this
                               requirement in that it can only be invoked as a
                               command option separate from an encryption step.
                               Note further that if bit-padding or un-padding
                               is attempted on a file which is in an encrypted
                               state, the file will be damaged beyond repair.

CCRP  filename  /u             'Unpad' 8th bits in 'filename', which must have
                               been a '7-bit' ASCII file prior to padding with
                               8th bits. This option has no warnings, and when
                               used on a file which was not originally '7-bit'
                               ASCII text, will damage the file beyond repair,
                               since the exact 8th bits to change back to 1's
                               cannot be determined.


      WARNING(!) Encryption changes the contents of a file, and if you cannot
                 perform the decryption process properly, including the use of
                 keys/passwords, you won't be able to recover the file at all.

                 Normally, before making changes to a file, you are advised
                 to make a backup copy of the file, but since the purpose of
                 encryption is to make the file unreadable and unusable, to
                 have a usable backup copy of the file on the same computer,
                 or even in the same area that the computer is located in,
                 wouldn't suit the primary purpose of encryption.


NOTES: If maximum security is the objective, you might want to encrypt a file
       several times (in several passes) with a different encryption key each
       pass, using different programs, and mixing the encryption/decryption
       order (OK as long as different keys are used).  Examples:

ENCRYPT.BAT (encrypt the file; see Note 4 above concerning the /d switch)
ccrp filename  /p
bcrp filename  /d  Little_Miss_Muffet_Sat_On_Her_Tuffet
ccrp filename  /e  The_Quick_Brown_Fox_Jumped_Over_The_Lazy_Dog
bcrp filename  /e  We_Have_Met_The_Enemy_And_They_Are_Us
ccrp filename  /d  Let_Him_That_Hath_Understanding_Count_The_Number_Of_The_Beast

DECRYPT.BAT (decrypt the file; see Note 4 above concerning the /e switch)
ccrp filename  /e  Let_Him_That_Hath_Understanding_Count_The_Number_Of_The_Beast
bcrp filename  /d  We_Have_Met_The_Enemy_And_They_Are_Us
ccrp filename  /d  The_Quick_Brown_Fox_Jumped_Over_The_Lazy_Dog
bcrp filename  /e  Little_Miss_Muffet_Sat_On_Her_Tuffet
ccrp filename  /u
*******************************************************************************
*******************************************************************************
*******************************************************************************
FAQ for Cryptography Of A Sort (COAS)
Author  : Dale Thorn <dthorn@gte.net>
Revised : 27 Oct 1996

Q: Is COAS an actual product?
A: COAS is an encryption engine supplied in source-code format, which
   calls some commonly-available (and replaceable) functions included
   with commercial computer-language libraries, which in turn perform
   some of the rudimentary tasks required by the program.  Public Key
   features are not currently supported in COAS, therefore, messaging
   applications are not as well supported as is local file encryption.

Q: What are the main differences between COAS and other non-messaging-oriented
   crypto products?
A: 1. COAS repositions bits based on multiple encoding passes using one or more
      Pseudo-Random Number Generators (PRNG's).  Since COAS is provided only in
      source code format, and since the source code calls the PRNG function in
      the compiler library(s), COAS is actually independent of specific PRNG's.
      NOTE: PRNG limitations, as described in the popular literature, do not
            necessarily apply when repositioning bits in multiple passes, as
            opposed to modifying bits as is normally done in other software.
            Think of "brute force encryption" (more on this below).
   2. COAS does not use a "key" as such, and thus does not "encrypt" the bits
      in a text bitstream.  Instead, it uses an input value (text or numeric)
      as an entry point into a common PRN sequence.  Since the entry point is
      a secret, and since bits are moved using random block sizes, from their
      original bytes into unrelated destination bytes, cryptanalytic attempts
      must necessarily begin with brute-force guessing as to the entry points
      in the PRN sequences, in order to associate the correct bits with their
      original bytes of text.  Multiple encoding passes raise the number of
      guesses exponentially.
   3. COAS source code is extremely small, the primary intent for which was
      to provide a sample encoding engine for local/personal computer files.
      Due to its small size and simplicity, the source code can be easily
      modified by casual users, who may add in their own custom routines.
      NOTE: It cannot be overemphasized, that crypto programs which have
            a widely-respected reputation must also be held suspect when
            A) The very nature of those programs is to deceive, -and-
            B) The source code is either not available, or is so complex
               as to discourage ordinary people from working with it.

Q: But if COAS uses a common, ordinary PRNG, how can it possibly be secure?
A: I can think of two arguments against using PRNG's:
   1. Encoded text is easy to decode by brute force on most computers, -and-
   2. Encoded text can be seen as having regular patterns when "viewed" from
      the vantage point of programs employing higher-dimensional mathematics.
   Addressing the former, a single-pass encryption of a text file using the
   typical PRNG might be breakable in as little as .000001 second on one of
   the larger, faster computers available, however, the same approach might
   require as many as 10^24 years if the number of encoding passes reaches
   ten or more.  To simplify: try to guess the number I'm thinking between
   zero and 32,000.  You can make 16 billion guesses per second, so it will
   take only .000001 second (on average) to get the correct answer.  If you
   had to guess ten numbers correctly (and sequentially), it would require
   roughly (16,000^10) / 16,000,000,000 seconds, approximately 10^24 years.
   Addressing the latter, the ability to "view" the text as a lattice in a
   higher dimension is likewise diminished by the discontinuities inherent
   in multi-pass encoding, when bit-group sizes are determined dynamically
   by PRN's following the secret entry points into the PRNG sequences.

Q: Since COAS only moves bits and doesn't change any of them, wouldn't that
   make cryptanalysis much easier, since the number of 0-bits and 1-bits in
   the encrypted file would be identical to the numbers in the source file?
A: While the COAS encryption processes don't actually change any bits, the
   bit-padding and de-padding options in versions 3.x and above will allow
   you to change 8th bits to 1's in "7-bit" ASCII text, after which you do
   any encryption steps followed (eventually) by decryption and de-padding.

Q: What about the possibility that two or more encryption passes could be
   decrypted in a single pass, as in the scenario where a third key K3 is
   functionally equivalent to two separate encrypting keys K1 and K2?
A: Since COAS encoding is controlled through entry points into a PRNG's
   number sequences (adjacent encryptions may also use different PRNG's
   and/or bit-move logic), searching for a "key" or algorithm which can
   unpack two or more layers of coding will prove futile when all entry
   points into the PRNG's are different, and different PRNG's are used.
   A couple of points to consider:
   One, the output of the PRNG (or any number series) does not describe
   the bit move-to locations; those are determined by sorting the PRN's
   then moving the bits according to the sequence of the original array
   positions of the PRN's prior to sorting. Since some of the PRN's are
   duplicates, the original array positions relative to each other will
   be determined by chance, i.e., the vagaries of the sort process, etc.
   Two, since the bits are moved rather than modified, and since groups
   of bits vary in size, an attempt to find particular bits that belong
   to specific bytes after multi-move shuffling, using any compound key
   or algorithm in a single decoding pass, will certainly prove futile.

Q: Since the personal computer implementation of COAS uses 16-bit integers to
   initialize (set entry points into) the PRNG's, would ten encryption passes
   be somehow equivalent to the use of a 160-bit key in conventional programs?
A: If the conventional program used a 160-bit key in a manner similar to COAS,
   it would still have to:  1) move bits, not change them. 2) use an indirect
   method for specifying move locations.  3) model the processes used in COAS
   quite closely, since there's no straightforward mathematical approach that
   can duplicate the conditions described in the previous question and answer.

Q: What's the difference between the techniques used by COAS and the use of a
   One-Time Pad (OTP)?
A: The theory behind the OTP assumes that (unlike the use of a Public/Private
   key) subsequent encryptions using the same OTP key would reveal the nature
   of the OTP, i.e., any newly-encoded files and messages would share certain
   common identifiable characteristics which could be exploited to facilitate
   the decryption of all files using that pad.
   COAS, on the other hand, doesn't alter any of a file's bits, and therefore
   does not "add" its PRNG entry points' characteristics to a file other than
   shuffling bits in accordance with the original physical positions of PRN's
   which have been sorted by size.

Q: Is it possible for anyone to alter the contents of files encrypted by COAS
   so that a person performing the eventual decryption would not realize that
   the file(s) were indeed altered?
A: Less likely than incidental or brute-force decryption.  Each bit is moved
   once in each encryption pass, and if any bits were moved or changed, that
   many bytes (or nearly as many, since bits are not moved in byte-divisible
   groups, so most will end up in unrelated bytes after encryption) would be
   affected, and the resulting bytes would not likely pass even the simplest
   checksum test.

Q: Is COAS a "weak" product (cryptographically speaking), either because of
   limitations in its own internal algorithms, or in the commercial library
   functions it calls?
A: COAS can be used in ways that produce weak encryption, which is really
   an advantage in encouraging beginners to get started, given its simple
   user interface. Whether it can produce "strong" encryption or not is a
   matter of opinion, where said opinion is not so much a function of the
   product's alleged weaknesses, as it is the fact that cryptography grew
   up from a long history of hand-ciphering and the mathematics attending
   that growth, and the obvious resistance to new paradigms in this field.
   While mathematical proof of encryption strength is highly desirable in
   most applications (some would argue essential in certain applications),
   I see things this way:  Computer software of any kind, which cannot be
   analyzed by common persons (average programmers), whose innards cannot
   be exposed to the masses for whatever reason, should not be used where
   it could effect control over the lives of those people.  Looking at it
   a different way, it's wise for any individual or group to evaluate the
   software that's available, and make their own judgements independently
   of "expert opinion" in the field.




Thread