1 #include "../config.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <stdarg.h>
6 #include <errno.h>
7 
8 #include "docs.h"
9 #include "sha256.h"
10 #include "chacha.h"
11 #include "optparse.h"
12 
13 int curve25519_donna(uint8_t *p, const uint8_t *s, const uint8_t *b);
14 
15 /* Global options. */
16 static char *global_pubkey = 0;
17 static char *global_seckey = 0;
18 
19 #if ENCHIVE_AGENT_DEFAULT_ENABLED
20 static int global_agent_timeout = ENCHIVE_AGENT_TIMEOUT;
21 #else
22 static int global_agent_timeout = 0;
23 #endif
24 
25 #if ENCHIVE_PINENTRY_DEFAULT_ENABLED
26 static char *pinentry_path = STR(ENCHIVE_PINENTRY_DEFAULT);
27 #else
28 static char *pinentry_path = 0;
29 #endif
30 
31 static const char enchive_suffix[] = STR(ENCHIVE_FILE_EXTENSION);
32 
33 static struct {
34     char *name;
35     FILE *file;
36 } cleanup[2];
37 
38 /**
39  * Register a file for deletion should fatal() be called.
40  */
41 static void
cleanup_register(FILE * file,char * name)42 cleanup_register(FILE *file, char *name)
43 {
44     if (file) {
45         unsigned i;
46         for (i = 0; i < sizeof(cleanup) / sizeof(*cleanup); i++) {
47             if (!cleanup[i].name) {
48                 cleanup[i].name = name;
49                 cleanup[i].file = file;
50                 return;
51             }
52         }
53     }
54     abort();
55 }
56 
57 /**
58  * Update cleanup registry to indicate FILE has been closed.
59  */
60 static void
cleanup_closed(FILE * file)61 cleanup_closed(FILE *file)
62 {
63     unsigned i;
64     for (i = 0; i < sizeof(cleanup) / sizeof(*cleanup); i++) {
65         if (file == cleanup[i].file) {
66             cleanup[i].file = 0;
67             return;
68         }
69     }
70     abort();
71 }
72 
73 /**
74  * Free resources held by the cleanup registry.
75  */
76 static void
cleanup_free(void)77 cleanup_free(void)
78 {
79     size_t i;
80     for (i = 0; i < sizeof(cleanup) / sizeof(*cleanup); i++)
81         free(cleanup[i].name);
82 }
83 
84 /**
85  * Print a message, cleanup, and exit the program with a failure code.
86  */
87 static void
fatal(const char * fmt,...)88 fatal(const char *fmt, ...)
89 {
90     unsigned i;
91     va_list ap;
92     va_start(ap, fmt);
93     fprintf(stderr, "enchive: ");
94     vfprintf(stderr, fmt, ap);
95     fputc('\n', stderr);
96     for (i = 0; i < sizeof(cleanup) / sizeof(*cleanup); i++) {
97         if (cleanup[i].file)
98             fclose(cleanup[i].file);
99         if (cleanup[i].name)
100             remove(cleanup[i].name);
101     }
102     va_end(ap);
103     exit(EXIT_FAILURE);
104 }
105 
106 /**
107  * Print a non-fatal warning message.
108  */
109 static void
warning(const char * fmt,...)110 warning(const char *fmt, ...)
111 {
112     va_list ap;
113     va_start(ap, fmt);
114     fprintf(stderr, "warning: ");
115     vfprintf(stderr, fmt, ap);
116     fputc('\n', stderr);
117     va_end(ap);
118 }
119 
120 /**
121  * Return a copy of S, which may be NULL.
122  * Abort the program if out of memory.
123  */
124 static char *
dupstr(const char * s)125 dupstr(const char *s)
126 {
127     char *copy = 0;
128     if (s) {
129         size_t len = strlen(s) + 1;
130         copy = malloc(len);
131         if (!copy)
132             fatal("out of memory");
133         memcpy(copy, s, len);
134     }
135     return copy;
136 }
137 
138 /**
139  * Concatenate N strings as a new string.
140  * Abort the program if out of memory.
141  */
142 static char *
joinstr(int n,...)143 joinstr(int n, ...)
144 {
145     int i;
146     va_list ap;
147     char *p, *str;
148     size_t len = 1;
149 
150     va_start(ap, n);
151     for (i = 0; i < n; i++) {
152         char *s = va_arg(ap, char *);
153         len += strlen(s);
154     }
155     va_end(ap);
156 
157     p = str = malloc(len);
158     if (!str)
159         fatal("out of memory");
160 
161     va_start(ap, n);
162     for (i = 0; i < n; i++) {
163         char *s = va_arg(ap, char *);
164         size_t slen = strlen(s);
165         memcpy(p, s, slen);
166         p += slen;
167     }
168     va_end(ap);
169 
170     *p = 0;
171     return str;
172 }
173 
174 /**
175  * Read the protection key from a key agent identified by its IV.
176  */
177 static int agent_read(uint8_t *key, const uint8_t *id);
178 
179 /**
180  * Serve the protection key on a key agent identified by its IV.
181  */
182 static int agent_run(const uint8_t *key, const uint8_t *id);
183 
184 #if ENCHIVE_OPTION_AGENT
185 #include <poll.h>
186 #include <unistd.h>
187 #include <sys/un.h>
188 #include <sys/stat.h>
189 #include <sys/socket.h>
190 
191 /**
192  * Fill ADDR with a unix domain socket name for the agent.
193  */
194 static int
agent_addr(struct sockaddr_un * addr,const uint8_t * iv)195 agent_addr(struct sockaddr_un *addr, const uint8_t *iv)
196 {
197     char *dir = getenv("XDG_RUNTIME_DIR");
198     if (!dir) {
199         dir = getenv("TMPDIR");
200         if (!dir)
201             dir = "/tmp";
202     }
203 
204     addr->sun_family = AF_UNIX;
205     if (strlen(dir) + 1 + 16 + 1 > sizeof(addr->sun_path)) {
206         warning("agent socket path too long -- %s", dir);
207         return 0;
208     } else {
209         sprintf(addr->sun_path, "%s/%02x%02x%02x%02x%02x%02x%02x%02x", dir,
210                 iv[0], iv[1], iv[2], iv[3], iv[4], iv[5], iv[6], iv[7]);
211         return 1;
212     }
213 }
214 
215 static int
agent_read(uint8_t * key,const uint8_t * iv)216 agent_read(uint8_t *key, const uint8_t *iv)
217 {
218     int success;
219     struct sockaddr_un addr;
220     int fd = socket(AF_UNIX, SOCK_STREAM, 0);
221     if (!agent_addr(&addr, iv)) {
222         close(fd);
223         return 0;
224     }
225     if (connect(fd, (struct sockaddr *)&addr, sizeof(addr))) {
226         close(fd);
227         return 0;
228     }
229     success = read(fd, key, 32) == 32;
230     close(fd);
231     return success;
232 }
233 
234 static int
agent_run(const uint8_t * key,const uint8_t * iv)235 agent_run(const uint8_t *key, const uint8_t *iv)
236 {
237     struct pollfd pfd = {-1, POLLIN, 0};
238     struct sockaddr_un addr;
239     pid_t pid;
240 
241     pfd.fd = socket(AF_UNIX, SOCK_STREAM, 0);
242     if (pfd.fd == -1) {
243         warning("could not create agent socket");
244         return 0;
245     }
246 
247     if (!agent_addr(&addr, iv))
248         return 0;
249 
250     pid = fork();
251     if (pid == -1) {
252         warning("could not fork() agent -- %s", strerror(errno));
253         return 0;
254     } else if (pid != 0) {
255         return 1;
256     }
257     close(0);
258     close(1);
259 
260     umask(~(S_IRUSR | S_IWUSR));
261 
262     if (unlink(addr.sun_path))
263         if (errno != ENOENT)
264             fatal("failed to remove existing socket -- %s", strerror(errno));
265 
266     if (bind(pfd.fd, (struct sockaddr *)&addr, sizeof(addr))) {
267         if (errno != EADDRINUSE)
268             warning("could not bind agent socket %s -- %s",
269                     addr.sun_path, strerror(errno));
270         exit(EXIT_FAILURE);
271     }
272 
273     if (listen(pfd.fd, SOMAXCONN)) {
274         if (errno != EADDRINUSE)
275             fatal("could not listen on agent socket -- %s", strerror(errno));
276         exit(EXIT_FAILURE);
277     }
278 
279     close(2);
280     for (;;) {
281         int cfd;
282         int r = poll(&pfd, 1, global_agent_timeout * 1000);
283         if (r < 0) {
284             unlink(addr.sun_path);
285             fatal("agent poll failed -- %s", strerror(errno));
286         }
287         if (r == 0) {
288             unlink(addr.sun_path);
289             fputs("info: agent timeout\n", stderr);
290             close(pfd.fd);
291             break;
292         }
293         cfd = accept(pfd.fd, 0, 0);
294         if (cfd != -1) {
295             if (write(cfd, key, 32) != 32)
296                 warning("agent write failed");
297             close(cfd);
298         }
299     }
300     exit(EXIT_SUCCESS);
301 }
302 
303 #else
304 static int
agent_read(uint8_t * key,const uint8_t * id)305 agent_read(uint8_t *key, const uint8_t *id)
306 {
307     (void)key;
308     (void)id;
309     return 0;
310 }
311 
312 static int
agent_run(const uint8_t * key,const uint8_t * id)313 agent_run(const uint8_t *key, const uint8_t *id)
314 {
315     (void)key;
316     (void)id;
317     return 0;
318 }
319 #endif
320 
321 /**
322  * Prepend the system user config directory to a filename, creating
323  * the directory if necessary. Calls fatal() on any error.
324  */
325 static char *storage_directory(char *file);
326 
327 #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
328 #include <dirent.h>
329 #include <unistd.h>
330 #include <sys/stat.h>
331 #include <sys/types.h>
332 
333 /**
334  * Return non-zero if path exists and is a directory.
335  */
336 static int
dir_exists(const char * path)337 dir_exists(const char *path)
338 {
339     struct stat info;
340     return !stat(path, &info) && S_ISDIR(info.st_mode);
341 }
342 
343 /* Use $XDG_CONFIG_HOME/enchive, or $HOME/.config/enchive. */
344 static char *
storage_directory(char * file)345 storage_directory(char *file)
346 {
347     static const char enchive[] = "/enchive/";
348     static const char config[] = "/.config";
349     char *xdg_config_home = getenv("XDG_CONFIG_HOME");
350     char *path, *s;
351 
352     if (!xdg_config_home) {
353         char *home = getenv("HOME");
354         if (!home)
355             fatal("no $HOME or $XDG_CONFIG_HOME, giving up");
356         if (home[0] != '/')
357             fatal("$HOME is not absolute");
358         path = joinstr(4, home, config, enchive, file);
359     } else {
360         if (xdg_config_home[0] != '/')
361             fatal("$XDG_CONFIG_HOME is not absolute");
362         path = joinstr(3, xdg_config_home, enchive, file);
363     }
364 
365     s = strchr(path + 1, '/');
366     while (s) {
367         *s = 0;
368         if (dir_exists(path) || !mkdir(path, 0700)) {
369             DIR *dir = opendir(path);
370             if (dir)
371                 closedir(dir);
372             else
373                 fatal("opendir(%s) -- %s", path, strerror(errno));
374         } else {
375             fatal("mkdir(%s) -- %s", path, strerror(errno));
376         }
377         *s = '/';
378         s = strchr(s + 1, '/');
379     }
380 
381     return path;
382 }
383 
384 #elif defined(_WIN32)
385 #include <windows.h>
386 
387 /* Use %APPDATA% */
388 static char *
storage_directory(char * file)389 storage_directory(char *file)
390 {
391     char *parent;
392     static const char enchive[] = "\\enchive\\";
393     char *appdata = getenv("APPDATA");
394     if (!appdata)
395         fatal("$APPDATA is unset");
396 
397     parent = joinstr(2, appdata, enchive);
398     if (!CreateDirectory(parent, 0)) {
399         if (GetLastError() == ERROR_PATH_NOT_FOUND) {
400             fatal("$APPDATA directory doesn't exist");
401         } else { /* ERROR_ALREADY_EXISTS */
402             DWORD attr = GetFileAttributes(parent);
403             if ((attr == INVALID_FILE_ATTRIBUTES) ||
404                 !(attr & FILE_ATTRIBUTE_DIRECTORY))
405                 fatal("%s is not a directory", parent);
406         }
407     }
408     free(parent);
409 
410     return joinstr(3, appdata, enchive, file);
411 }
412 
413 #endif /* _WIN32 */
414 
415 /**
416  * Read a passphrase directly from the keyboard without echo.
417  */
418 static void get_passphrase(char *buf, size_t len, char *prompt);
419 
420 /**
421  * Read a passphrase without any fanfare (fallback).
422  */
423 static void
get_passphrase_dumb(char * buf,size_t len,char * prompt)424 get_passphrase_dumb(char *buf, size_t len, char *prompt)
425 {
426     size_t passlen;
427     warning("reading passphrase from stdin with echo");
428     fputs(prompt, stderr);
429     fflush(stderr);
430     if (!fgets(buf, len, stdin))
431         fatal("could not read passphrase");
432     passlen = strlen(buf);
433     if (buf[passlen - 1] < ' ')
434         buf[passlen - 1] = 0;
435 }
436 
437 #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
438 #include <fcntl.h>
439 #include <unistd.h>
440 #include <termios.h>
441 
442 static void
pinentry_decode(char * buf,size_t blen,const char * str)443 pinentry_decode(char *buf, size_t blen, const char *str)
444 {
445     size_t i, j;
446 
447     for (i = 0, j = 0; str[i] && str[i] != '\n' && j < blen - 1; i++) {
448         int c = str[i];
449         if (c == '%') {
450             static const char *hex = "0123456789ABCDEF";
451             char *nibh, *nibl;
452             if (!str[i + 1] || !str[i + 2])
453                 fatal("invalid data from pinentry");
454             nibh = memchr(hex, str[i + 1], 16);
455             nibl = memchr(hex, str[i + 2], 16);
456             if (!nibh || !nibl)
457                 fatal("invalid data from pinentry");
458             buf[j++] = (nibh - hex) * 16 + (nibl - hex);
459             i += 2;
460         } else {
461             buf[j++] = c;
462         }
463     }
464     buf[j] = 0;
465 }
466 
467 static void
invoke_pinentry(char * buf,size_t len,char * prompt)468 invoke_pinentry(char *buf, size_t len, char *prompt)
469 {
470     int pin[2];
471     int pout[2];
472     pid_t pid;
473 
474     if (pipe(pin) != 0)
475         fatal("could not start pinentry -- %s", strerror(errno));
476     if (pipe(pout) != 0)
477         fatal("could not start pinentry -- %s", strerror(errno));
478 
479     pid = fork();
480     if (pid == -1)
481         fatal("pinentry fork() failed -- %s", strerror(errno));
482     if (pid) {
483         FILE *pfi, *pfo;
484         char line[ENCHIVE_PASSPHRASE_MAX * 3 + 32];
485 
486         close(pin[0]);
487         close(pout[1]);
488 
489         if (!(pfi = fdopen(pin[1], "w")))
490             fatal("fdopen() input -- %s", strerror(errno));
491         if (!(pfo = fdopen(pout[0], "r")))
492             fatal("fdopen() output -- %s", strerror(errno));
493 
494         if (!fgets(line, sizeof(line), pfo))
495             /* Likely caused by exec() failure, so exit quietly. */
496             exit(EXIT_FAILURE);
497         if (strncmp(line, "OK", 2) != 0)
498             fatal("pinentry startup failure");
499 
500         if (fprintf(pfi, "SETPROMPT %s\n", prompt) < 0 || fflush(pfi) < 0)
501             fatal("pinentry write() -- %s", strerror(errno));
502 
503         if (!fgets(line, sizeof(line), pfo))
504             fatal("pinentry read() -- %s", strerror(errno));
505         if (strncmp(line, "OK", 2) != 0)
506             fatal("pinentry protocol failure");
507 
508         if (fprintf(pfi, "GETPIN\n") < 0 || fflush(pfi) < 0)
509             fatal("pinentry write() -- %s", strerror(errno));
510 
511         if (!fgets(line, sizeof(line), pfo))
512             fatal("pinentry read() -- %s", strerror(errno));
513         if (strncmp(line, "ERR ", 4) == 0)
514             fatal("passphrase entry canceled");
515         else if (strncmp(line, "OK", 2) == 0)
516             buf[0] = 0;
517         else if (strncmp(line, "D ", 2) == 0)
518             pinentry_decode(buf, len, line + 2);
519         else
520             fatal("pinentry protocol failure");
521 
522         fclose(pfo);
523         fclose(pfi);
524     } else {
525         close(pin[1]);
526         close(pout[0]);
527         dup2(pin[0], STDIN_FILENO);
528         dup2(pout[1], STDOUT_FILENO);
529         if (execlp(pinentry_path, pinentry_path, (char *)0))
530             fatal("exec(\"%s\") failed -- %s",
531                   pinentry_path, strerror(errno));
532     }
533 }
534 
535 static void
get_passphrase(char * buf,size_t len,char * prompt)536 get_passphrase(char *buf, size_t len, char *prompt)
537 {
538     int tty;
539 
540     if (pinentry_path) {
541         invoke_pinentry(buf, len, prompt);
542         return;
543     }
544 
545     tty = open("/dev/tty", O_RDWR);
546     if (tty == -1) {
547         get_passphrase_dumb(buf, len, prompt);
548     } else {
549         char newline = '\n';
550         size_t i = 0;
551         struct termios old, new;
552         if (write(tty, prompt, strlen(prompt)) == -1)
553             fatal("error asking for passphrase");
554         tcgetattr(tty, &old);
555         new = old;
556         new.c_lflag &= ~ECHO;
557         tcsetattr(tty, TCSANOW, &new);
558         errno = 0;
559         while (i < len - 1 && read(tty, buf + i, 1) == 1) {
560             if (buf[i] == '\n' || buf[i] == '\r')
561                 break;
562             i++;
563         }
564         buf[i] = 0;
565         tcsetattr(tty, TCSANOW, &old);
566         if (write(tty, &newline, 1) == -1)
567             fatal("error asking for passphrase");
568         close(tty);
569         if (errno)
570             fatal("could not read passphrase from /dev/tty");
571     }
572 }
573 
574 #elif defined(_WIN32)
575 #include <windows.h>
576 
577 static void
get_passphrase(char * buf,size_t len,char * prompt)578 get_passphrase(char *buf, size_t len, char *prompt)
579 {
580     DWORD orig;
581     HANDLE in = GetStdHandle(STD_INPUT_HANDLE);
582     if (!GetConsoleMode(in, &orig)) {
583         get_passphrase_dumb(buf, len, prompt);
584     } else {
585         size_t passlen;
586         SetConsoleMode(in, orig & ~ENABLE_ECHO_INPUT);
587         fputs(prompt, stderr);
588         if (!fgets(buf, len, stdin))
589             fatal("could not read passphrase");
590         fputc('\n', stderr);
591         passlen = strlen(buf);
592         if (buf[passlen - 1] < ' ')
593             buf[passlen - 1] = 0;
594     }
595 }
596 
597 #else
598 static void
get_passphrase(char * buf,size_t len,char * prompt)599 get_passphrase(char *buf, size_t len, char *prompt)
600 {
601     get_passphrase_dumb(buf, len, prompt);
602 }
603 #endif
604 
605 /**
606  * Create/truncate a file with paranoid permissions using OS calls.
607  */
608 static FILE *secure_creat(const char *file);
609 
610 #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
611 #include <unistd.h>
612 
613 static FILE *
secure_creat(const char * file)614 secure_creat(const char *file)
615 {
616     int fd = open(file, O_CREAT | O_WRONLY, 00600);
617     if (fd == -1)
618         return 0;
619     return fdopen(fd, "wb");
620 }
621 
622 #else
623 static FILE *
secure_creat(const char * file)624 secure_creat(const char *file)
625 {
626     return fopen(file, "wb");
627 }
628 #endif
629 
630 /**
631  * Initialize a SHA-256 context for HMAC-SHA256.
632  * All message data will go into the resulting context.
633  */
634 static void
hmac_init(SHA256_CTX * ctx,const uint8_t * key)635 hmac_init(SHA256_CTX *ctx, const uint8_t *key)
636 {
637     int i;
638     uint8_t pad[SHA256_BLOCK_SIZE];
639     sha256_init(ctx);
640     for (i = 0; i < SHA256_BLOCK_SIZE; i++)
641         pad[i] = key[i] ^ 0x36U;
642     sha256_update(ctx, pad, sizeof(pad));
643 }
644 
645 /**
646  * Compute the final HMAC-SHA256 MAC.
647  * The key must be the same as used for initialization.
648  */
649 static void
hmac_final(SHA256_CTX * ctx,const uint8_t * key,uint8_t * hash)650 hmac_final(SHA256_CTX *ctx, const uint8_t *key, uint8_t *hash)
651 {
652     int i;
653     uint8_t pad[SHA256_BLOCK_SIZE];
654     sha256_final(ctx, hash);
655     sha256_init(ctx);
656     for (i = 0; i < SHA256_BLOCK_SIZE; i++)
657         pad[i] = key[i] ^ 0x5cU;
658     sha256_update(ctx, pad, sizeof(pad));
659     sha256_update(ctx, hash, SHA256_BLOCK_SIZE);
660     sha256_final(ctx, hash);
661 }
662 
663 /**
664  * Derive a 32-byte key from null-terminated passphrase into buf.
665  * Optionally provide an 8-byte salt.
666  */
667 static void
key_derive(const char * passphrase,uint8_t * buf,int iexp,const uint8_t * salt)668 key_derive(const char *passphrase, uint8_t *buf, int iexp, const uint8_t *salt)
669 {
670     uint8_t salt32[SHA256_BLOCK_SIZE] = {0};
671     SHA256_CTX ctx[1];
672     unsigned long i;
673     unsigned long memlen = 1UL << iexp;
674     unsigned long mask = memlen - 1;
675     unsigned long iterations = 1UL << (iexp - 5);
676     uint8_t *memory, *memptr, *p;
677 
678     memory = malloc(memlen + SHA256_BLOCK_SIZE);
679     if (!memory)
680         fatal("not enough memory for key derivation");
681 
682     if (salt)
683         memcpy(salt32, salt, 8);
684     hmac_init(ctx, salt32);
685     sha256_update(ctx, (uint8_t *)passphrase, strlen(passphrase));
686     hmac_final(ctx, salt32, memory);
687 
688     for (p = memory + SHA256_BLOCK_SIZE;
689          p < memory + memlen + SHA256_BLOCK_SIZE;
690          p += SHA256_BLOCK_SIZE) {
691         sha256_init(ctx);
692         sha256_update(ctx, p - SHA256_BLOCK_SIZE, SHA256_BLOCK_SIZE);
693         sha256_final(ctx, p);
694     }
695 
696     memptr = memory + memlen - SHA256_BLOCK_SIZE;
697     for (i = 0; i < iterations; i++) {
698         unsigned long offset;
699         sha256_init(ctx);
700         sha256_update(ctx, memptr, SHA256_BLOCK_SIZE);
701         sha256_final(ctx, memptr);
702         offset = ((unsigned long)memptr[3] << 24 |
703                   (unsigned long)memptr[2] << 16 |
704                   (unsigned long)memptr[1] <<  8 |
705                   (unsigned long)memptr[0] <<  0);
706         memptr = memory + (offset & mask);
707     }
708 
709     memcpy(buf, memptr, SHA256_BLOCK_SIZE);
710     free(memory);
711 }
712 
713 /**
714  * Get secure entropy suitable for key generation from OS.
715  * Abort the program if the entropy could not be retrieved.
716  */
717 static void secure_entropy(void *buf, size_t len);
718 
719 #if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
720 static void
secure_entropy(void * buf,size_t len)721 secure_entropy(void *buf, size_t len)
722 {
723     FILE *r = fopen("/dev/urandom", "rb");
724     if (!r)
725         fatal("failed to open %s", "/dev/urandom");
726     if (!fread(buf, len, 1, r))
727         fatal("failed to gather entropy");
728     fclose(r);
729 }
730 
731 #elif defined(_WIN32)
732 #include <windows.h>
733 
734 static void
secure_entropy(void * buf,size_t len)735 secure_entropy(void *buf, size_t len)
736 {
737     HCRYPTPROV h = 0;
738     DWORD type = PROV_RSA_FULL;
739     DWORD flags = CRYPT_VERIFYCONTEXT | CRYPT_SILENT;
740     if (!CryptAcquireContext(&h, 0, 0, type, flags) ||
741         !CryptGenRandom(h, len, buf))
742         fatal("failed to gather entropy");
743     CryptReleaseContext(h, 0);
744 }
745 #endif
746 
747 /**
748  * Generate a brand new Curve25519 secret key from system entropy.
749  */
750 static void
generate_secret(uint8_t * s)751 generate_secret(uint8_t *s)
752 {
753     secure_entropy(s, 32);
754     s[0] &= 248;
755     s[31] &= 127;
756     s[31] |= 64;
757 }
758 
759 /**
760  * Generate a Curve25519 public key from a secret key.
761  */
762 static void
compute_public(uint8_t * p,const uint8_t * s)763 compute_public(uint8_t *p, const uint8_t *s)
764 {
765     static const uint8_t b[32] = {9};
766     curve25519_donna(p, s, b);
767 }
768 
769 /**
770  * Compute a shared secret from our secret key and their public key.
771  */
772 static void
compute_shared(uint8_t * sh,const uint8_t * s,const uint8_t * p)773 compute_shared(uint8_t *sh, const uint8_t *s, const uint8_t *p)
774 {
775     curve25519_donna(sh, s, p);
776 }
777 
778 /**
779  * Encrypt from file to file using key/iv, aborting on any error.
780  */
781 static void
symmetric_encrypt(FILE * in,FILE * out,const uint8_t * key,const uint8_t * iv)782 symmetric_encrypt(FILE *in, FILE *out, const uint8_t *key, const uint8_t *iv)
783 {
784     static uint8_t buffer[2][CHACHA_BLOCKLENGTH * 1024];
785     uint8_t mac[SHA256_BLOCK_SIZE];
786     SHA256_CTX hmac[1];
787     chacha_ctx ctx[1];
788 
789     chacha_keysetup(ctx, key, 256);
790     chacha_ivsetup(ctx, iv);
791     hmac_init(hmac, key);
792 
793     for (;;) {
794         size_t z = fread(buffer[0], 1, sizeof(buffer[0]), in);
795         if (!z) {
796             if (ferror(in))
797                 fatal("error reading plaintext file");
798             break;
799         }
800         sha256_update(hmac, buffer[0], z);
801         chacha_encrypt(ctx, buffer[0], buffer[1], z);
802         if (!fwrite(buffer[1], z, 1, out))
803             fatal("error writing ciphertext file");
804         if (z < sizeof(buffer[0]))
805             break;
806     }
807 
808     hmac_final(hmac, key, mac);
809 
810     if (!fwrite(mac, sizeof(mac), 1, out))
811         fatal("error writing checksum to ciphertext file");
812     if (fflush(out))
813         fatal("error flushing to ciphertext file -- %s", strerror(errno));
814 }
815 
816 /**
817  * Decrypt from file to file using key/iv, aborting on any error.
818  */
819 static void
symmetric_decrypt(FILE * in,FILE * out,const uint8_t * key,const uint8_t * iv)820 symmetric_decrypt(FILE *in, FILE *out, const uint8_t *key, const uint8_t *iv)
821 {
822     static uint8_t buffer[2][CHACHA_BLOCKLENGTH * 1024 + SHA256_BLOCK_SIZE];
823     uint8_t mac[SHA256_BLOCK_SIZE];
824     SHA256_CTX hmac[1];
825     chacha_ctx ctx[1];
826 
827     chacha_keysetup(ctx, key, 256);
828     chacha_ivsetup(ctx, iv);
829     hmac_init(hmac, key);
830 
831     /* Always keep SHA256_BLOCK_SIZE bytes in the buffer. */
832     if (!(fread(buffer[0], SHA256_BLOCK_SIZE, 1, in))) {
833         if (ferror(in))
834             fatal("cannot read ciphertext file");
835         else
836             fatal("ciphertext file too short");
837     }
838 
839     for (;;) {
840         uint8_t *p = buffer[0] + SHA256_BLOCK_SIZE;
841         size_t z = fread(p, 1, sizeof(buffer[0]) - SHA256_BLOCK_SIZE, in);
842         if (!z) {
843             if (ferror(in))
844                 fatal("error reading ciphertext file");
845             break;
846         }
847         chacha_encrypt(ctx, buffer[0], buffer[1], z);
848         sha256_update(hmac, buffer[1], z);
849         if (!fwrite(buffer[1], z, 1, out))
850             fatal("error writing plaintext file");
851 
852         /* Move last SHA256_BLOCK_SIZE bytes to the front. */
853         memmove(buffer[0], buffer[0] + z, SHA256_BLOCK_SIZE);
854 
855         if (z < sizeof(buffer[0]) - SHA256_BLOCK_SIZE)
856             break;
857     }
858 
859     hmac_final(hmac, key, mac);
860     if (memcmp(buffer[0], mac, sizeof(mac)) != 0)
861         fatal("checksum mismatch!");
862     if (fflush(out))
863         fatal("error flushing to plaintext file -- %s", strerror(errno));
864 
865 }
866 
867 /**
868  * Return the default public key file.
869  */
870 static char *
default_pubfile(void)871 default_pubfile(void)
872 {
873     return storage_directory("enchive.pub");
874 }
875 
876 /**
877  * Return the default secret key file.
878  */
879 static char *
default_secfile(void)880 default_secfile(void)
881 {
882     return storage_directory("enchive.sec");
883 }
884 
885 /**
886  * Dump the public key to a file, aborting on error.
887  */
888 static void
write_pubkey(char * file,uint8_t * key)889 write_pubkey(char *file, uint8_t *key)
890 {
891     FILE *f = fopen(file, "wb");
892     if (!f)
893         fatal("failed to open key file for writing '%s' -- %s",
894               file, strerror(errno));
895     cleanup_register(f, file);
896     if (!fwrite(key, 32, 1, f))
897         fatal("failed to write key file '%s'", file);
898     cleanup_closed(f);
899     if (fclose(f))
900         fatal("failed to flush key file '%s' -- %s", file, strerror(errno));
901 }
902 
903 /* Layout of secret key file */
904 #define SECFILE_IV            0
905 #define SECFILE_ITERATIONS    8
906 #define SECFILE_VERSION       9
907 #define SECFILE_PROTECT_HASH  12
908 #define SECFILE_SECKEY        32
909 
910 /**
911  * Write the secret key to a file, encrypting it if necessary.
912  */
913 static void
write_seckey(char * file,const uint8_t * seckey,int iexp)914 write_seckey(char *file, const uint8_t *seckey, int iexp)
915 {
916     FILE *secfile;
917     chacha_ctx cha[1];
918     SHA256_CTX sha[1];
919     uint8_t buf[8 + 1 + 3 + 20 + 32] = {0}; /* entire file contents */
920     uint8_t protect[32];
921 
922     uint8_t *buf_iv           = buf + SECFILE_IV;
923     uint8_t *buf_iterations   = buf + SECFILE_ITERATIONS;
924     uint8_t *buf_version      = buf + SECFILE_VERSION;
925     uint8_t *buf_protect_hash = buf + SECFILE_PROTECT_HASH;
926     uint8_t *buf_seckey       = buf + SECFILE_SECKEY;
927 
928     buf_version[0] = ENCHIVE_FORMAT_VERSION;
929 
930     if (iexp) {
931         /* Prompt for a passphrase. */
932         char pass[2][ENCHIVE_PASSPHRASE_MAX];
933         get_passphrase(pass[0], sizeof(pass[0]),
934                        "protection passphrase (empty for none): ");
935         if (!pass[0][0]) {
936             /* Nevermind. */
937             iexp = 0;
938         }  else {
939             get_passphrase(pass[1], sizeof(pass[0]),
940                            "protection passphrase (repeat): ");
941             if (strcmp(pass[0], pass[1]) != 0)
942                 fatal("protection passphrases don't match");
943 
944             /* Generate an IV to double as salt. */
945             secure_entropy(buf_iv, 8);
946 
947             key_derive(pass[0], protect, iexp, buf_iv);
948             buf_iterations[0] = iexp;
949 
950             sha256_init(sha);
951             sha256_update(sha, protect, sizeof(protect));
952             sha256_final(sha, buf_protect_hash);
953         }
954     }
955 
956     if (iexp) {
957         /* Encrypt using key derived from passphrase. */
958         chacha_keysetup(cha, protect, 256);
959         chacha_ivsetup(cha, buf_iv);
960         chacha_encrypt(cha, seckey, buf_seckey, 32);
961     } else {
962         /* Copy key to output buffer. */
963         memcpy(buf_seckey, seckey, 32);
964     }
965 
966     secfile = secure_creat(file);
967     if (!secfile)
968         fatal("failed to open key file for writing '%s'", file);
969     cleanup_register(secfile, file);
970     if (!fwrite(buf, sizeof(buf), 1, secfile))
971         fatal("failed to write key file '%s'", file);
972     cleanup_closed(secfile);
973     if (fclose(secfile))
974         fatal("failed to flush key file '%s' -- %s", file, strerror(errno));
975 }
976 
977 /**
978  * Load the public key from the file.
979  */
980 static void
load_pubkey(const char * file,uint8_t * key)981 load_pubkey(const char *file, uint8_t *key)
982 {
983     FILE *f = fopen(file, "rb");
984     if (!f)
985         fatal("failed to open key file for reading '%s' -- %s",
986               file, strerror(errno));
987     if (!fread(key, 32, 1, f))
988         fatal("failed to read key file '%s'", file);
989     fclose(f);
990 }
991 
992 /**
993  * Attempt to load and decrypt the secret key stored in a file.
994  *
995  * If the key is encrypted, attempt to query a key agent. If that
996  * fails (no agent, bad key) prompt the user for a passphrase. If that
997  * fails (wrong passphrase), abort the program.
998  *
999  * If "global_agent_timeout" is non-zero, start a key agent if
1000  * necessary.
1001  */
1002 static void
load_seckey(const char * file,uint8_t * seckey)1003 load_seckey(const char *file, uint8_t *seckey)
1004 {
1005     FILE *secfile;
1006     chacha_ctx cha[1];
1007     SHA256_CTX sha[1];
1008     uint8_t buf[8 + 4 + 20 + 32];            /* entire key file contents */
1009     uint8_t protect[32];                     /* protection key */
1010     uint8_t protect_hash[SHA256_BLOCK_SIZE]; /* hash of protection key */
1011     int iexp;
1012     int version;
1013 
1014     uint8_t *buf_iv           = buf + SECFILE_IV;
1015     uint8_t *buf_iterations   = buf + SECFILE_ITERATIONS;
1016     uint8_t *buf_version      = buf + SECFILE_VERSION;
1017     uint8_t *buf_protect_hash = buf + SECFILE_PROTECT_HASH;
1018     uint8_t *buf_seckey       = buf + SECFILE_SECKEY;
1019 
1020     /* Read the entire file into buf. */
1021     secfile = fopen(file, "rb");
1022     if (!secfile)
1023         fatal("failed to open key file for reading '%s' -- %s",
1024               file, strerror(errno));
1025     if (!fread(buf, sizeof(buf), 1, secfile))
1026         fatal("failed to read key file -- %s", file);
1027     fclose(secfile);
1028 
1029     version = buf_version[0];
1030     if (version != ENCHIVE_FORMAT_VERSION)
1031         fatal("secret key version mismatch -- expected %d, got %d",
1032               ENCHIVE_FORMAT_VERSION, version);
1033 
1034     iexp = buf_iterations[0];
1035     if (iexp) {
1036         /* Secret key is encrypted. */
1037         int agent_success = agent_read(protect, buf_iv);
1038         if (agent_success) {
1039             /* Check validity of agent key. */
1040             sha256_init(sha);
1041             sha256_update(sha, protect, 32);
1042             sha256_final(sha, protect_hash);
1043             agent_success = !memcmp(protect_hash, buf_protect_hash, 20);
1044         }
1045 
1046         if (!agent_success) {
1047             /* Ask user for passphrase. */
1048             char pass[ENCHIVE_PASSPHRASE_MAX];
1049             get_passphrase(pass, sizeof(pass), "passphrase: ");
1050             key_derive(pass, protect, iexp, buf_iv);
1051 
1052             /* Validate passphrase. */
1053             sha256_init(sha);
1054             sha256_update(sha, protect, sizeof(protect));
1055             sha256_final(sha, protect_hash);
1056             if (memcmp(protect_hash, buf_protect_hash, 20) != 0)
1057                 fatal("wrong passphrase");
1058         }
1059 
1060         /* We have the correct protection key. Start the agent? */
1061         if (!agent_success && global_agent_timeout)
1062             agent_run(protect, buf_iv);
1063 
1064         /* Decrypt the key into the output. */
1065         chacha_keysetup(cha, protect, 256);
1066         chacha_ivsetup(cha, buf_iv);
1067         chacha_encrypt(cha, buf_seckey, seckey, 32);
1068     } else {
1069         /* Key is unencrypted, copy into output. */
1070         memcpy(seckey, buf_seckey, 32);
1071     }
1072 }
1073 
1074 /**
1075  * Return 1 if file exists, or 0 if it doesn't.
1076  */
1077 static int
file_exists(char * filename)1078 file_exists(char *filename)
1079 {
1080     FILE *f = fopen(filename, "r");
1081     if (f) {
1082         fclose(f);
1083         return 1;
1084     }
1085     return 0;
1086 }
1087 
1088 /**
1089  * Print a nice fingerprint of a key.
1090  */
1091 static void
print_fingerprint(const uint8_t * key)1092 print_fingerprint(const uint8_t *key)
1093 {
1094     int i;
1095     uint8_t hash[32];
1096     SHA256_CTX sha[1];
1097 
1098     sha256_init(sha);
1099     sha256_update(sha, key, 32);
1100     sha256_final(sha, hash);
1101     for (i = 0; i < 16; i += 4) {
1102         unsigned long chunk =
1103             ((unsigned long)hash[i + 0] << 24) |
1104             ((unsigned long)hash[i + 1] << 16) |
1105             ((unsigned long)hash[i + 2] <<  8) |
1106             ((unsigned long)hash[i + 3] <<  0);
1107         printf("%s%08lx", i ? "-" : "", chunk);
1108     }
1109 }
1110 
1111 enum command {
1112     COMMAND_UNKNOWN = -2,
1113     COMMAND_AMBIGUOUS = -1,
1114     COMMAND_KEYGEN,
1115     COMMAND_FINGERPRINT,
1116     COMMAND_ARCHIVE,
1117     COMMAND_EXTRACT
1118 };
1119 
1120 static const char command_names[][12] = {
1121     "keygen", "fingerprint", "archive", "extract"
1122 };
1123 
1124 /**
1125  * Attempt to unambiguously parse the user's command into an enum.
1126  */
1127 static enum command
parse_command(char * command)1128 parse_command(char *command)
1129 {
1130     int found = COMMAND_UNKNOWN;
1131     size_t len = strlen(command);
1132     int ncommands = sizeof(command_names) / sizeof(*command_names);
1133     int i;
1134     for (i = 0; i < ncommands; i++) {
1135         if (strncmp(command, command_names[i], len) == 0) {
1136             if (found >= 0)
1137                 return COMMAND_AMBIGUOUS;
1138             found = i;
1139         }
1140     }
1141     return found;
1142 }
1143 
1144 static void
command_keygen(struct optparse * options)1145 command_keygen(struct optparse *options)
1146 {
1147     static const struct optparse_long keygen[] = {
1148         {"derive",      'd', OPTPARSE_OPTIONAL},
1149         {"edit"  ,      'e', OPTPARSE_NONE},
1150         {"force",       'f', OPTPARSE_NONE},
1151         {"fingerprint", 'i', OPTPARSE_NONE},
1152         {"iterations",  'k', OPTPARSE_REQUIRED},
1153         {"plain",       'u', OPTPARSE_NONE},
1154         {"repeats",     'r', OPTPARSE_REQUIRED},
1155         {0, 0, 0}
1156     };
1157 
1158     char *pubfile = dupstr(global_pubkey);
1159     char *secfile = dupstr(global_seckey);
1160     int pubfile_exists;
1161     int secfile_exists;
1162     uint8_t public[32];
1163     uint8_t secret[32];
1164     int clobber = 0;
1165     int derive = 0;
1166     int edit = 0;
1167     int protect = 1;
1168     int fingerprint = 0;
1169     int repeats = 1;
1170     int key_derive_iterations = ENCHIVE_KEY_DERIVE_ITERATIONS;
1171     int seckey_derive_iterations = ENCHIVE_SECKEY_DERIVE_ITERATIONS;
1172 
1173     int option;
1174     while ((option = optparse_long(options, keygen, 0)) != -1) {
1175         switch (option) {
1176             case 'd': {
1177                 char *p;
1178                 char *arg = options->optarg;
1179                 derive = 1;
1180                 if (arg) {
1181                     long n;
1182                     errno = 0;
1183                     n = strtol(arg, &p, 10);
1184                     if (errno || *p)
1185                         fatal("invalid argument -- %s", arg);
1186                     if (n < 5 || n > 31)
1187                         fatal("--derive argument must be 5 <= n <= 31 -- %s",
1188                               arg);
1189                     seckey_derive_iterations = n;
1190                 }
1191             } break;
1192             case 'e':
1193                 edit = 1;
1194                 break;
1195             case 'f':
1196                 clobber = 1;
1197                 break;
1198             case 'i':
1199                 fingerprint = 1;
1200                 break;
1201             case 'k': {
1202                 char *p;
1203                 char *arg = options->optarg;
1204                 long n;
1205                 errno = 0;
1206                 n = strtol(arg, &p, 10);
1207                 if (errno || *p)
1208                     fatal("invalid argument -- %s", arg);
1209                 if (n < 5 || n > 31)
1210                     fatal("--iterations argument must be 5 <= n <= 31 -- %s",
1211                           arg);
1212                 key_derive_iterations = n;
1213             } break;
1214             case 'r': {
1215                 char *p;
1216                 char *arg = options->optarg;
1217                 long n;
1218                 errno = 0;
1219                 n = strtol(arg, &p, 10);
1220                 if (errno || *p || n < 0 || n >= 256)
1221                     fatal("invalid --repeats (-r) -- %s", arg);
1222                 repeats = n;
1223             } break;
1224             case 'u':
1225                 protect = 0;
1226                 break;
1227             default:
1228                 fatal("%s", options->errmsg);
1229         }
1230     }
1231 
1232     if (edit && derive)
1233         fatal("--edit and --derive are mutually exclusive");
1234 
1235     if (!pubfile)
1236         pubfile = default_pubfile();
1237     pubfile_exists = file_exists(pubfile);
1238     if (!secfile)
1239         secfile = default_secfile();
1240     secfile_exists = file_exists(secfile);
1241 
1242     if (!edit && !clobber) {
1243         if (pubfile_exists)
1244             fatal("operation would clobber %s", pubfile);
1245         if (secfile_exists)
1246             fatal("operation would clobber %s", secfile);
1247     }
1248 
1249     if (edit) {
1250         if (!secfile_exists)
1251             fatal("cannot edit non-existing file %s", secfile);
1252         load_seckey(secfile, secret);
1253     } else if (derive) {
1254         /* Generate secret key from passphrase. */
1255         char pass[2][ENCHIVE_PASSPHRASE_MAX];
1256         get_passphrase(pass[0], sizeof(pass[0]),
1257                        "secret key passphrase: ");
1258         while (repeats--) {
1259             get_passphrase(pass[1], sizeof(pass[0]),
1260                            "secret key passphrase (repeat): ");
1261             if (strcmp(pass[0], pass[1]) != 0)
1262                 fatal("secret key passphrases don't match");
1263         }
1264         key_derive(pass[0], secret, seckey_derive_iterations, 0);
1265         secret[0] &= 248;
1266         secret[31] &= 127;
1267         secret[31] |= 64;
1268     } else {
1269         /* Generate secret key from entropy. */
1270         generate_secret(secret);
1271     }
1272 
1273     compute_public(public, secret);
1274 
1275     if (fingerprint) {
1276         fputs("keyid: ", stdout);
1277         print_fingerprint(public);
1278         putchar('\n');
1279     }
1280 
1281     write_seckey(secfile, secret, protect ? key_derive_iterations : 0);
1282     write_pubkey(pubfile, public);
1283 }
1284 
1285 static void
command_fingerprint(struct optparse * options)1286 command_fingerprint(struct optparse *options)
1287 {
1288     static const struct optparse_long fingerprint[] = {
1289         {0, 0, 0}
1290     };
1291 
1292     char *pubfile = dupstr(global_pubkey);
1293     uint8_t public[32];
1294 
1295     int option;
1296     while ((option = optparse_long(options, fingerprint, 0)) != -1) {
1297         switch (option) {
1298             default:
1299                 fatal("%s", options->errmsg);
1300         }
1301     }
1302 
1303     if (!pubfile)
1304         pubfile = default_pubfile();
1305     load_pubkey(pubfile, public);
1306     free(pubfile);
1307 
1308     print_fingerprint(public);
1309     putchar('\n');
1310 }
1311 
1312 static void
command_archive(struct optparse * options)1313 command_archive(struct optparse *options)
1314 {
1315     static const struct optparse_long archive[] = {
1316         {"delete", 'd', OPTPARSE_NONE},
1317         {0, 0, 0}
1318     };
1319 
1320     /* Options */
1321     char *infile;
1322     char *outfile;
1323     FILE *in = stdin;
1324     FILE *out = stdout;
1325     char *pubfile = dupstr(global_pubkey);
1326     int delete = 0;
1327 
1328     /* Workspace */
1329     uint8_t public[32];
1330     uint8_t esecret[32];
1331     uint8_t epublic[32];
1332     uint8_t shared[32];
1333     uint8_t iv[SHA256_BLOCK_SIZE];
1334     SHA256_CTX sha[1];
1335 
1336     int option;
1337     while ((option = optparse_long(options, archive, 0)) != -1) {
1338         switch (option) {
1339             case 'd':
1340                 delete = 1;
1341                 break;
1342             default:
1343                 fatal("%s", options->errmsg);
1344         }
1345     }
1346 
1347     if (!pubfile)
1348         pubfile = default_pubfile();
1349     load_pubkey(pubfile, public);
1350     free(pubfile);
1351 
1352     infile = optparse_arg(options);
1353     if (infile) {
1354         in = fopen(infile, "rb");
1355         if (!in)
1356             fatal("could not open input file '%s' -- %s",
1357                   infile, strerror(errno));
1358     }
1359 
1360     outfile = dupstr(optparse_arg(options));
1361     if (!outfile && infile) {
1362         /* Generate an output filename. */
1363         outfile = joinstr(2, infile, enchive_suffix);
1364     }
1365     if (outfile) {
1366         out = fopen(outfile, "wb");
1367         if (!out)
1368             fatal("could not open output file '%s' -- %s",
1369                   outfile, strerror(errno));
1370         cleanup_register(out, outfile);
1371     }
1372 
1373     /* Generare ephemeral keypair. */
1374     generate_secret(esecret);
1375     compute_public(epublic, esecret);
1376 
1377     /* Create shared secret between ephemeral key and master key. */
1378     compute_shared(shared, esecret, public);
1379     sha256_init(sha);
1380     sha256_update(sha, shared, sizeof(shared));
1381     sha256_final(sha, iv);
1382     iv[0] += (unsigned)ENCHIVE_FORMAT_VERSION;
1383     if (!fwrite(iv, 8, 1, out))
1384         fatal("failed to write IV to archive");
1385     if (!fwrite(epublic, sizeof(epublic), 1, out))
1386         fatal("failed to write ephemeral key to archive");
1387     symmetric_encrypt(in, out, shared, iv);
1388 
1389     if (in != stdin)
1390         fclose(in);
1391     if (out != stdout) {
1392         cleanup_closed(out);
1393         fclose(out); /* already flushed */
1394     }
1395 
1396     if (delete && infile)
1397         remove(infile);
1398 
1399 }
1400 
1401 static void
command_extract(struct optparse * options)1402 command_extract(struct optparse *options)
1403 {
1404     static const struct optparse_long extract[] = {
1405         {"delete", 'd', OPTPARSE_NONE},
1406         {0, 0, 0}
1407     };
1408 
1409     /* Options */
1410     char *infile;
1411     char *outfile;
1412     FILE *in = stdin;
1413     FILE *out = stdout;
1414     char *secfile = dupstr(global_seckey);
1415     int delete = 0;
1416 
1417     /* Workspace */
1418     SHA256_CTX sha[1];
1419     uint8_t secret[32];
1420     uint8_t epublic[32];
1421     uint8_t shared[32];
1422     uint8_t iv[8];
1423     uint8_t check_iv[SHA256_BLOCK_SIZE];
1424 
1425     int option;
1426     while ((option = optparse_long(options, extract, 0)) != -1) {
1427         switch (option) {
1428             case 'd':
1429                 delete = 1;
1430                 break;
1431             default:
1432                 fatal("%s", options->errmsg);
1433         }
1434     }
1435 
1436     if (!secfile)
1437         secfile = default_secfile();
1438     load_seckey(secfile, secret);
1439     free(secfile);
1440 
1441     infile = optparse_arg(options);
1442     if (infile) {
1443         in = fopen(infile, "rb");
1444         if (!in)
1445             fatal("could not open input file '%s' -- %s",
1446                   infile, strerror(errno));
1447     }
1448 
1449     outfile = dupstr(optparse_arg(options));
1450     if (!outfile && infile) {
1451         /* Generate an output filename. */
1452         size_t slen = sizeof(enchive_suffix) - 1;
1453         size_t len = strlen(infile);
1454         if (len <= slen || strcmp(enchive_suffix, infile + len - slen) != 0)
1455             fatal("could not determine output filename from %s", infile);
1456         outfile = dupstr(infile);
1457         outfile[len - slen] = 0;
1458     }
1459     if (outfile) {
1460         out = fopen(outfile, "wb");
1461         if (!out)
1462             fatal("could not open output file '%s' -- %s",
1463                   infile, strerror(errno));
1464         cleanup_register(out, outfile);
1465     }
1466 
1467     if (!(fread(iv, sizeof(iv), 1, in)))
1468         fatal("failed to read IV from archive");
1469     if (!(fread(epublic, sizeof(epublic), 1, in)))
1470         fatal("failed to read ephemeral key from archive");
1471     compute_shared(shared, secret, epublic);
1472 
1473     /* Validate key before processing the file. */
1474     sha256_init(sha);
1475     sha256_update(sha, shared, sizeof(shared));
1476     sha256_final(sha, check_iv);
1477     check_iv[0] += (unsigned)ENCHIVE_FORMAT_VERSION;
1478     if (memcmp(iv, check_iv, sizeof(iv)) != 0)
1479         fatal("invalid master key or format");
1480 
1481     symmetric_decrypt(in, out, shared, iv);
1482 
1483     if (in != stdin)
1484         fclose(in);
1485     if (out != stdout) {
1486         cleanup_closed(out);
1487         fclose(out); /* already flushed */
1488     }
1489 
1490     if (delete && infile)
1491         remove(infile);
1492 }
1493 
1494 /**
1495  * Write a NULL-terminated array of strings with a newline after each.
1496  */
1497 static void
multiputs(const char ** s,FILE * f)1498 multiputs(const char **s, FILE *f)
1499 {
1500     while (*s) {
1501         fputs(*s++, f);
1502         fputc('\n', f);
1503     }
1504 }
1505 
1506 static void
print_usage(FILE * f)1507 print_usage(FILE *f)
1508 {
1509     multiputs(docs_usage, f);
1510 }
1511 
1512 static void
print_version(void)1513 print_version(void)
1514 {
1515     puts("enchive " STR(ENCHIVE_VERSION));
1516 }
1517 
1518 int
main(int argc,char ** argv)1519 main(int argc, char **argv)
1520 {
1521     static const struct optparse_long global[] = {
1522 #if ENCHIVE_OPTION_AGENT
1523         {"agent",         'a', OPTPARSE_OPTIONAL},
1524         {"no-agent",      'A', OPTPARSE_NONE},
1525 #endif
1526         {"pinentry",      'e', OPTPARSE_OPTIONAL},
1527         {"pubkey",        'p', OPTPARSE_REQUIRED},
1528         {"seckey",        's', OPTPARSE_REQUIRED},
1529         {"version",       'V', OPTPARSE_NONE},
1530         {"help",          'h', OPTPARSE_NONE},
1531         {0, 0, 0}
1532     };
1533 
1534     int option;
1535     char *command;
1536     struct optparse options[1];
1537     optparse_init(options, argv);
1538     options->permute = 0;
1539     (void)argc;
1540 
1541     while ((option = optparse_long(options, global, 0)) != -1) {
1542         switch (option) {
1543 #if ENCHIVE_OPTION_AGENT
1544             case 'a':
1545                 if (options->optarg) {
1546                     char *arg = options->optarg;
1547                     char *endptr;
1548                     errno = 0;
1549                     global_agent_timeout = strtol(arg, &endptr, 10);
1550                     if (*endptr || errno)
1551                         fatal("invalid --agent argument -- %s", arg);
1552                 } else
1553                     global_agent_timeout = ENCHIVE_AGENT_TIMEOUT;
1554                 break;
1555             case 'A':
1556                 global_agent_timeout = 0;
1557                 break;
1558 #endif
1559             case 'e':
1560                 if (options->optarg)
1561                     pinentry_path = options->optarg;
1562                 else
1563                     pinentry_path = STR(ENCHIVE_PINENTRY_DEFAULT);
1564                 break;
1565             case 'p':
1566                 global_pubkey = options->optarg;
1567                 break;
1568             case 's':
1569                 global_seckey = options->optarg;
1570                 break;
1571             case 'h':
1572                 print_usage(stdout);
1573                 exit(EXIT_SUCCESS);
1574                 break;
1575             case 'V':
1576                 print_version();
1577                 exit(EXIT_SUCCESS);
1578                 break;
1579             default:
1580                 fatal("%s", options->errmsg);
1581         }
1582     }
1583 
1584     command = optparse_arg(options);
1585     options->permute = 1;
1586     if (!command) {
1587         fprintf(stderr, "enchive: missing command\n");
1588         print_usage(stderr);
1589         exit(EXIT_FAILURE);
1590     }
1591 
1592     switch (parse_command(command)) {
1593         case COMMAND_UNKNOWN:
1594         case COMMAND_AMBIGUOUS:
1595             fprintf(stderr, "enchive: unknown command, %s\n", command);
1596             print_usage(stderr);
1597             exit(EXIT_FAILURE);
1598             break;
1599         case COMMAND_KEYGEN:
1600             command_keygen(options);
1601             break;
1602         case COMMAND_FINGERPRINT:
1603             command_fingerprint(options);
1604             break;
1605         case COMMAND_ARCHIVE:
1606             command_archive(options);
1607             break;
1608         case COMMAND_EXTRACT:
1609             command_extract(options);
1610             break;
1611     }
1612 
1613     cleanup_free();
1614     return 0;
1615 }
1616