source: zcrypt.c @ 8a213ca

release-1.10
Last change on this file since 8a213ca 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
Line 
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>
10
11#include <unistd.h>
12#include <sys/types.h>
13#include <glib.h>
14#include <string.h>
15#include <stdlib.h>
16#include <sys/wait.h>
17#include <ctype.h>
18#include <limits.h>
19#include <getopt.h>
20
21#include <config.h>
22
23#ifdef HAVE_KERBEROS_IV
24#include <kerberosIV/des.h>
25#else
26#include <openssl/des.h>
27#endif
28
29#include "filterproc.h"
30
31extern const char *version;
32
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
37#define MAX_KEY      128
38#define MAX_LINE     128
39#define MAX_RESULT   4096
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;
59  const char *signature;
60  char *message;
61} ZWRITEOPTIONS;
62
63CALLER_OWN char *GetZephyrVarKeyFile(const char *whoami, const char *class, const char *instance);
64int ParseCryptSpec(const char *spec, const char **keyfile);
65CALLER_OWN char *BuildArgString(char **argv, int start, int end);
66CALLER_OWN char *read_keystring(const char *keyfile);
67
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);
72
73int do_decrypt(const char *keyfile, int cipher);
74int do_decrypt_aes(const char *keyfile);
75int do_decrypt_des(const char *keyfile);
76
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
85enum cipher_algo {
86  CIPHER_DES,
87  CIPHER_AES,
88  NCIPHER
89};
90
91typedef struct {
92  int (*encrypt)(const char *keyfile, const char *in, int len, FILE *out);
93  int (*decrypt)(const char *keyfile);
94} cipher_pair;
95
96cipher_pair ciphers[NCIPHER] = {
97  [CIPHER_DES] = { do_encrypt_des, do_decrypt_des},
98  [CIPHER_AES] = { do_encrypt_aes, do_decrypt_aes},
99};
100
101static void owl_zcrypt_string_to_schedule(char *keystring, des_key_schedule *schedule) {
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);
109  des_key_sched(key, *schedule);
110}
111
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
119int main(int argc, char *argv[])
120{
121  char *cryptspec = NULL;
122  const char *keyfile;
123  int cipher;
124  int error = FALSE;
125  int zephyr = FALSE;
126  const char *class = NULL, *instance = NULL;
127  int mode = M_NONE;
128
129  int c;
130
131  int messageflag = FALSE;
132  ZWRITEOPTIONS zoptions;
133  zoptions.flags = 0;
134
135  enum {
136    OPT_VERSION = CHAR_MAX + 1,
137    OPT_HELP,
138  };
139  static const struct option options[] = {
140    {"version", no_argument, NULL, OPT_VERSION},
141    {"help", no_argument, NULL, OPT_HELP},
142    {NULL, 0, NULL, 0}
143  };
144
145  while ((c = getopt_long(argc, argv, "ZDERSF:c:i:advqtluons:f:m", options, NULL)) != -1)
146  {
147    switch(c)
148    {
149      case OPT_VERSION:
150        /* Version */
151        printf("This is zcrypt version %s\n", version);
152        exit(0);
153      case OPT_HELP:
154        /* Help */
155        usage(stdout, argv[0]);
156        exit(0);
157      case 'Z':
158        /* Zephyr encrypt */
159        mode = M_ZEPHYR_ENCRYPT;
160        break;
161      case 'D':
162        /* Decrypt */
163        mode = M_DECRYPT;
164        break;
165      case 'E':
166        /* Encrypt */
167        mode = M_ENCRYPT;
168        break;
169      case 'R':
170        /* Randomize the keyfile */
171        mode = M_RANDOMIZE;
172        break;
173      case 'S':
174        /* Set a new key value from stdin */
175        mode = M_SETKEY;
176        break;
177      case 'F':
178        /* Specify the keyfile explicitly */
179        if (cryptspec != NULL) error = TRUE;
180        cryptspec = optarg;
181        break;
182      case 'c':
183        /* Zwrite/zcrypt: class name */
184        if (class != NULL) error = TRUE;
185        class = optarg;
186        break;
187      case 'i':
188        /* Zwrite/zcrypt: instance name */
189        if (instance != NULL) error = TRUE;
190        instance = optarg;
191        break;
192      case 'a':
193        /* Zwrite: authenticate (default) */
194        zoptions.flags &= ~ZWRITE_OPT_NOAUTH;
195        break;
196      case 'd':
197        /* Zwrite: do not authenticate */
198        zoptions.flags |= ZWRITE_OPT_NOAUTH;
199        break;
200      case 'v':
201        /* Zwrite: verbose */
202        zoptions.flags |= ZWRITE_OPT_VERBOSE;
203        break;
204      case 'q':
205        /* Zwrite: quiet */
206        zoptions.flags |= ZWRITE_OPT_QUIET;
207        break;
208      case 't':
209        /* Zwrite: no expand tabs (ignored) */
210        break;
211      case 'l':
212        /* Zwrite: ignore '.' on a line by itself (ignored) */
213        zoptions.flags |= ZCRYPT_OPT_IGNOREDOT;
214        break;
215      case 'u':
216        /* Zwrite: urgent message */
217        instance = "URGENT";
218        break;
219      case 'o':
220        /* Zwrite: ignore zephyr variables zwrite-class, zwrite-inst, */
221        /*         zwrite-opcode */
222        zoptions.flags |= ZWRITE_OPT_IGNOREVARS;
223        break;
224      case 'n':
225        /* Zwrite: prevent PING message (always used) */
226        break;
227      case 's':
228        /* Zwrite: signature */
229        zoptions.flags |= ZWRITE_OPT_SIGNATURE;
230        zoptions.signature = optarg;
231        break;
232      case 'f':
233        /* Zwrite: file system specification (ignored) */
234        break;
235      case 'm':
236        /* Message on rest of line*/
237        messageflag = TRUE;
238        break;
239      case '?':
240        error = TRUE;
241        break;
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    {
256      fprintf(stderr, "Memory allocation error.\n");
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
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
286  if (error || !cryptspec)
287  {
288    usage(stderr, argv[0]);
289    exit(1);
290  }
291
292  cipher = ParseCryptSpec(cryptspec, &keyfile);
293  if(cipher < 0) {
294    fprintf(stderr, "Invalid cipher specification: %s\n", cryptspec);
295    exit(1);
296  }
297
298
299  if (mode == M_RANDOMIZE)
300  {
301    /* Choose a new, random key */
302    /*
303      FILE *fkey = fopen(fname, "w");
304      if (!fkey)
305      printf("Could not open key file for writing: %s\n", fname);
306      else
307      {
308      char string[100];
309      fputs(fkey, string);
310      fclose(fkey);
311      }
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;
320
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;
329    }
330
331    fkey = fopen(keyfile, "w");
332    if (!fkey)
333      fprintf(stderr, "Could not open key file for writing: %s\n", keyfile);
334    else
335    {
336      if (fputs(newkey, fkey) != strlen(newkey) || putc('\n', fkey) != '\n')
337      {
338        fprintf(stderr, "Error writing to key file.\n");
339        fclose(fkey);
340        exit(1);
341      }
342      else
343      {
344        fclose(fkey);
345        fprintf(stderr, "Key update complete.\n");
346      }
347    }
348  }
349  else
350  {
351    if (mode == M_ZEPHYR_ENCRYPT || mode == M_ENCRYPT)
352      error = !do_encrypt((mode == M_ZEPHYR_ENCRYPT), class, instance,
353                          &zoptions, keyfile, cipher);
354    else
355      error = !do_decrypt(keyfile, cipher);
356  }
357
358  /* Always print the **END** message if -D is specified. */
359  if (mode == M_DECRYPT)
360    printf("**END**\n");
361
362  return error;
363}
364
365int ParseCryptSpec(const char *spec, const char **keyfile) {
366  int cipher = CIPHER_DES;
367  char *cipher_name = strdup(spec);
368  char *colon = strchr(cipher_name, ':');
369
370  *keyfile = spec;
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;
393}
394
395/* Build a space-separated string from argv from elements between start  *
396 * and end - 1.  malloc()'s the returned string. */
397CALLER_OWN char *BuildArgString(char **argv, int start, int end)
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)
421        *ptr++ = ' ';
422      /* Copy argv[i], leaving ptr pointing to the '\0' copied from temp */
423      while ((*ptr = *temp++))
424        ptr++;
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 */
434CALLER_OWN char *GetZephyrVarKeyFile(const char *whoami, const char *class, const char *instance)
435{
436  char *keyfile = NULL;
437  char *varname[MAX_SEARCH];
438  int length[MAX_SEARCH], i;
439  char buffer[MAX_BUFF];
440  const char *home;
441  char *filename;
442  char result[MAX_SEARCH][MAX_BUFF];
443  int numsearch = 0;
444  FILE *fsearch;
445
446  memset(varname, 0, sizeof(varname));
447
448  /* Determine names to look for in .crypt-table */
449  if (instance)
450    varname[numsearch++] = g_strdup_printf("crypt-%s-%s:", (class?class:"message"), instance);
451  if (class)
452    varname[numsearch++] = g_strdup_printf("crypt-%s:", class);
453  varname[numsearch++] = g_strdup("crypt-default:");
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 */
463  home = getenv("HOME");
464  if (home == NULL)
465    home = g_get_home_dir();
466  filename = g_build_filename(home, ".crypt-table", NULL);
467  fsearch = fopen(filename, "r");
468  if (fsearch)
469  {
470    /* Scan file for a match */
471    while (!feof(fsearch))
472    {
473      if (!fgets(buffer, MAX_BUFF - 3, fsearch)) break;
474      for (i = 0; i < numsearch; i++)
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        }
485    }
486
487    /* Pick the "best" match found */
488    keyfile = NULL;
489    for (i = 0; i < numsearch; i++)
490      if (*result[i])
491      {
492        keyfile = result[i];
493        break;
494      }
495
496    if (keyfile != NULL)
497    {
498      /* Prepare result to be returned */
499      char *temp = keyfile;
500      keyfile = (char *)malloc(strlen(temp) + 1);
501      if (keyfile)
502        strcpy(keyfile, temp);
503      else
504        fprintf(stderr, "Memory allocation error.\n");
505    }
506    fclose(fsearch);
507  }
508  else
509    fprintf(stderr, "Could not open key table file: %s\n", filename);
510
511  for(i = 0; i < MAX_SEARCH; i++) {
512    g_free(varname[i]);
513  }
514
515  g_free(filename);
516
517  return keyfile;
518}
519
520static pid_t zephyrpipe_pid = 0;
521
522/* Open a pipe to zwrite */
523FILE *GetZephyrPipe(const char *class, const char *instance, const ZWRITEOPTIONS *zoptions)
524{
525  int fildes[2];
526  pid_t pid;
527  FILE *result;
528  const char *argv[20];
529  int argc = 0;
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)
575        exit(0);
576      close(fildes[0]);
577    }
578    close(fildes[0]);
579    execvp(argv[0], (char **)argv);
580    fprintf(stderr, "Exec error: could not run zwrite\n");
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 */
595void CloseZephyrPipe(FILE *pipe)
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
606void block_to_ascii(unsigned char *output, FILE *outfile)
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
616CALLER_OWN char *slurp_stdin(int ignoredot, int *length) {
617  char *buf;
618  char *inptr;
619
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
648CALLER_OWN char *GetInputBuffer(ZWRITEOPTIONS *zoptions, int *length) {
649  char *buf;
650
651  if (zoptions->flags & ZCRYPT_OPT_MESSAGE)
652  {
653    /* Use the -m message */
654    buf = strdup(zoptions->message);
655    *length = strlen(buf);
656  }
657  else
658  {
659    if (isatty(0)) {
660      /* tty input, so show the "Type your message now..." message */
661      if (zoptions->flags & ZCRYPT_OPT_IGNOREDOT)
662        printf("Type your message now.  End with the end-of-file character.\n");
663      else
664        printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
665    } else {
666      zoptions->flags |= ZCRYPT_OPT_IGNOREDOT;
667    }
668
669    buf = slurp_stdin(zoptions->flags & ZCRYPT_OPT_IGNOREDOT, length);
670  }
671  return buf;
672}
673
674CALLER_OWN char *read_keystring(const char *keyfile) {
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. */
693int do_encrypt(int zephyr, const char *class, const char *instance,
694               ZWRITEOPTIONS *zoptions, const char *keyfile, int cipher)
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  }
707
708  if (zephyr) {
709    outfile = GetZephyrPipe(class, instance, zoptions);
710    if (!outfile)
711    {
712      fprintf(stderr, "Could not run zwrite\n");
713      if (inbuff)
714        free(inbuff);
715      return FALSE;
716    }
717  }
718
719  out = ciphers[cipher].encrypt(keyfile, inbuff, buflen, outfile);
720
721  if (zephyr)
722    CloseZephyrPipe(outfile);
723
724  free(inbuff);
725  return out;
726}
727
728int do_encrypt_des(const char *keyfile, const char *in, int length, FILE *outfile)
729{
730  des_key_schedule schedule;
731  unsigned char input[8], output[8];
732  const char *inptr;
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
742  owl_zcrypt_string_to_schedule(keystring, &schedule);
743  free(keystring);
744
745  inptr = in;
746  num_blocks = (length + 7) / 8;
747  last_block_size = ((length + 7) % 8) + 1;
748
749  /* Encrypt the input (inbuff or stdin) and send it to outfile */
750  while (TRUE)
751  {
752    /* Get 8 bytes from buffer */
753    if (num_blocks > 1)
754    {
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--;
765    }
766    else
767      size = 0;
768
769    /* Check for EOF and pad the string to 8 chars, if needed */
770    if (size == 0)
771      break;
772    if (size < 8)
773      memset(input + size, 0, 8 - size);
774
775    /* Encrypt and output the block */
776    des_ecb_encrypt(&input, &output, schedule, TRUE);
777    block_to_ascii(output, outfile);
778
779    if (size < 8)
780      break;
781  }
782
783  putc('\n', outfile);
784
785  return TRUE;
786}
787
788int do_encrypt_aes(const char *keyfile, const char *in, int length, FILE *outfile)
789{
790  char *out;
791  int err, status;
792  const char *argv[] = {
793    "gpg",
794    "--symmetric",
795    "--no-options",
796    "--no-default-keyring",
797    "--keyring", "/dev/null",
798    "--secret-keyring", "/dev/null",
799    "--batch",
800    "--quiet",
801    "--no-use-agent",
802    "--armor",
803    "--cipher-algo", "AES",
804    "--passphrase-file", keyfile,
805    NULL
806  };
807  err = call_filter(argv, in, &out, &status);
808  if(err || status) {
809    g_free(out);
810    return FALSE;
811  }
812  fwrite(out, strlen(out), 1, outfile);
813  g_free(out);
814  return TRUE;
815}
816
817/* Read a half-byte from stdin, skipping invalid characters.  Returns -1
818   if at EOF or file error */
819int read_ascii_nybble(void)
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. */
834int read_ascii_byte(void)
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 */
850int read_ascii_block(unsigned char *input)
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 */
868int do_decrypt(const char *keyfile, int cipher)
869{
870  return ciphers[cipher].decrypt(keyfile);
871}
872
873int do_decrypt_aes(const char *keyfile) {
874  char *in, *out;
875  int length;
876  const char *argv[] = {
877    "gpg",
878    "--decrypt",
879    "--no-options",
880    "--no-default-keyring",
881    "--keyring", "/dev/null",
882    "--secret-keyring", "/dev/null",
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
894  err = call_filter(argv, in, &out, &status);
895  free(in);
896  if(err || status) {
897    g_free(out);
898    return FALSE;
899  }
900  fwrite(out, strlen(out), 1, stdout);
901  g_free(out);
902
903  return TRUE;
904}
905
906int do_decrypt_des(const char *keyfile) {
907  des_key_schedule schedule;
908  unsigned char input[8], output[8];
909  char tmp[9];
910  char *keystring;
911
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);
925
926  keystring = read_keystring(keyfile);
927  if(!keystring) return FALSE;
928
929  owl_zcrypt_string_to_schedule(keystring, &schedule);
930
931  free(keystring);
932
933  while (read_ascii_block(input))
934  {
935    des_ecb_encrypt(&input, &output, schedule, FALSE);
936    memcpy(tmp, output, 8);
937    printf("%s", tmp);
938  }
939
940  if (!tmp[0] || tmp[strlen(tmp) - 1] != '\n')
941      printf("\n");
942  return TRUE;
943}
Note: See TracBrowser for help on using the repository browser.