source: zcrypt.c @ c86a35c

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