source: zcrypt.c @ 5175cf8

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