source: zcrypt.c @ e51b410

barnowl_perlaimdebianowlrelease-1.10release-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since e51b410 was f87c490, checked in by James M. Kretchmar <kretch@mit.edu>, 22 years ago
CTRL and META are now OWL_CTRL and OWL_META. OWL_CTRL moved to keypress.c do_encrypt declaired static
  • Property mode set to 100644
File size: 16.8 KB
Line 
1/* This file is stolen and slightly modified code */
2
3/* zcrypt.c -- Read in a data stream from stdin & dump a decrypted/encrypted *
4 *   datastream.  Reads the string to make the key from from the first       *
5 *   parameter.  Encrypts or decrypts according to -d or -e flag.  (-e is    *
6 *   default.)  Will invoke zwrite if the -c option is provided for          *
7 *   encryption.  If a zephyr class is specified & the keyfile name omitted  *
8 *   the ~/.crypt-table will be checked for "crypt-classname" and then       *
9 *   "crypt-default" for the keyfile name.                                   */
10
11static const char fileIdent[] = "$Id$";
12
13#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
16#include <sys/types.h>
17#include <sys/wait.h>
18#include "owl.h"
19
20#define BASE_CODE 70
21#define LAST_CODE (BASE_CODE + 15)
22#define OUTPUT_BLOCK_SIZE 16
23#include <unistd.h>
24#include <sys/types.h>
25#include <des.h>
26#include <zephyr/zephyr.h>
27
28#define MAX_KEY 128
29
30#ifndef TRUE
31#define TRUE -1
32#endif
33#ifndef FALSE
34#define FALSE 0
35#endif
36
37#define ZWRITE_OPT_NOAUTH     (1<<0)
38#define ZWRITE_OPT_SIGNATURE  (1<<1)
39#define ZWRITE_OPT_IGNOREVARS (1<<2)
40#define ZWRITE_OPT_VERBOSE    (1<<3)
41#define ZWRITE_OPT_QUIET      (1<<4)
42#define ZCRYPT_OPT_MESSAGE    (1<<5)
43#define ZCRYPT_OPT_IGNOREDOT  (1<<6)
44
45typedef struct
46{
47  int flags;
48  char *signature;
49  char *message;
50} ZWRITEOPTIONS;
51
52char *GetZephyrVarKeyFile(char *whoami, char *class, char *instance);
53char *BuildArgString(char **argv, int start, int end);
54static int do_encrypt(char *keystring, int zephyr, char *class, char *instance, ZWRITEOPTIONS *zoptions, char* keyfile);
55int do_decrypt(char *keystring);
56
57#ifndef HAVE_DES_ECB_ENCRYPT_PROTO
58int des_ecb_encrypt(char [], char [], des_key_schedule, int);
59#endif
60
61#define M_NONE            0
62#define M_ZEPHYR_ENCRYPT  1
63#define M_DECRYPT         2
64#define M_ENCRYPT         3
65#define M_RANDOMIZE       4
66#define M_SETKEY          5
67
68int zcrypt(int argc, char *argv[]) {
69  char *fname = NULL;
70  int error = FALSE;
71  int zephyr = FALSE;
72  char *class = NULL, *instance = NULL;
73  int mode = M_NONE;
74
75  extern int optind, opterr;
76  extern char *optarg;
77  char c;
78
79  int messageflag = FALSE;
80  ZWRITEOPTIONS zoptions;
81  zoptions.flags = 0;
82
83  while ((c = getopt(argc, argv, "ZDERSF:c:i:advqtluons:f:m")) != (char)EOF) {
84    switch(c) {
85      case 'Z':
86        /* Zephyr encrypt */
87        mode = M_ZEPHYR_ENCRYPT;
88        break;
89      case 'D':
90        /* Decrypt */
91        mode = M_DECRYPT;
92        break;
93      case 'E':
94        /* Encrypt */
95        mode = M_ENCRYPT;
96        break;
97      case 'R':
98        /* Randomize the keyfile */
99        mode = M_RANDOMIZE;
100        break;
101      case 'S':
102        /* Set a new key value from stdin */
103        mode = M_SETKEY;
104        break;
105      case 'F':
106        /* Specify the keyfile explicitly */
107        if (fname != NULL) error = TRUE;
108        fname = optarg;
109        break;
110      case 'c':
111        /* Zwrite/zcrypt: class name */
112        if (class != NULL) error = TRUE;
113        class = optarg;
114        break;
115      case 'i':
116        /* Zwrite/zcrypt: instance name */
117        if (instance != NULL) error = TRUE;
118        instance = optarg;
119        break;
120      case 'a':
121        /* Zwrite: authenticate (default) */
122        zoptions.flags &= ~ZWRITE_OPT_NOAUTH;
123        break;
124      case 'd':
125        /* Zwrite: do not authenticate */
126        zoptions.flags |= ZWRITE_OPT_NOAUTH;
127        break;
128      case 'v':
129        /* Zwrite: verbose */
130        zoptions.flags |= ZWRITE_OPT_VERBOSE;
131        break;
132      case 'q':
133        /* Zwrite: quiet */
134        zoptions.flags |= ZWRITE_OPT_QUIET;
135        break;
136      case 't':
137        /* Zwrite: no expand tabs (ignored) */
138        break;
139      case 'l':
140        /* Zwrite: ignore '.' on a line by itself (ignored) */
141        zoptions.flags |= ZCRYPT_OPT_IGNOREDOT;
142        break;
143      case 'u':
144        /* Zwrite: urgent message */
145        instance = "URGENT";
146        break;
147      case 'o':
148        /* Zwrite: ignore zephyr variables zwrite-class, zwrite-inst, */
149        /*         zwrite-opcode */
150        zoptions.flags |= ZWRITE_OPT_IGNOREVARS;
151        break;
152      case 'n':
153        /* Zwrite: prevent PING message (always used) */
154        break;
155      case 's':
156        /* Zwrite: signature */
157        zoptions.flags |= ZWRITE_OPT_SIGNATURE;
158        zoptions.signature = optarg;
159        break;
160      case 'f':
161        /* Zwrite: file system specification (ignored) */
162        break;
163      case 'm':
164        /* Message on rest of line */
165        messageflag = TRUE;
166        break;
167      case '?':
168        error = TRUE;
169        break;
170    }
171    if (error || messageflag) break;
172  }
173
174  if (class != NULL || instance != NULL) {
175    zephyr = TRUE;
176  }
177
178  if (messageflag) {
179    zoptions.flags |= ZCRYPT_OPT_MESSAGE;
180    zoptions.message = BuildArgString(argv, optind, argc);
181    if (!zoptions.message)
182    {
183      printf("Memory allocation error.\n");
184      error = TRUE;
185    }
186  } else if (optind < argc) {
187    error = TRUE;
188  }
189
190  if (mode == M_NONE) mode = (zephyr?M_ZEPHYR_ENCRYPT:M_ENCRYPT);
191
192  if (mode == M_ZEPHYR_ENCRYPT && !zephyr) error = TRUE;
193
194  if (!error && fname == NULL && (class != NULL || instance != NULL)) {
195    fname = GetZephyrVarKeyFile(argv[0], class, instance);
196  }
197
198 
199  if (error || fname == NULL) {
200    printf("Usage: %s [-Z|-D|-E|-R|-S] [-F Keyfile] [-c class] [-i instance]\n", argv[0]);
201    printf("       [-advqtluon] [-s signature] [-f arg] [-m message]\n");
202    printf("  One or more of class, instance, and keyfile must be specified.\n");
203  } else {
204    if (mode == M_RANDOMIZE) {
205      /* Choose a new, random key */
206/*
207      FILE *fkey = fopen(fname, "w");
208      if (!fkey)
209        printf("Could not open key file for writing: %s\n", fname);
210      else
211      {
212        char string[100];
213        fputs(fkey, string);
214        fclose(fkey);
215        }
216 */
217      printf("Feature not yet implemented.\n");
218    } else if (mode == M_SETKEY) {
219      /* Set a new, user-entered key */
220      char newkey[MAX_KEY];
221      FILE *fkey;
222     
223      if (isatty(0)) {
224        printf("Enter new key: ");
225        /* Really should read without echo!!! */
226        fgets(newkey, MAX_KEY - 1, stdin);
227      } else {
228        fgets(newkey, MAX_KEY - 1, stdin);
229      }
230
231      fkey = fopen(fname, "w");
232      if (!fkey) {
233        printf("Could not open key file for writing: %s\n", fname);
234      } else {
235        if (fputs(newkey, fkey) != strlen(newkey) || putc('\n', fkey) != '\n') {
236          printf("Error writing to key file.\n");
237          fclose(fkey);
238        } else {
239          fclose(fkey);
240          printf("Key update complete.\n");
241        }
242      }
243    } else {
244      /* Encrypt/decrypt */
245      FILE *fkey = fopen(fname, "r");
246      if (!fkey) {
247        printf("Could not open key file: %s\n", fname);
248      } else {
249        char keystring[MAX_KEY];
250        fgets(keystring, MAX_KEY-1, fkey);
251        if (mode == M_ZEPHYR_ENCRYPT || mode == M_ENCRYPT) {
252          do_encrypt(keystring, (mode == M_ZEPHYR_ENCRYPT), class, instance,
253                     &zoptions, fname);
254        } else {
255          do_decrypt(keystring);
256        }
257        fclose(fkey);
258      }
259    }
260  }
261
262  /* Always print the **END** message if -D is specified. */
263  if (mode == M_DECRYPT) printf("**END**\n");
264
265  exit(0);
266}
267
268int zcrypt_decrypt(char *out, char *in, char *class, char *instance) {
269  /* written by kretch for owl. */
270  /* return 0 on success, otherwise -1 */
271  char *fname, keystring[MAX_KEY], *inptr, *endptr;
272  FILE *fkey;
273  des_cblock key;
274  des_key_schedule schedule;
275  char input[8], output[9];
276  int i, c1, c2;
277 
278  fname=GetZephyrVarKeyFile("zcrypt", class, instance);
279  fkey=fopen(fname, "r");
280  if (!fkey) return(-1);
281  fgets(keystring, MAX_KEY-1, fkey);
282  fclose(fkey);
283
284  strcpy(out, "");
285
286  output[0] = '\0';    /* In case no message at all                 */
287  output[8] = '\0';    /* NULL at end will limit string length to 8 */
288
289  des_string_to_key(keystring, key);
290  des_key_sched(key, schedule);
291
292  inptr=in;
293  endptr=in+strlen(in)-1;
294  while (inptr<endptr) {
295    for (i=0; i<8; i++) {
296      c1=(inptr[0])-BASE_CODE;
297      c2=(inptr[1])-BASE_CODE;
298      input[i]=c1 * 0x10 + c2;
299      inptr+=2;
300    }
301    des_ecb_encrypt(input, output, schedule, FALSE);
302    strcat(out, output);
303  }
304
305  if (output[0]) {
306    if (output[strlen(output)-1] != '\n') {
307      strcat(out, "\n");
308    }
309  } else {
310    strcat(out, "\n");
311  }
312  return(0);
313}
314
315int zcrypt_encrypt(char *out, char *in, char *class, char *instance) {
316  return(0);
317}
318
319/* Build a space-separated string from argv from elements between start  *
320 * and end - 1.  malloc()'s the returned string. */
321char *BuildArgString(char **argv, int start, int end) {
322  int len = 1;
323  int i;
324  char *result;
325
326  /* Compute the length of the string.  (Plus 1 or 2) */
327  for (i = start; i < end; i++) {
328    len += strlen(argv[i]) + 1;
329  }
330
331  /* Allocate memory */
332  result = (char *)malloc(len);
333  if (result) {
334    /* Build the string */
335    char *ptr = result;
336    /* Start with an empty string, in case nothing is copied. */
337    *ptr = '\0';
338    /* Copy the arguments */
339    for (i = start; i < end; i++) {
340      char *temp = argv[i];
341      /* Add a space, if not the first argument */
342      if (i != start) *ptr++ = ' ';
343      /* Copy argv[i], leaving ptr pointing to the '\0' copied from temp */
344      while ((*ptr = *temp++)!=0) {
345        ptr++;
346      }
347    }
348  }
349
350  return(result);
351}
352
353#define MAX_BUFF 258
354#define MAX_SEARCH 3
355/* Find the class/instance in the .crypt-table */
356char *GetZephyrVarKeyFile(char *whoami, char *class, char *instance) {
357  char *keyfile = NULL;
358  char varname[MAX_SEARCH][128];
359  int length[MAX_SEARCH], i;
360  char buffer[MAX_BUFF];
361  char filename[MAX_BUFF];
362  char result[MAX_SEARCH][MAX_BUFF];
363  int numsearch = 0;
364  FILE *fsearch;
365
366  /* Determine names to look for in .crypt-table */
367  if (instance) {
368    sprintf(varname[numsearch++], "crypt-%s-%s:", (class?class:"message"), 
369            instance);
370  }
371  if (class) {
372    sprintf(varname[numsearch++], "crypt-%s:", class);
373  }
374  sprintf(varname[numsearch++], "crypt-default:");
375
376  /* Setup the result array, and determine string lengths */
377  for (i = 0; i < numsearch; i++) {
378    result[i][0] = '\0';
379    length[i] = strlen(varname[i]);
380  }
381
382  /* Open~/.crypt-table */
383  sprintf(filename, "%s/.crypt-table", getenv("HOME"));
384  fsearch = fopen(filename, "r");
385  if (fsearch) {
386    /* Scan file for a match */
387    while (!feof(fsearch)) {
388      fgets(buffer, MAX_BUFF - 3, fsearch);
389      for (i = 0; i < numsearch; i++) {
390        if (strncasecmp(varname[i], buffer, length[i]) == 0) {
391          int j;
392          for (j = length[i]; buffer[j] == ' '; j++)
393            ;
394          strcpy(result[i], &buffer[j]);
395          if (*result[i]) {
396            if (result[i][strlen(result[i])-1] == '\n') {
397              result[i][strlen(result[i])-1] = '\0';
398            }
399          }
400        }
401      }
402    }
403
404    /* Pick the "best" match found */
405    keyfile = NULL;
406    for (i = 0; i < numsearch; i++) {
407      if (*result[i]) {
408        keyfile = result[i];
409        break;
410      }
411    }
412
413    if (keyfile == NULL) {
414      printf("Could not find key table entry.\n");
415    } else {
416      /* Prepare result to be returned */
417      char *temp = keyfile;
418      keyfile = (char *)malloc(strlen(temp) + 1);
419      if (keyfile) {
420        strcpy(keyfile, temp);
421      } else {
422        printf("Memory allocation error.\n");
423      }
424    }
425   
426    fclose(fsearch);
427  } else {
428    printf("Could not open key table file: %s\n", filename);
429  }
430
431  return(keyfile);
432}
433
434static pid_t zephyrpipe_pid = 0;
435
436/* Open a pipe to zwrite */
437static FILE *GetZephyrPipe(char *class, char *instance, ZWRITEOPTIONS *zoptions) {
438  int fildes[2];
439  pid_t pid;
440  FILE *result;
441  char *argv[20];
442  int argc = 0;
443
444  if (pipe(fildes) < 0) return(NULL);
445  pid = fork();
446
447  if (pid < 0) {
448    /* Error: clean up */
449    close(fildes[0]);
450    close(fildes[1]);
451    result = NULL;
452  } else if (pid == 0) {
453    /* Setup child process */
454    argv[argc++] = "zwrite";
455    argv[argc++] = "-n";     /* Always send without ping */
456    if (class) {
457      argv[argc++] = "-c";
458      argv[argc++] = class;
459    }
460    if (instance) {
461      argv[argc++] = "-i";
462      argv[argc++] = instance;
463    }
464    if (zoptions->flags & ZWRITE_OPT_NOAUTH) argv[argc++] = "-d";
465    if (zoptions->flags & ZWRITE_OPT_QUIET) argv[argc++] = "-q";
466    if (zoptions->flags & ZWRITE_OPT_VERBOSE) argv[argc++] = "-v";
467    if (zoptions->flags & ZWRITE_OPT_SIGNATURE) {
468      argv[argc++] = "-s";
469      argv[argc++] = zoptions->signature;
470    }
471    argv[argc++] = "-O";
472    argv[argc++] = "crypt";
473    argv[argc] = NULL;
474    close(fildes[1]);
475    if (fildes[0] != STDIN_FILENO) {
476      if (dup2(fildes[0], STDIN_FILENO) != STDIN_FILENO) exit(0);
477      close(fildes[0]);
478    }
479    close(fildes[0]);
480    execvp(argv[0], argv);
481    printf("Exec error: could not run zwrite\n");
482    exit(0);
483  } else {
484    close(fildes[0]);
485    /* Create a FILE * for the zwrite pipe */
486    result = (FILE *)fdopen(fildes[1], "w");
487    zephyrpipe_pid = pid;
488  }
489
490  return(result);
491}
492
493/* Close the pipe to zwrite */
494void CloseZephyrPipe(FILE *pipe) {
495  fclose(pipe);
496  waitpid(zephyrpipe_pid, NULL, 0);
497  zephyrpipe_pid = 0;
498}
499
500#define MAX_RESULT 2048
501
502
503void block_to_ascii(char *output, FILE *outfile) {
504  int i;
505  for (i = 0; i < 8; i++) {
506    putc(((output[i] & 0xf0) >> 4) + BASE_CODE, outfile);
507    putc( (output[i] & 0x0f)       + BASE_CODE, outfile);
508  }
509}
510
511#define MAX_LINE 128
512
513/* Encrypt stdin, with prompt if isatty, and send to stdout, or to zwrite
514   if zephyr is set. */
515static int do_encrypt(char *keystring, int zephyr, char *class, char *instance, ZWRITEOPTIONS *zoptions, char* keyfile) {
516  des_cblock key;
517  des_key_schedule schedule;
518  char input[8], output[8];
519  int size;
520  FILE *outfile = stdout;
521  int error = FALSE;
522  char *inbuff = NULL, *inptr;
523  int freein = FALSE;
524  int use_buffer = FALSE;
525  int num_blocks=0, last_block_size=0;
526
527  des_string_to_key(keystring, key);
528  des_key_sched(key, schedule);
529
530  if (zephyr) {
531    if (zoptions->flags & ZCRYPT_OPT_MESSAGE) {
532      /* Use the -m message */
533      int length;
534      inbuff = zoptions->message;     
535      length = strlen(inbuff);
536      num_blocks = (length + 7) / 8;
537      last_block_size = ((length + 7) % 8) + 1;
538      use_buffer = TRUE;
539    } else if (isatty(0)) {
540      /* tty input, so show the "Type your message now..." message */
541      if (zoptions->flags & ZCRYPT_OPT_IGNOREDOT) {
542        printf("Type your message now.  End with the end-of-file character.\n");
543      } else {
544        printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
545      }
546      use_buffer = TRUE;
547      if ((inptr = inbuff = (char *)malloc(MAX_RESULT)) == NULL) {
548        printf("Memory allocation error\n");
549        return FALSE;
550      }
551      while (inptr - inbuff < MAX_RESULT - MAX_LINE - 20) {
552        fgets(inptr, MAX_LINE, stdin);
553        if (inptr[0]) {
554          if (inptr[0] == '.' && inptr[1] == '\n' && 
555              !(zoptions->flags & ZCRYPT_OPT_IGNOREDOT)) {
556            inptr[0] = '\0';
557            break;
558          } else {
559            inptr += strlen(inptr);
560          }
561        } else {
562          break;
563        }
564      }
565      num_blocks = (inptr - inbuff + 7) / 8;
566      last_block_size = ((inptr - inbuff + 7) % 8) + 1;
567      freein = TRUE;
568    }
569
570    /* if (zephyr) */
571    outfile = GetZephyrPipe(class, instance, zoptions);
572    if (!outfile) {
573      printf("Could not run zwrite\n");
574      if (freein && inbuff) {
575        free(inbuff);
576      }
577      return(FALSE);
578    }
579  }
580
581  inptr = inbuff;
582
583  /* Encrypt the input (inbuff or stdin) and send it to outfile */
584  while (TRUE) {
585    if (use_buffer) {
586      /* Get 8 bytes from buffer */
587      if (num_blocks > 1) {
588        size = 8;
589        memcpy(input, inptr, size);
590        inptr += 8;
591        num_blocks--;
592      } else if (num_blocks == 1) {
593        size = last_block_size;
594        memcpy(input, inptr, size);
595        num_blocks--;
596      } else {
597        size = 0;
598      }
599    } else {
600      /* Get 8 bytes from stdin */
601      size = fread(input, 1, 8, stdin);
602    }
603
604    /* Check for EOF and pad the string to 8 chars, if needed */
605    if (size == 0) break;     /* END OF INPUT: BREAK FROM while LOOP! */
606     
607    if (size < 8) memset(input + size, 0, 8 - size);
608
609    /* Encrypt and output the block */
610    des_ecb_encrypt(input, output, schedule, TRUE);
611    block_to_ascii(output, outfile);
612
613    if (size < 8) break;
614  }
615
616  /* Close out the output */
617  if (!error) putc('\n', outfile);
618  if (zephyr) CloseZephyrPipe(outfile);
619
620  /* Free the input buffer, if necessary */
621  if (freein && inbuff) free(inbuff);
622
623  return(!error);
624}
625
626/* Read a half-byte from stdin, skipping invalid characters.  Returns -1
627   if at EOF or file error */
628int read_ascii_nybble() {
629  char c;
630
631  while (TRUE) {
632    if (fread(&c, 1, 1, stdin) == 0) {
633      return(-1);
634    } else if (c >= BASE_CODE && c <= LAST_CODE) {
635      return(c - BASE_CODE);
636    }
637  }
638}
639
640/* Read both halves of the byte and return the single byte.  Returns -1
641   if at EOF or file error. */
642int read_ascii_byte() {
643  int c1, c2;
644  c1 = read_ascii_nybble();
645  if (c1 >= 0) {
646    c2 = read_ascii_nybble();
647    if (c2 >= 0) {
648      return c1 * 0x10 + c2;
649    }
650  }
651  return(-1);
652}
653
654/* Read an 8-byte DES block from stdin */
655int read_ascii_block(char *input) {
656  int c, i;
657
658  for (i = 0; i < 8; i++) {
659    c = read_ascii_byte();
660    if (c < 0) return(FALSE);
661    input[i] = c;
662  }
663
664  return(TRUE);
665}
666
667/* Decrypt stdin */
668int do_decrypt(char *keystring) {
669  des_cblock key;
670  des_key_schedule schedule;
671  char input[8], output[9];
672
673  output[0] = '\0';    /* In case no message at all                 */
674  output[8] = '\0';    /* NULL at end will limit string length to 8 */
675
676  des_string_to_key(keystring, key);
677  des_key_sched(key, schedule);
678
679  while (read_ascii_block(input)) {
680    des_ecb_encrypt(input, output, schedule, FALSE);
681    printf("%s", output);
682  }
683
684  if (output[0]) {
685    if (output[strlen(output)-1] != '\n') {
686      printf("\n");
687    }
688  } else {
689    printf("\n");
690  }
691  return(0);
692}
Note: See TracBrowser for help on using the repository browser.