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