home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / games / volume13 / okbridge / part06 / code.c next >
C/C++ Source or Header  |  1992-01-12  |  9KB  |  315 lines

  1. /* code.c
  2.  ! 
  3.  ! Copyright (C) 1990,1991 by Matthew Clegg
  4.  ! 
  5.  ! This program may be copied and distributed freely.  Please do not
  6.  ! charge money for this program or for any program derived from it.
  7.  ! If you modify this program, then include a notice stating plainly
  8.  ! that your program is derived from the okbridge program and is not
  9.  ! the same as the official okbridge program.
  10.  !
  11.  ! I welcome any suggestions for improvement to okbridge, and 
  12.  ! I would be especially happy to receive improved source code.
  13.  ! If you have comments or suggestions, or if you would like to
  14.  ! join the okbridge mailing list, then write to
  15.  !
  16.  !   mclegg@cs.ucsd.edu
  17.  !
  18.  *
  19.  * This file implements procedures for a very simple cipher which
  20.  * is used to encode crucial parts of the files which contain
  21.  * email duplicate hands.
  22.  *
  23.  * The intention of this cipher is to make the contents
  24.  * of an email duplicate file non-obvious.  This cipher is certainly
  25.  * not intended to be difficult to break -- it is simply intended to
  26.  * allow email duplicate files to be manipulated (e.g., mailed, copied,
  27.  * etc.) without having their contents revealed.
  28.  *
  29.  * The cipher that we use is based upon the following principles:
  30.  *    1.  Only the 64 characters a-zA-Z0-9+- are encoded.
  31.  *        This defines a function h(c) for characters c which is 0
  32.  *        if c is not coded and which is a unique integer in the
  33.  *        range [1,64] if c is coded.
  34.  *    2.  An initial permutation p the integers [1,64] is chosen.
  35.  *    3.  Given a string s, a permuted string s' is computed according
  36.  *        to the following formula:
  37.  *
  38.  *      s'[i] =  s[i]                  if h[s[i]] = 0,
  39.  *           h^-1 [ p[ (h[s[i]] + i) mod 64 ]]    otherwise.
  40.  *
  41.  *        In other words, the encoding of a character is determined
  42.  *        by a fixed permutation and by its index in the string.
  43.  *
  44.  * An email duplicate file begins with a header line identifying the
  45.  * fact that it is an email duplicate file.  The following line contains
  46.  * the permutation which has been used to encode the file.  The
  47.  * succeeding lines are a mixture of plain-text and coded lines.
  48.  * Coded lines begin with an exclamation point '!'.
  49.  */
  50.  
  51. #include <stdio.h>
  52.  
  53.  
  54. extern char *malloc ();
  55.  
  56. /* extern long random (); */
  57. extern int rand ();
  58. #define random(n) ((rand () / 64) % n)
  59.  
  60. int codefile_line_no;
  61.     /* The number of lines that have been read from the current
  62.            coded file. */
  63.  
  64. #define CIPHER_SIZE    64
  65. #define CIPHER_SIZE1    65
  66.  
  67. static  int cipher_mapping [128];    /* the function h above. */
  68. static  int cipher_unmapping [128];    /* h^-1, where defined  */
  69. static  int mapping_is_initialized = 0;
  70.  
  71. typedef int cipher_encoding [128];    /* the function p above. */
  72. typedef int cipher_decoding [128];    /* p^-1 */
  73.  
  74. typedef struct Encoded_File_Struct {
  75.     cipher_encoding        encoding;
  76.     cipher_decoding        decoding;
  77.     FILE            *cf;
  78. } Encoded_File;
  79.  
  80. static void Initialize_Cipher_Mapping ()
  81. {
  82.     int i;
  83.  
  84.     for (i = 0; i < 128; i++)
  85.         cipher_mapping[i] = cipher_unmapping[i] = 0;
  86.     for (i = 'A'; i <= 'Z'; i++)
  87.         cipher_mapping[i] = i - 'A' + 1;
  88.     for (i = 'a'; i <= 'z'; i++)
  89.         cipher_mapping[i] = i - 'a' + 26 + 1;
  90.     for (i = '0'; i <= '9'; i++)
  91.         cipher_mapping[i] = i - '0' + 52 + 1;
  92.     cipher_mapping['+'] = 63;
  93.     cipher_mapping['-'] = 64;
  94.  
  95.     for (i = 0; i < 128; i++)
  96.         if (cipher_mapping[i])
  97.             cipher_unmapping[cipher_mapping[i]] = i;
  98. };
  99.  
  100. static int Read_Line (f, buf, buflen)
  101.     FILE *f; char *buf; int buflen;
  102. /* Reads a line of up to buflen characters from the file f into
  103.    the buffer buf.  Returns the number of characters read, or -1
  104.    if EOF reached.
  105. */
  106. {
  107.     int i, ch;
  108.  
  109.     i = 0;
  110.     while ((ch = getc(f)) != '\n') {
  111.         if (ch == EOF)
  112.             return (-1);
  113.         if ((i < buflen - 1) && (ch != '\015'))
  114.             buf[i++] = ch;
  115.     };
  116.     buf[i] = '\0';
  117.     codefile_line_no++;
  118.     return (i);
  119. };
  120.  
  121. int Reset_Encoded_File (filename, check_string, ef)
  122.     char *filename, *check_string; Encoded_File **ef;
  123. /* Opens the named file for input.  Returns a pointer to a structure
  124.    describing the opened file.  If an error occurs in opening the
  125.    file, returns -1, in which case the system error code is stored
  126.    in errno.  Reads lines from the file until a line is found which
  127.    matches check_string.  If the check_string is not found, then
  128.    returns 1.  Else, reads the cipher_encoding from the following line.
  129.    Allocates a new Encoded_File structure and stores its location in ef.
  130.    Returns 0 on success.
  131. */
  132. {
  133.     FILE *code_file;
  134.     char *check_buffer, code_buffer [CIPHER_SIZE1];
  135.     int buflen, read_code, i;
  136.  
  137.     if (!mapping_is_initialized)
  138.         Initialize_Cipher_Mapping ();
  139.  
  140.     if (strcmp(filename, "-"))
  141.       code_file = fopen (filename, "r");
  142.     else
  143.       code_file = stdin;
  144.  
  145.     if (code_file == NULL)
  146.         return (-1);
  147.     codefile_line_no = 0;
  148.  
  149.     buflen = strlen (check_string);
  150.     check_buffer = malloc (buflen + 1);
  151.     do {
  152.         read_code = Read_Line (code_file, check_buffer, buflen+1);
  153.     } while ((read_code >= 0) && strcmp (check_string, check_buffer));
  154.     free (check_buffer);
  155.     if (read_code < 0) {
  156.         fclose (code_file);
  157.         return (1);
  158.     };
  159.  
  160.     read_code = Read_Line (code_file, code_buffer, CIPHER_SIZE1);
  161.     if (read_code < 0) {
  162.         fclose (code_file);
  163.         return (1);
  164.     };
  165.  
  166.     *ef = (Encoded_File *) malloc(sizeof(Encoded_File));
  167.     for (i = 0; i < CIPHER_SIZE; i++)
  168.         (*ef)->encoding[i+1] = cipher_mapping[code_buffer[i]];
  169.     for (i = 1; i < CIPHER_SIZE1; i++)
  170.         (*ef)->decoding[(*ef)->encoding[i]] = i;
  171.     (*ef)->cf = code_file;
  172.     return (0);
  173. };
  174.  
  175. static void Encode_Line (ef, buf)
  176.     Encoded_File *ef; char *buf;
  177. {
  178.     int i, base_code;
  179.  
  180.     for (i = 0; buf[i] != '\0'; i++)
  181.         if ((base_code = cipher_mapping[buf[i]]) != 0)
  182.             buf[i] = cipher_unmapping [ef->encoding[
  183.                     (base_code + 3*i) % CIPHER_SIZE + 1]];
  184. };
  185.  
  186. static void Decode_Line (ef, buf)
  187.     Encoded_File *ef; char *buf;
  188. {
  189.     int i, p, base_code;
  190.  
  191.     for (i = 0; buf[i] != '\0'; i++)
  192.         if ((base_code = cipher_mapping[buf[i]]) != 0) {
  193.             p = (ef->decoding[base_code] + 3*CIPHER_SIZE - 3*i)
  194.                 % CIPHER_SIZE - 1;
  195.             if (p == 0) p = CIPHER_SIZE;
  196.             buf[i] = cipher_unmapping[p];
  197.         };
  198.             
  199.  
  200. };
  201.  
  202. int Read_Encoded_Line (ef, buf, buflen)
  203.     Encoded_File *ef; char *buf; int buflen;
  204. /* Reads a line of up to buflen characters from the encoded file ef
  205.    into buf.  If the first character of the line is '!', then strips
  206.    that character and applies the decoding algorithm to the remainder
  207.    of the line.  Otherwise, just copies the line from the input file
  208.    to the buffer.  Returns the number of characters read or -1 if
  209.    the end of file is reached.
  210. */
  211. {
  212.     int i, read_code, base_mapping;
  213.  
  214.     read_code = Read_Line (ef->cf, buf, buflen);
  215.     if ((read_code <= 0) || (buf[0] != '!'))
  216.         return (read_code);
  217.  
  218.     for (i = 0; i < read_code; i++)
  219.         buf[i] = buf[i+1];
  220.     read_code -= 1;
  221.  
  222.     Decode_Line (ef, buf);
  223.     return (read_code);
  224.     
  225. };
  226.  
  227. int Rewrite_Encoded_File (filename, check_string, ef)
  228.     char *filename, *check_string; Encoded_File **ef;
  229. /* Opens the named file for output.  Returns a pointer to a structure
  230.    describing the opened file.  If an error occurs in opening the file,
  231.    then returns -1, in which case the system error code is stored
  232.    in errno.  Invents a permutation for the new encoded file.
  233.    Writes the check_string as the first line of the new file,
  234.    and the permutation as the second line.  Returns 0 to indicate
  235.    success.
  236. */
  237. {
  238.     FILE *code_file;
  239.     char code_buffer [CIPHER_SIZE1];
  240.     int read_code, i, t, c;
  241.  
  242.     if (!mapping_is_initialized)
  243.         Initialize_Cipher_Mapping ();
  244.  
  245.     if (strcmp(filename, "-"))
  246.       code_file = fopen (filename, "w");
  247.     else
  248.       code_file = stdout;
  249.  
  250.     if (code_file == NULL)
  251.         return (-1);
  252.  
  253.     *ef = (Encoded_File *) malloc(sizeof(Encoded_File));
  254.  
  255.     for (i = 1; i < CIPHER_SIZE1; i++) 
  256.         (*ef)->encoding [i] = i;
  257.     for (i = 1; i < CIPHER_SIZE; i++) {
  258.         c = random (CIPHER_SIZE + 1 - i);
  259.         t = (*ef)->encoding[i+c]; 
  260.         (*ef)->encoding[i+c] = (*ef)->encoding[i];
  261.         (*ef)->encoding[i] = t;
  262.     };
  263.  
  264.     for (i = 1; i < CIPHER_SIZE1; i++)
  265.         (*ef)->decoding[(*ef)->encoding[i]] = i;
  266.  
  267.     (*ef)->cf = code_file;
  268.  
  269.     fprintf ((*ef)->cf, "%s\n", check_string);
  270.     
  271.     for (i = 0; i < CIPHER_SIZE; i++)
  272.         code_buffer[i] = cipher_unmapping[(*ef)->encoding[i+1]];
  273.     code_buffer[CIPHER_SIZE] = '\0';
  274.     fprintf ((*ef)->cf, "%s\n", code_buffer);
  275.  
  276.     return (0);
  277.         
  278. };
  279.  
  280. int Write_Encoded_Line (ef, buf)
  281.     Encoded_File *ef; char *buf;
  282. /* Writes the encoded version of the string from buf to the encoded
  283.    file ef.  Returns 0 on success or 1 if the system reports an error.
  284. */
  285. {
  286.     Encode_Line (ef, buf);
  287.     fprintf (ef->cf, "!%s\n", buf);
  288.     fflush (ef->cf);
  289.     Decode_Line (ef, buf);
  290.     return (0);
  291. };
  292.  
  293. int Write_Unencoded_Line (ef, buf)
  294.     Encoded_File *ef; char *buf;
  295. /* Writes the unencoded line in buf to the file ef. */
  296. {
  297.     if (buf[0] == '!')
  298.         fprintf (ef->cf, " %s\n", buf);
  299.     else
  300.         fprintf (ef->cf, "%s\n", buf);
  301.     return (0);
  302. };
  303.  
  304. void Close_Encoded_File (ef)
  305.     Encoded_File *ef;
  306. /* Closes the file associated to ef and disposes of the memory
  307.    associated to ef. */
  308. {
  309.         if ((ef->cf != stdout) && (ef->cf != stdin)) {
  310.       fflush (ef->cf);
  311.       fclose (ef->cf);
  312.     };
  313.     free (ef);
  314. };
  315.