source: zcrypt.c @ ee6b30f

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