source: zcrypt.c @ b343c2c

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