home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / vile-src.zip / vile-8.1 / crypt.c < prev    next >
C/C++ Source or Header  |  1998-09-07  |  11KB  |  412 lines

  1. /*    Crypt:    Encryption routines for MicroEMACS
  2.  *        written by Dana Hoggatt and Daniel Lawrence
  3.  *
  4.  * $Header: /usr/build/vile/vile/RCS/crypt.c,v 1.23 1998/09/07 21:17:52 tom Exp $
  5.  *
  6.  */
  7.  
  8. #ifdef STANDALONE
  9. # ifndef OPT_ENCRYPT
  10. #  define OPT_ENCRYPT 1
  11. # endif
  12. # define UINT    unsigned int
  13. # define ULONG    unsigned long
  14. #else
  15. # include    "estruct.h"
  16. # include    "edef.h"
  17. #endif
  18.  
  19. #if    OPT_ENCRYPT
  20. static    int    mod95 (int val);
  21.  
  22. #ifdef STANDALONE
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include "config.h"
  26. #else
  27. /* assume ANSI C */
  28. #define HAVE_STDLIB_H 1
  29. #endif
  30.  
  31. #include <sys/types.h>        /* sometimes needed to get size_t */
  32.  
  33. #if HAVE_STDLIB_H
  34. #include <stdlib.h>
  35. #endif
  36.  
  37. #ifdef HAVE_UNISTD_H
  38. #include <unistd.h>
  39. #endif
  40.  
  41. #if STDC_HEADERS || HAVE_STRING_H
  42. # include <string.h>
  43.   /* An ANSI string.h and pre-ANSI memory.h might conflict.  */
  44. # if !STDC_HEADERS && HAVE_MEMORY_H
  45. #  include <memory.h>
  46. # endif /* not STDC_HEADERS and HAVE_MEMORY_H */
  47. #else /* not STDC_HEADERS and not HAVE_STRING_H */
  48. # if HAVE_STRINGS_H
  49. #  include <strings.h>
  50.   /* memory.h and strings.h conflict on some systems */
  51.   /* FIXME: should probably define memcpy and company in terms of bcopy,
  52.      et al here */
  53. # endif
  54. #endif /* not STDC_HEADERS and not HAVE_STRING_H */
  55.  
  56. #include <stdio.h>
  57. #include <ctype.h>
  58.  
  59. extern    int    ue_makekey (char *key, UINT len);
  60. extern    void    ue_crypt (char *bptr, UINT len);
  61.  
  62. static void
  63. failed(const char *s)
  64. {
  65.     perror(s);
  66.     exit(1);
  67. }
  68.  
  69.  
  70. static void
  71. filecrypt(FILE *ifp, char *key, int mailmode)
  72. {
  73.  
  74.     char buf[5000];
  75.     char *p;
  76.  
  77.     ue_crypt((char *)0, 0);
  78.     ue_crypt(key, strlen(key));
  79.  
  80.     while (1) {
  81.     p = fgets( buf, sizeof(buf), ifp);
  82.     if (!p) {
  83.         if (ferror(ifp))
  84.         failed("reading file");
  85.         if (feof(ifp))
  86.         break;
  87.     }
  88.     if (mailmode) {
  89.         if (strcmp(buf, "\n") == 0)
  90.         mailmode = 0;
  91.     }
  92.     if (!mailmode)
  93.         ue_crypt(buf, strlen(buf));
  94.     if (fputs(buf, stdout) == EOF)
  95.         failed("writing stdout");
  96.     }
  97.  
  98.     if (fflush(stdout))
  99.     failed("flushing stdout");
  100.  
  101.  
  102. }
  103.  
  104. int
  105. main(int argc, char **argv)
  106. {
  107.     char key[256];
  108.     char *prog = argv[0];
  109.     int mailmode = 0;
  110.  
  111.     key[0] = 0;
  112.  
  113.     /* -m for mailmode:  leaves headers intact (up to first blank line)
  114.      * then crypts the rest.  i use this for encrypting mail messages
  115.      * in mh folders.  */
  116.     if (argc > 1 && strcmp(argv[1], "-m") == 0) {
  117.         mailmode = 1;
  118.         argc -= 1;
  119.         argv += 1;
  120.     }
  121.     if (argc > 2 && strcmp(argv[1], "-k") == 0) {
  122.         if (strlen(argv[2]) > sizeof(key) - 1) {
  123.         fprintf(stderr, "%s: excessive key length\n", prog);
  124.         exit(1);
  125.         }
  126.         (void)strncpy(key, argv[2], sizeof(key));
  127.         (void)memset(argv[2], '.', strlen(argv[2]));
  128.         key[sizeof(key)-1] = '\0';
  129.         argc -= 2;
  130.         argv += 2;
  131.     }
  132.     if (argc > 1 && argv[1][0] == '-') {
  133.         fprintf(stderr,
  134.         "usage: %s [-m] [-k crypt-key] [file ...]\n"
  135.         "  where crypt-key will be prompted for if not specified\n"
  136.         "  and -m will force \"mail-mode\", which leaves text before\n"
  137.         "  the first empty line of a file (i.e. headers) intact.\n",
  138.         prog
  139.         );
  140.         exit(1);
  141.     }
  142.     if (!key[0]) {
  143. #if HAVE_GETPASS
  144.         char *userkey;
  145.         userkey = getpass("Enter key: ");
  146.  
  147.         /* HACK -- the linux version of getpass is not
  148.          * interruptible.  this means there's no way to abort
  149.          * a botched passwd.  until this problem goes away (and
  150.          * i do believe it's a bug, and i'm not planning on
  151.          * providing our own getpass()) we'll just see if the last
  152.          * char of the entered key is ^C, and consider it an abort
  153.          * if so.  yes, this should really be the INTR char.
  154.          */
  155.         if (userkey[strlen(userkey)-1] == 3) {
  156.         fprintf(stderr,"Aborted\n");
  157.         exit(1);
  158.         }
  159.         (void)strncpy(key, userkey, sizeof(key));
  160.         (void)memset(userkey, '.', strlen(userkey));
  161. #else
  162.         fprintf(stderr,
  163.         "usage: %s [-m] -k crypt-key [file ...]\n"
  164.         "  where '-k crypt-key' is required (no prompting on this system)\n"
  165.         "  and -m will force \"mail-mode\", which leaves text before\n"
  166.         "  the first empty line of a file (i.e. headers) intact.\n",
  167.         prog
  168.         );
  169.         exit(1);
  170. #endif
  171.     }
  172.  
  173.     if (argc > 1) {
  174.         int n;
  175.         for (n = 1; n < argc; n++) {
  176.             FILE *fp = fopen(argv[n], "r");
  177.             if (fp == 0)
  178.                 failed(argv[n]);
  179.             filecrypt(fp, key, mailmode);
  180.             (void)fclose(fp);
  181.         }
  182.     } else {
  183.         filecrypt(stdin, key, mailmode);
  184.     }
  185.     exit(0);
  186. }
  187.  
  188. #else /* STANDALONE */
  189.  
  190. int
  191. ue_makekey(            /* make encryption key */
  192. char    *key,            /* where to write key */
  193. UINT    len)
  194. {
  195.     register int status;    /* return status */
  196.     int odisinp = disinp;    /* original value of disinp */
  197.     char    temp[NPAT];
  198.  
  199.     /* turn command input echo off */
  200.     disinp = FALSE;
  201.  
  202.     /* get the string to use as an encryption string */
  203.     temp[0] = EOS;
  204.     status = mlreply("Encryption String: ", temp, len-1);
  205.     disinp = odisinp;
  206.  
  207.         if (status == TRUE) {
  208.         (void)strcpy(key, temp);
  209.  
  210.         /* and encrypt it */
  211.         ue_crypt((char *)0, 0);
  212.         ue_crypt(key, strlen(key));
  213.     }
  214.     mlerase();        /* clear it off the bottom line */
  215.     return(status);
  216. }
  217.  
  218. /* ARGSUSED */
  219. int
  220. ue_setkey(        /* reset encryption key of current buffer */
  221. int f GCC_UNUSED,    /* default flag */
  222. int n GCC_UNUSED)    /* numeric argument */
  223. {
  224.     register int s = ue_makekey(curbp->b_key, NPAT);
  225.  
  226.     if (s == FALSE) {
  227.         if (curbp->b_key[0] != EOS) {
  228.             s = mlyesno("Discard encryption key");
  229.             if (s == TRUE) {
  230.                 curbp->b_key[0] = EOS;
  231.                 make_local_b_val(curbp, MDCRYPT);
  232.                 set_b_val(curbp, MDCRYPT, FALSE);
  233.                 curwp->w_flag |= WFMODE;
  234.             }
  235.         }
  236.     }
  237.     return (s);
  238. }
  239.  
  240. #endif /* STANDALONE */
  241.  
  242. /**********
  243.  *
  244.  *    ue_crypt - in place encryption/decryption of a buffer
  245.  *
  246.  *    (C) Copyright 1986, Dana L. Hoggatt
  247.  *    1216, Beck Lane, Lafayette, IN
  248.  *
  249.  *    When consulting directly with the author of this routine,
  250.  *    please refer to this routine as the "DLH-POLY-86-B CIPHER".
  251.  *
  252.  *    This routine was written for Dan Lawrence, for use in V3.8 of
  253.  *    MicroEMACS, a public domain text/program editor.
  254.  *
  255.  *    I kept the following goals in mind when preparing this function:
  256.  *
  257.  *        1.    All printable characters were to be encrypted back
  258.  *        into the printable range, control characters and
  259.  *        high-bit characters were to remain unaffected.  this
  260.  *        way, encrypted would still be just as cheap to
  261.  *        transmit down a 7-bit data path as they were before.
  262.  *
  263.  *        2.    The encryption had to be portable.  The encrypted
  264.  *        file from one computer should be able to be decrypted
  265.  *        on another computer.
  266.  *
  267.  *        3.    The encryption had to be inexpensive, both in terms
  268.  *        of speed and space.
  269.  *
  270.  *        4.    The system needed to be secure against all but the
  271.  *        most determined of attackers.
  272.  *
  273.  *    For encryption of a block of data, one calls crypt passing
  274.  *    a pointer to the data block and its length. The data block is
  275.  *    encrypted in place, that is, the encrypted output overwrites
  276.  *    the input.  Decryption is totally isomorphic, and is performed
  277.  *    in the same manner by the same routine.
  278.  *
  279.  *    Before using this routine for encrypting data, you are expected
  280.  *    to specify an encryption key.  This key is an arbitrary string,
  281.  *    to be supplied by the user.  To set the key takes two calls to
  282.  *    ue_crypt().  First, you call
  283.  *
  284.  *        ue_crypt(NULL, vector)
  285.  *
  286.  *    This resets all internal control information.  Typically (and
  287.  *    specifically in the case on MICRO-emacs) you would use a "vector"
  288.  *    of 0.  Other values can be used to customize your editor to be
  289.  *    "incompatible" with the normally distributed version.  For
  290.  *    this purpose, the best results will be obtained by avoiding
  291.  *    multiples of 95.
  292.  *
  293.  *    Then, you "encrypt" your password by calling
  294.  *
  295.  *        ue_crypt(pass, strlen(pass))
  296.  *
  297.  *    where "pass" is your password string.  Crypt() will destroy
  298.  *    the original copy of the password (it becomes encrypted),
  299.  *    which is good.  You do not want someone on a multiuser system
  300.  *    to peruse your memory space and bump into your password.
  301.  *    Still, it is a better idea to erase the password buffer to
  302.  *    defeat memory perusal by a more technical snooper.
  303.  *
  304.  *    For the interest of cryptologists, at the heart of this
  305.  *    function is a Beaufort Cipher.  The cipher alphabet is the
  306.  *    range of printable characters (' ' to '~'), all "control"
  307.  *    and "high-bit" characters are left unaltered.
  308.  *
  309.  *    The key is a variant autokey, derived from a weighted sum
  310.  *    of all the previous clear text and cipher text.  A counter
  311.  *    is used as salt to obliterate any simple cyclic behavior
  312.  *    from the clear text, and key feedback is used to assure
  313.  *    that the entire message is based on the original key,
  314.  *    preventing attacks on the last part of the message as if
  315.  *    it were a pure autokey system.
  316.  *
  317.  *    Overall security of encrypted data depends upon three
  318.  *    factors:  the fundamental cryptographic system must be
  319.  *    difficult to compromise; exhaustive searching of the key
  320.  *    space must be computationally expensive; keys and plaintext
  321.  *    must remain out of sight.  This system satisfies this set
  322.  *    of conditions to within the degree desired for MicroEMACS.
  323.  *
  324.  *    Though direct methods of attack (against systems such as
  325.  *    this) do exist, they are not well known and will consume
  326.  *    considerable amounts of computing time.  An exhaustive
  327.  *    search requires over a billion investigations, on average.
  328.  *
  329.  *    The choice, entry, storage, manipulation, alteration,
  330.  *    protection and security of the keys themselves are the
  331.  *    responsibility of the user.
  332.  *
  333.  **********/
  334.  
  335. void
  336. ue_crypt(
  337. register char *bptr,    /* buffer of characters to be encrypted */
  338. register UINT len)    /* number of characters in the buffer */
  339. {
  340.     register int cc;    /* current character being considered */
  341.  
  342.     static ULONG key = 0;    /* 29 bit encipherment key */
  343.     static int salt = 0;    /* salt to spice up key with */
  344.  
  345.     if (!bptr) {        /* is there anything here to encrypt? */
  346.         key = len;    /* set the new key */
  347.         salt = len;    /* set the new salt */
  348.         return;
  349.     }
  350.     while (len--) {        /* for every character in the buffer */
  351.  
  352.         cc = *bptr;    /* get a character out of the buffer */
  353.  
  354.         /* only encipher printable characters */
  355.         if ((cc >= ' ') && (cc <= '~')) {
  356.  
  357. /**  If the upper bit (bit 29) is set, feed it back into the key.  This
  358.     assures us that the starting key affects the entire message.  **/
  359.  
  360.             key &= 0x1FFFFFFFL;    /* strip off overflow */
  361.             if (key & 0x10000000L) {
  362.                 key ^= 0x0040A001L;    /* feedback */
  363.             }
  364.  
  365. /**  Down-bias the character, perform a Beaufort encipherment, and
  366.     up-bias the character again.  We want key to be positive
  367.     so that the left shift here will be more portable and the
  368.     mod95() faster   **/
  369.  
  370.             cc = mod95((int)(key % 95) - (cc - ' ')) + ' ';
  371.  
  372. /**  the salt will spice up the key a little bit, helping to obscure
  373.     any patterns in the clear text, particularly when all the
  374.     characters (or long sequences of them) are the same.  We do
  375.     not want the salt to go negative, or it will affect the key
  376.     too radically.  It is always a good idea to chop off cyclics
  377.     to prime values.  **/
  378.  
  379.             if (++salt >= 20857) {    /* prime modulus */
  380.                 salt = 0;
  381.             }
  382.  
  383. /**  our autokey (a special case of the running key) is being
  384.     generated by a weighted checksum of clear text, cipher
  385.     text, and salt.   **/
  386.  
  387.             key = key + key + cc + *bptr + salt;
  388.         }
  389.         *bptr++ = cc;    /* put character back into buffer */
  390.     }
  391.     return;
  392. }
  393.  
  394. static int mod95(register int val)
  395. {
  396.     /*  The mathematical MOD does not match the computer MOD  */
  397.  
  398.     /*  Yes, what I do here may look strange, but it gets the
  399.         job done, and portably at that.  */
  400.  
  401.     while (val >= 9500)
  402.         val -= 9500;
  403.     while (val >= 950)
  404.         val -= 950;
  405.     while (val >= 95)
  406.         val -= 95;
  407.     while (val < 0)
  408.         val += 95;
  409.     return (val);
  410. }
  411. #endif
  412.