source: zcrypt.c @ d6bc343

release-1.10
Last change on this file since d6bc343 was 8f335a8, checked in by Anders Kaseorg <andersk@mit.edu>, 12 years ago
zcrypt: Accept --help Signed-off-by: Anders Kaseorg <andersk@mit.edu>
  • Property mode set to 100644
File size: 21.9 KB
RevLine 
[edae037]1/* zcrypt.c -- Read in a data stream from stdin & dump a decrypted/encrypted *
2 *   datastream.  Reads the string to make the key from from the first       *
3 *   parameter.  Encrypts or decrypts according to -d or -e flag.  (-e is    *
4 *   default.)  Will invoke zwrite if the -c option is provided for          *
5 *   encryption.  If a zephyr class is specified & the keyfile name omitted  *
6 *   the ~/.crypt-table will be checked for "crypt-classname" and then       *
7 *   "crypt-default" for the keyfile name.                                   */
8
9#include <stdio.h>
[6b1c3b6]10
[edae037]11#include <unistd.h>
12#include <sys/types.h>
[6b1c3b6]13#include <glib.h>
[356465e]14#include <string.h>
15#include <stdlib.h>
16#include <sys/wait.h>
[8bd190d]17#include <ctype.h>
[8f335a8]18#include <limits.h>
[478dc8e]19#include <getopt.h>
[edae037]20
[6249a88f]21#include <config.h>
[b094191]22
[49bc81e]23#ifdef HAVE_KERBEROS_IV
24#include <kerberosIV/des.h>
25#else
26#include <openssl/des.h>
27#endif
28
[8bd190d]29#include "filterproc.h"
30
[5175cf8]31#ifndef OWL_VERSION_STRING
32#ifdef  GIT_VERSION
33#define stringify(x)       __stringify(x)
34#define __stringify(x)     #x
35#define OWL_VERSION_STRING stringify(GIT_VERSION)
36#else
37#define OWL_VERSION_STRING PACKAGE_VERSION
38#endif
39#endif /* !OWL_VERSION_STRING */
40
[6829afc]41/* Annotate functions in which the caller owns the return value and is
42 * responsible for ensuring it is freed. */
43#define CALLER_OWN G_GNUC_WARN_UNUSED_RESULT
44
[8bd190d]45#define MAX_KEY      128
46#define MAX_LINE     128
47#define MAX_RESULT   4096
[edae037]48
49#ifndef TRUE
50#define TRUE -1
51#endif
52#ifndef FALSE
53#define FALSE 0
54#endif
55
56#define ZWRITE_OPT_NOAUTH     (1<<0)
57#define ZWRITE_OPT_SIGNATURE  (1<<1)
58#define ZWRITE_OPT_IGNOREVARS (1<<2)
59#define ZWRITE_OPT_VERBOSE    (1<<3)
60#define ZWRITE_OPT_QUIET      (1<<4)
61#define ZCRYPT_OPT_MESSAGE    (1<<5)
62#define ZCRYPT_OPT_IGNOREDOT  (1<<6)
63
64typedef struct
65{
66  int flags;
[1dd285b]67  const char *signature;
[edae037]68  char *message;
69} ZWRITEOPTIONS;
70
[6829afc]71CALLER_OWN char *GetZephyrVarKeyFile(const char *whoami, const char *class, const char *instance);
[e832a52]72int ParseCryptSpec(const char *spec, const char **keyfile);
[6829afc]73CALLER_OWN char *BuildArgString(char **argv, int start, int end);
74CALLER_OWN char *read_keystring(const char *keyfile);
[8bd190d]75
[e832a52]76int do_encrypt(int zephyr, const char *class, const char *instance,
77               ZWRITEOPTIONS *zoptions, const char* keyfile, int cipher);
78int do_encrypt_des(const char *keyfile, const char *in, int len, FILE *out);
79int do_encrypt_aes(const char *keyfile, const char *in, int len, FILE *out);
[8bd190d]80
[e832a52]81int do_decrypt(const char *keyfile, int cipher);
82int do_decrypt_aes(const char *keyfile);
83int do_decrypt_des(const char *keyfile);
[8bd190d]84
[edae037]85
86#define M_NONE            0
87#define M_ZEPHYR_ENCRYPT  1
88#define M_DECRYPT         2
89#define M_ENCRYPT         3
90#define M_RANDOMIZE       4
91#define M_SETKEY          5
92
[6d7f2a8]93enum cipher_algo {
94  CIPHER_DES,
95  CIPHER_AES,
96  NCIPHER
97};
98
99typedef struct {
[e832a52]100  int (*encrypt)(const char *keyfile, const char *in, int len, FILE *out);
101  int (*decrypt)(const char *keyfile);
[6d7f2a8]102} cipher_pair;
103
104cipher_pair ciphers[NCIPHER] = {
[3c2c7fc]105  [CIPHER_DES] = { do_encrypt_des, do_decrypt_des},
106  [CIPHER_AES] = { do_encrypt_aes, do_decrypt_aes},
[6d7f2a8]107};
[9a4077c]108
[c836519]109static void owl_zcrypt_string_to_schedule(char *keystring, des_key_schedule *schedule) {
[356465e]110#ifdef HAVE_KERBEROS_IV
111  des_cblock key;
112#else
113  des_cblock _key, *key = &_key;
114#endif
115
116  des_string_to_key(keystring, key);
[c836519]117  des_key_sched(key, *schedule);
[356465e]118}
119
[8f335a8]120void usage(FILE *file, const char *progname)
121{
122  fprintf(file, "Usage: %s [-Z|-D|-E|-R|-S] [-F Keyfile] [-c class] [-i instance]\n", progname);
123  fprintf(file, "       [-advqtluon] [-s signature] [-f arg] [-m message]\n");
124  fprintf(file, "  One or more of class, instance, and keyfile must be specified.\n");
125}
126
[356465e]127int main(int argc, char *argv[])
[edae037]128{
[9a4077c]129  char *cryptspec = NULL;
[e832a52]130  const char *keyfile;
[9a4077c]131  int cipher;
[edae037]132  int error = FALSE;
133  int zephyr = FALSE;
[1dd285b]134  const char *class = NULL, *instance = NULL;
[edae037]135  int mode = M_NONE;
136
[478dc8e]137  int c;
[edae037]138
139  int messageflag = FALSE;
140  ZWRITEOPTIONS zoptions;
141  zoptions.flags = 0;
142
[5175cf8]143  enum {
144    OPT_VERSION = CHAR_MAX + 1,
[8f335a8]145    OPT_HELP,
[5175cf8]146  };
[478dc8e]147  static const struct option options[] = {
[5175cf8]148    {"version", no_argument, NULL, OPT_VERSION},
[8f335a8]149    {"help", no_argument, NULL, OPT_HELP},
[478dc8e]150    {NULL, 0, NULL, 0}
151  };
152
153  while ((c = getopt_long(argc, argv, "ZDERSF:c:i:advqtluons:f:m", options, NULL)) != -1)
[edae037]154  {
155    switch(c)
156    {
[5175cf8]157      case OPT_VERSION:
158        /* Version */
159        printf("This is zcrypt version %s\n", OWL_VERSION_STRING);
160        exit(0);
[8f335a8]161      case OPT_HELP:
162        /* Help */
163        usage(stdout, argv[0]);
164        exit(0);
[edae037]165      case 'Z':
166        /* Zephyr encrypt */
167        mode = M_ZEPHYR_ENCRYPT;
[f7f35c0]168        break;
[edae037]169      case 'D':
170        /* Decrypt */
[f7f35c0]171        mode = M_DECRYPT;
172        break;
[edae037]173      case 'E':
[f7f35c0]174        /* Encrypt */
175        mode = M_ENCRYPT;
176        break;
[edae037]177      case 'R':
[f7f35c0]178        /* Randomize the keyfile */
179        mode = M_RANDOMIZE;
180        break;
[edae037]181      case 'S':
[f7f35c0]182        /* Set a new key value from stdin */
183        mode = M_SETKEY;
184        break;
[edae037]185      case 'F':
[f7f35c0]186        /* Specify the keyfile explicitly */
[9a4077c]187        if (cryptspec != NULL) error = TRUE;
188        cryptspec = optarg;
[f7f35c0]189        break;
[edae037]190      case 'c':
[f7f35c0]191        /* Zwrite/zcrypt: class name */
192        if (class != NULL) error = TRUE;
193        class = optarg;
194        break;
[edae037]195      case 'i':
[f7f35c0]196        /* Zwrite/zcrypt: instance name */
197        if (instance != NULL) error = TRUE;
198        instance = optarg;
199        break;
[edae037]200      case 'a':
[f7f35c0]201        /* Zwrite: authenticate (default) */
202        zoptions.flags &= ~ZWRITE_OPT_NOAUTH;
203        break;
[edae037]204      case 'd':
[f7f35c0]205        /* Zwrite: do not authenticate */
206        zoptions.flags |= ZWRITE_OPT_NOAUTH;
207        break;
[edae037]208      case 'v':
[f7f35c0]209        /* Zwrite: verbose */
210        zoptions.flags |= ZWRITE_OPT_VERBOSE;
211        break;
[edae037]212      case 'q':
[f7f35c0]213        /* Zwrite: quiet */
214        zoptions.flags |= ZWRITE_OPT_QUIET;
215        break;
[edae037]216      case 't':
[f7f35c0]217        /* Zwrite: no expand tabs (ignored) */
218        break;
[edae037]219      case 'l':
[f7f35c0]220        /* Zwrite: ignore '.' on a line by itself (ignored) */
221        zoptions.flags |= ZCRYPT_OPT_IGNOREDOT;
222        break;
[edae037]223      case 'u':
[f7f35c0]224        /* Zwrite: urgent message */
225        instance = "URGENT";
226        break;
[edae037]227      case 'o':
[f7f35c0]228        /* Zwrite: ignore zephyr variables zwrite-class, zwrite-inst, */
229        /*         zwrite-opcode */
230        zoptions.flags |= ZWRITE_OPT_IGNOREVARS;
231        break;
[edae037]232      case 'n':
[f7f35c0]233        /* Zwrite: prevent PING message (always used) */
234        break;
[edae037]235      case 's':
[f7f35c0]236        /* Zwrite: signature */
237        zoptions.flags |= ZWRITE_OPT_SIGNATURE;
238        zoptions.signature = optarg;
239        break;
[edae037]240      case 'f':
[f7f35c0]241        /* Zwrite: file system specification (ignored) */
242        break;
[edae037]243      case 'm':
[f7f35c0]244        /* Message on rest of line*/
245        messageflag = TRUE;
246        break;
[edae037]247      case '?':
[f7f35c0]248        error = TRUE;
249        break;
[edae037]250    }
251    if (error || messageflag)
252      break;
253  }
254
255  if (class != NULL || instance != NULL)
256    zephyr = TRUE;
257
258  if (messageflag)
259  {
260    zoptions.flags |= ZCRYPT_OPT_MESSAGE;
261    zoptions.message = BuildArgString(argv, optind, argc);
262    if (!zoptions.message)
263    {
[a08bfc3]264      fprintf(stderr, "Memory allocation error.\n");
[edae037]265      error = TRUE;
266    }
267  }
268  else if (optind < argc)
269  {
270    error = TRUE;
271  }
272
273  if (mode == M_NONE)
274    mode = (zephyr?M_ZEPHYR_ENCRYPT:M_ENCRYPT);
275
276  if (mode == M_ZEPHYR_ENCRYPT && !zephyr)
277    error = TRUE;
278
[9a4077c]279  if (!error && cryptspec == NULL && (class != NULL || instance != NULL)) {
280    cryptspec = GetZephyrVarKeyFile(argv[0], class, instance);
281    if(!cryptspec) {
282      fprintf(stderr, "Unable to find keyfile for ");
283      if(class != NULL) {
284        fprintf(stderr, "-c %s ", class);
285      }
286      if(instance != NULL) {
287        fprintf(stderr, "-i %s ", instance);
288      }
289      fprintf(stderr, "\n");
290      exit(-1);
291    }
292  }
293
[7ba7d66]294  if (error || !cryptspec)
[edae037]295  {
[8f335a8]296    usage(stderr, argv[0]);
[4133e34]297    exit(1);
298  }
[9a4077c]299
300  cipher = ParseCryptSpec(cryptspec, &keyfile);
301  if(cipher < 0) {
302    fprintf(stderr, "Invalid cipher specification: %s\n", cryptspec);
[4133e34]303    exit(1);
[edae037]304  }
[9a4077c]305
306
307  if (mode == M_RANDOMIZE)
[edae037]308  {
[9a4077c]309    /* Choose a new, random key */
310    /*
[edae037]311      FILE *fkey = fopen(fname, "w");
312      if (!fkey)
[9a4077c]313      printf("Could not open key file for writing: %s\n", fname);
[edae037]314      else
315      {
[9a4077c]316      char string[100];
317      fputs(fkey, string);
318      fclose(fkey);
[356465e]319      }
[9a4077c]320    */
321    fprintf(stderr, "Feature not yet implemented.\n");
322  }
323  else if (mode == M_SETKEY)
324  {
325    /* Set a new, user-entered key */
326    char newkey[MAX_KEY];
327    FILE *fkey;
[edae037]328
[9a4077c]329    if (isatty(0))
330    {
331      printf("Enter new key: ");
332      /* Really should read without echo!!! */
333    }
334    if(!fgets(newkey, MAX_KEY - 1, stdin)) {
335      fprintf(stderr, "Error reading key.\n");
336      return 1;
[edae037]337    }
[9a4077c]338
339    fkey = fopen(keyfile, "w");
340    if (!fkey)
341      fprintf(stderr, "Could not open key file for writing: %s\n", keyfile);
[edae037]342    else
343    {
[9a4077c]344      if (fputs(newkey, fkey) != strlen(newkey) || putc('\n', fkey) != '\n')
345      {
346        fprintf(stderr, "Error writing to key file.\n");
347        fclose(fkey);
[4133e34]348        exit(1);
349      }
[edae037]350      else
351      {
[f7f35c0]352        fclose(fkey);
[9a4077c]353        fprintf(stderr, "Key update complete.\n");
[edae037]354      }
355    }
356  }
[9a4077c]357  else
358  {
359    if (mode == M_ZEPHYR_ENCRYPT || mode == M_ENCRYPT)
[8bd190d]360      error = !do_encrypt((mode == M_ZEPHYR_ENCRYPT), class, instance,
361                          &zoptions, keyfile, cipher);
[9a4077c]362    else
[8bd190d]363      error = !do_decrypt(keyfile, cipher);
[9a4077c]364  }
[edae037]365
366  /* Always print the **END** message if -D is specified. */
367  if (mode == M_DECRYPT)
368    printf("**END**\n");
[8bd190d]369
370  return error;
[edae037]371}
372
[e832a52]373int ParseCryptSpec(const char *spec, const char **keyfile) {
[8bd190d]374  int cipher = CIPHER_DES;
375  char *cipher_name = strdup(spec);
376  char *colon = strchr(cipher_name, ':');
377
[9a4077c]378  *keyfile = spec;
[8bd190d]379
380  if (colon) {
381    char *rest = strchr(spec, ':') + 1;
382    while(isspace(*rest)) rest++;
383
384    *colon-- = '\0';
385    while (colon >= cipher_name && isspace(*colon)) {
386      *colon = '\0';
387    }
388
389    if(strcmp(cipher_name, "AES") == 0) {
390      cipher = CIPHER_AES;
391      *keyfile = rest;
392    } else if(strcmp(cipher_name, "DES") == 0) {
393      cipher = CIPHER_DES;
394      *keyfile = rest;
395    }
396  }
397
398  free(cipher_name);
399
400  return cipher;
[9a4077c]401}
402
[edae037]403/* Build a space-separated string from argv from elements between start  *
404 * and end - 1.  malloc()'s the returned string. */
[6829afc]405CALLER_OWN char *BuildArgString(char **argv, int start, int end)
[edae037]406{
407  int len = 1;
408  int i;
409  char *result;
410
411  /* Compute the length of the string.  (Plus 1 or 2) */
412  for (i = start; i < end; i++)
413    len += strlen(argv[i]) + 1;
414
415  /* Allocate memory */
416  result = (char *)malloc(len);
417  if (result)
418  {
419    /* Build the string */
420    char *ptr = result;
421    /* Start with an empty string, in case nothing is copied. */
422    *ptr = '\0';
423    /* Copy the arguments */
424    for (i = start; i < end; i++)
425    {
426      char *temp = argv[i];
427      /* Add a space, if not the first argument */
428      if (i != start)
[f7f35c0]429        *ptr++ = ' ';
[edae037]430      /* Copy argv[i], leaving ptr pointing to the '\0' copied from temp */
[356465e]431      while ((*ptr = *temp++))
[f7f35c0]432        ptr++;
[edae037]433    }
434  }
435
436  return result;
437}
438
439#define MAX_BUFF 258
440#define MAX_SEARCH 3
441/* Find the class/instance in the .crypt-table */
[6829afc]442CALLER_OWN char *GetZephyrVarKeyFile(const char *whoami, const char *class, const char *instance)
[edae037]443{
[356465e]444  char *keyfile = NULL;
[6b1c3b6]445  char *varname[MAX_SEARCH];
[edae037]446  int length[MAX_SEARCH], i;
447  char buffer[MAX_BUFF];
[c6332f5]448  const char *home;
[6b1c3b6]449  char *filename;
[edae037]450  char result[MAX_SEARCH][MAX_BUFF];
451  int numsearch = 0;
452  FILE *fsearch;
453
[6b1c3b6]454  memset(varname, 0, sizeof(varname));
455
[edae037]456  /* Determine names to look for in .crypt-table */
457  if (instance)
[6b1c3b6]458    varname[numsearch++] = g_strdup_printf("crypt-%s-%s:", (class?class:"message"), instance);
[edae037]459  if (class)
[6b1c3b6]460    varname[numsearch++] = g_strdup_printf("crypt-%s:", class);
461  varname[numsearch++] = g_strdup("crypt-default:");
[edae037]462
463  /* Setup the result array, and determine string lengths */
464  for (i = 0; i < numsearch; i++)
465  {
466    result[i][0] = '\0';
467    length[i] = strlen(varname[i]);
468  }
469
470  /* Open~/.crypt-table */
[c6332f5]471  home = getenv("HOME");
472  if (home == NULL)
473    home = g_get_home_dir();
[dde1b4d]474  filename = g_build_filename(home, ".crypt-table", NULL);
[edae037]475  fsearch = fopen(filename, "r");
476  if (fsearch)
477  {
478    /* Scan file for a match */
479    while (!feof(fsearch))
480    {
[356465e]481      if (!fgets(buffer, MAX_BUFF - 3, fsearch)) break;
[edae037]482      for (i = 0; i < numsearch; i++)
[f7f35c0]483        if (strncasecmp(varname[i], buffer, length[i]) == 0)
484        {
485          int j;
486          for (j = length[i]; buffer[j] == ' '; j++)
487            ;
488          strcpy(result[i], &buffer[j]);
489          if (*result[i])
490            if (result[i][strlen(result[i])-1] == '\n')
491              result[i][strlen(result[i])-1] = '\0';
492        }
[edae037]493    }
494
495    /* Pick the "best" match found */
496    keyfile = NULL;
497    for (i = 0; i < numsearch; i++)
498      if (*result[i])
499      {
[f7f35c0]500        keyfile = result[i];
501        break;
[edae037]502      }
503
[9a4077c]504    if (keyfile != NULL)
[edae037]505    {
506      /* Prepare result to be returned */
507      char *temp = keyfile;
508      keyfile = (char *)malloc(strlen(temp) + 1);
509      if (keyfile)
[f7f35c0]510        strcpy(keyfile, temp);
[edae037]511      else
[f7f35c0]512        fprintf(stderr, "Memory allocation error.\n");
[edae037]513    }
514    fclose(fsearch);
515  }
516  else
[a08bfc3]517    fprintf(stderr, "Could not open key table file: %s\n", filename);
[edae037]518
[6b1c3b6]519  for(i = 0; i < MAX_SEARCH; i++) {
[3b8a563]520    g_free(varname[i]);
[6b1c3b6]521  }
522
[3b8a563]523  g_free(filename);
[6b1c3b6]524
[edae037]525  return keyfile;
526}
527
528static pid_t zephyrpipe_pid = 0;
529
530/* Open a pipe to zwrite */
[e832a52]531FILE *GetZephyrPipe(const char *class, const char *instance, const ZWRITEOPTIONS *zoptions)
[edae037]532{
533  int fildes[2];
534  pid_t pid;
535  FILE *result;
[e832a52]536  const char *argv[20];
[356465e]537  int argc = 0;
[edae037]538
539  if (pipe(fildes) < 0)
540    return NULL;
541  pid = fork();
542
543  if (pid < 0)
544  {
545    /* Error: clean up */
546    close(fildes[0]);
547    close(fildes[1]);
548    result = NULL;
549  }
550  else if (pid == 0)
551  {
552    /* Setup child process */
553    argv[argc++] = "zwrite";
554    argv[argc++] = "-n";     /* Always send without ping */
555    if (class)
556    {
557      argv[argc++] = "-c";
558      argv[argc++] = class;
559    }
560    if (instance)
561    {
562      argv[argc++] = "-i";
563      argv[argc++] = instance;
564    }
565    if (zoptions->flags & ZWRITE_OPT_NOAUTH)
566      argv[argc++] = "-d";
567    if (zoptions->flags & ZWRITE_OPT_QUIET)
568      argv[argc++] = "-q";
569    if (zoptions->flags & ZWRITE_OPT_VERBOSE)
570      argv[argc++] = "-v";
571    if (zoptions->flags & ZWRITE_OPT_SIGNATURE)
572    {
573      argv[argc++] = "-s";
574      argv[argc++] = zoptions->signature;
575    }
576    argv[argc++] = "-O";
577    argv[argc++] = "crypt";
578    argv[argc] = NULL;
579    close(fildes[1]);
580    if (fildes[0] != STDIN_FILENO)
581    {
582      if (dup2(fildes[0], STDIN_FILENO) != STDIN_FILENO)
[f7f35c0]583        exit(0);
[edae037]584      close(fildes[0]);
585    }
586    close(fildes[0]);
[e832a52]587    execvp(argv[0], (char **)argv);
[a08bfc3]588    fprintf(stderr, "Exec error: could not run zwrite\n");
[edae037]589    exit(0);
590  }
591  else
592  {
593    close(fildes[0]);
594    /* Create a FILE * for the zwrite pipe */
595    result = (FILE *)fdopen(fildes[1], "w");
596    zephyrpipe_pid = pid;
597  }
598
599  return result;
600}
601
602/* Close the pipe to zwrite */
[356465e]603void CloseZephyrPipe(FILE *pipe)
[edae037]604{
605  fclose(pipe);
606  waitpid(zephyrpipe_pid, NULL, 0);
607  zephyrpipe_pid = 0;
608}
609
610#define BASE_CODE 70
611#define LAST_CODE (BASE_CODE + 15)
612#define OUTPUT_BLOCK_SIZE 16
613
[356465e]614void block_to_ascii(unsigned char *output, FILE *outfile)
[edae037]615{
616  int i;
617  for (i = 0; i < 8; i++)
618  {
619    putc(((output[i] & 0xf0) >> 4) + BASE_CODE, outfile);
620    putc( (output[i] & 0x0f)       + BASE_CODE, outfile);
621  }
622}
623
[6829afc]624CALLER_OWN char *slurp_stdin(int ignoredot, int *length) {
[9a4077c]625  char *buf;
626  char *inptr;
[edae037]627
[8bd190d]628  if ((inptr = buf = (char *)malloc(MAX_RESULT)) == NULL)
629  {
630    fprintf(stderr, "Memory allocation error\n");
631    return NULL;
632  }
633  while (inptr - buf < MAX_RESULT - MAX_LINE - 20)
634  {
635    if (fgets(inptr, MAX_LINE, stdin) == NULL)
636      break;
637
638    if (inptr[0])
639    {
640      if (inptr[0] == '.' && inptr[1] == '\n' && !ignoredot)
641      {
642        inptr[0] = '\0';
643        break;
644      }
645      else
646        inptr += strlen(inptr);
647    }
648    else
649      break;
650  }
651  *length = inptr - buf;
652
653  return buf;
654}
655
[6829afc]656CALLER_OWN char *GetInputBuffer(ZWRITEOPTIONS *zoptions, int *length) {
[8bd190d]657  char *buf;
658
[9a4077c]659  if (zoptions->flags & ZCRYPT_OPT_MESSAGE)
[edae037]660  {
[9a4077c]661    /* Use the -m message */
662    buf = strdup(zoptions->message);
663    *length = strlen(buf);
664  }
665  else
666  {
667    if (isatty(0)) {
[edae037]668      /* tty input, so show the "Type your message now..." message */
669      if (zoptions->flags & ZCRYPT_OPT_IGNOREDOT)
[f7f35c0]670        printf("Type your message now.  End with the end-of-file character.\n");
[edae037]671      else
[f7f35c0]672        printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
[9a4077c]673    } else {
674      zoptions->flags |= ZCRYPT_OPT_IGNOREDOT;
675    }
676
[8bd190d]677    buf = slurp_stdin(zoptions->flags & ZCRYPT_OPT_IGNOREDOT, length);
[9a4077c]678  }
679  return buf;
680}
681
[6829afc]682CALLER_OWN char *read_keystring(const char *keyfile) {
[9a4077c]683  char *keystring;
684  FILE *fkey = fopen(keyfile, "r");
685  if(!fkey) {
686    fprintf(stderr, "Unable to open keyfile %s\n", keyfile);
687    return NULL;
688  }
689  keystring = malloc(MAX_KEY);
690  if(!fgets(keystring, MAX_KEY-1, fkey)) {
691    fprintf(stderr, "Unable to read from keyfile: %s\n", keyfile);
692    free(keystring);
693    keystring = NULL;
694  }
695  fclose(fkey);
696  return keystring;
697}
698
699/* Encrypt stdin, with prompt if isatty, and send to stdout, or to zwrite
700   if zephyr is set. */
[e832a52]701int do_encrypt(int zephyr, const char *class, const char *instance,
702               ZWRITEOPTIONS *zoptions, const char *keyfile, int cipher)
[9a4077c]703{
704  FILE *outfile = stdout;
705  char *inbuff = NULL;
706  int buflen;
707  int out = TRUE;
708
709  inbuff = GetInputBuffer(zoptions, &buflen);
710
711  if(!inbuff) {
712    fprintf(stderr, "Error reading zcrypt input!\n");
713    return FALSE;
714  }
[edae037]715
[9a4077c]716  if (zephyr) {
[edae037]717    outfile = GetZephyrPipe(class, instance, zoptions);
718    if (!outfile)
719    {
[a08bfc3]720      fprintf(stderr, "Could not run zwrite\n");
[9a4077c]721      if (inbuff)
[f7f35c0]722        free(inbuff);
[edae037]723      return FALSE;
724    }
725  }
726
[6d7f2a8]727  out = ciphers[cipher].encrypt(keyfile, inbuff, buflen, outfile);
[9a4077c]728
729  if (zephyr)
730    CloseZephyrPipe(outfile);
731
732  free(inbuff);
733  return out;
734}
735
[e832a52]736int do_encrypt_des(const char *keyfile, const char *in, int length, FILE *outfile)
[9a4077c]737{
738  des_key_schedule schedule;
739  unsigned char input[8], output[8];
[e832a52]740  const char *inptr;
[9a4077c]741  int num_blocks, last_block_size;
742  char *keystring;
743  int size;
744
745  keystring = read_keystring(keyfile);
746  if(!keystring) {
747    return FALSE;
748  }
749
[c836519]750  owl_zcrypt_string_to_schedule(keystring, &schedule);
[9a4077c]751  free(keystring);
752
753  inptr = in;
754  num_blocks = (length + 7) / 8;
755  last_block_size = ((length + 7) % 8) + 1;
[edae037]756
757  /* Encrypt the input (inbuff or stdin) and send it to outfile */
758  while (TRUE)
759  {
[9a4077c]760    /* Get 8 bytes from buffer */
761    if (num_blocks > 1)
[edae037]762    {
[9a4077c]763      size = 8;
764      memcpy(input, inptr, size);
765      inptr += 8;
766      num_blocks--;
767    }
768    else if (num_blocks == 1)
769    {
770      size = last_block_size;
771      memcpy(input, inptr, size);
772      num_blocks--;
[edae037]773    }
774    else
[9a4077c]775      size = 0;
[edae037]776
777    /* Check for EOF and pad the string to 8 chars, if needed */
778    if (size == 0)
[9a4077c]779      break;
[edae037]780    if (size < 8)
781      memset(input + size, 0, 8 - size);
782
783    /* Encrypt and output the block */
[356465e]784    des_ecb_encrypt(&input, &output, schedule, TRUE);
[edae037]785    block_to_ascii(output, outfile);
786
787    if (size < 8)
788      break;
789  }
790
[9a4077c]791  putc('\n', outfile);
[edae037]792
[9a4077c]793  return TRUE;
[edae037]794}
795
[e832a52]796int do_encrypt_aes(const char *keyfile, const char *in, int length, FILE *outfile)
[8bd190d]797{
798  char *out;
799  int err, status;
800  const char *argv[] = {
801    "gpg",
802    "--symmetric",
[048b1ff]803    "--no-options",
804    "--no-default-keyring",
805    "--keyring", "/dev/null",
806    "--secret-keyring", "/dev/null",
[8bd190d]807    "--batch",
808    "--quiet",
809    "--no-use-agent",
810    "--armor",
811    "--cipher-algo", "AES",
812    "--passphrase-file", keyfile,
813    NULL
814  };
[97cdbaf5]815  err = call_filter(argv, in, &out, &status);
[8bd190d]816  if(err || status) {
[3b8a563]817    g_free(out);
[8bd190d]818    return FALSE;
819  }
820  fwrite(out, strlen(out), 1, outfile);
821  g_free(out);
822  return TRUE;
823}
824
[edae037]825/* Read a half-byte from stdin, skipping invalid characters.  Returns -1
826   if at EOF or file error */
[356465e]827int read_ascii_nybble(void)
[edae037]828{
829  char c;
830
831  while (TRUE)
832  {
833    if (fread(&c, 1, 1, stdin) == 0)
834      return -1;
835    else if (c >= BASE_CODE && c <= LAST_CODE)
836      return c - BASE_CODE;
837  }
838}
839
840/* Read both halves of the byte and return the single byte.  Returns -1
841   if at EOF or file error. */
[356465e]842int read_ascii_byte(void)
[edae037]843{
844  int c1, c2;
845  c1 = read_ascii_nybble();
846  if (c1 >= 0)
847  {
848    c2 = read_ascii_nybble();
849    if (c2 >= 0)
850    {
851      return c1 * 0x10 + c2;
852    }
853  }
854  return -1;
855}
856
857/* Read an 8-byte DES block from stdin */
[356465e]858int read_ascii_block(unsigned char *input)
[edae037]859{
860  int c;
861
862  int i;
863  for (i = 0; i < 8; i++)
864  {
865    c = read_ascii_byte();
866    if (c < 0)
867      return FALSE;
868
869    input[i] = c;
870  }
871
872  return TRUE;
873}
874
875/* Decrypt stdin */
[e832a52]876int do_decrypt(const char *keyfile, int cipher)
[edae037]877{
[6d7f2a8]878  return ciphers[cipher].decrypt(keyfile);
[8bd190d]879}
880
[e832a52]881int do_decrypt_aes(const char *keyfile) {
[8bd190d]882  char *in, *out;
883  int length;
884  const char *argv[] = {
885    "gpg",
886    "--decrypt",
[048b1ff]887    "--no-options",
888    "--no-default-keyring",
889    "--keyring", "/dev/null",
890    "--secret-keyring", "/dev/null",
[8bd190d]891    "--batch",
892    "--no-use-agent",
893    "--quiet",
894    "--passphrase-file", keyfile,
895    NULL
896  };
897  int err, status;
898
899  in = slurp_stdin(TRUE, &length);
900  if(!in) return FALSE;
901
[97cdbaf5]902  err = call_filter(argv, in, &out, &status);
[d72ba1e]903  free(in);
[8bd190d]904  if(err || status) {
[3b8a563]905    g_free(out);
[8bd190d]906    return FALSE;
907  }
908  fwrite(out, strlen(out), 1, stdout);
909  g_free(out);
910
911  return TRUE;
912}
913
[e832a52]914int do_decrypt_des(const char *keyfile) {
[edae037]915  des_key_schedule schedule;
[356465e]916  unsigned char input[8], output[8];
[60fcd71]917  char tmp[9];
[8bd190d]918  char *keystring;
[edae037]919
[60fcd71]920  /*
921    DES decrypts 8 bytes at a time. We copy those over into the 9-byte
922    'tmp', which has the final byte zeroed, to ensure that we always
923    have a NULL-terminated string we can call printf/strlen on.
924
925    We don't pass 'tmp' to des_ecb_encrypt directly, because it's
926    prototyped as taking 'unsigned char[8]', and this avoids a stupid
927    cast.
928
929    We zero 'tmp' entirely, not just the final byte, in case there are
930    no input blocks.
931  */
932  memset(tmp, 0, sizeof tmp);
[edae037]933
[8bd190d]934  keystring = read_keystring(keyfile);
935  if(!keystring) return FALSE;
936
[c836519]937  owl_zcrypt_string_to_schedule(keystring, &schedule);
[edae037]938
[8bd190d]939  free(keystring);
940
[edae037]941  while (read_ascii_block(input))
942  {
[356465e]943    des_ecb_encrypt(&input, &output, schedule, FALSE);
[60fcd71]944    memcpy(tmp, output, 8);
945    printf("%s", tmp);
[edae037]946  }
947
[60fcd71]948  if (!tmp[0] || tmp[strlen(tmp) - 1] != '\n')
[edae037]949      printf("\n");
[9a4077c]950  return TRUE;
[edae037]951}
Note: See TracBrowser for help on using the repository browser.