From 2dfc2ab17a7b49b1f39587062b60960e06a0d4d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrien=20Gallou=C3=ABt?= Date: Wed, 6 May 2020 19:34:46 +0000 Subject: [PATCH] Be more friendly and ask for new passphrases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Adrien Gallouët --- README.md | 2 +- secret.c | 86 +++++++++++++++++++++++++++++-------------------------- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 23f0b02..78f9196 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ But it does have some interesting features: - A secret agent that only trusts subprocesses. Not all the processes of the same user! - Secret names completion is available after calling the secret agent. - Supports unstored secrets. Derived from some simple keys and a passphrase. - - Supports multiple passphrases. Not super user-friendly but nice to have. + - Supports multiple passphrases. A confirmation is requested for each new passphrase. - Depends only on the [libhydrogen](https://libhydrogen.org/) library. - Small, simple and non obfuscated C code. Well, I hope so :) diff --git a/secret.c b/secret.c index df23091..b710007 100644 --- a/secret.c +++ b/secret.c @@ -49,6 +49,7 @@ struct { char ctx_master[hydro_pwhash_CONTEXTBYTES]; char ctx_secret[hydro_secretbox_CONTEXTBYTES]; char ctx_passwd[hydro_pwhash_CONTEXTBYTES]; + int known_key; } s = { .pipe = {-1, -1}, .ctx_master = "MASTER", @@ -180,11 +181,27 @@ s_input(unsigned char *buf, size_t size, const char *prompt) if (buf[i] < ' ') s_fatal("Invalid input!"); } - hydro_memzero(buf + len, size - len); return len; } +static void +s_ask_pass(void *buf, size_t size, const char *prompt) +{ + unsigned char pass[128]; + size_t len = s_input(pass, sizeof(pass), prompt); + + if (!len) + s_exit(0); + + int r = hydro_pwhash_deterministic(buf, size, + (char *)pass, len, + s.ctx_master, s.hdr.master, + load64_le(s.hdr.opslimit), 0, 1); + hydro_memzero(pass, sizeof(pass)); + if (r) s_oops(__LINE__); +} + static int s_open_secret(int use_tty) { @@ -221,43 +238,10 @@ s_open_secret(int use_tty) if (!use_tty) s_exit(0); - unsigned char pass[128]; - size_t len = s_input(pass, sizeof(pass), "Passphrase: "); - - if (!len) - s_exit(0); - - int r = hydro_pwhash_deterministic(s.x.key, sizeof(s.x.key), - (char *)pass, len, - s.ctx_master, s.hdr.master, - load64_le(s.hdr.opslimit), 0, 1); - hydro_memzero(pass, sizeof(pass)); - - if (r) - s_oops(__LINE__); - + s_ask_pass(s.x.key, sizeof(s.x.key), "Passphrase: "); return fd; } -static void -s_print_keys(int use_tty) -{ - int fd = s_open_secret(use_tty); - - while (s_read(fd, s.enc, sizeof(s.enc)) == sizeof(s.enc)) { - if (hydro_secretbox_decrypt(&s.x.entry, - s.enc, sizeof(s.enc), 0, - s.ctx_secret, s.x.key)) - continue; - size_t len = strnlen(s.x.entry.msg, sizeof(s.x.entry.msg)); - if (len >= sizeof(s.x.entry.msg)) - s_oops(__LINE__); - s_write(1, s.x.entry.msg, len); - s_write(1, "\n", 1); - } - close(fd); -} - static size_t s_keylen(const char *str) { @@ -273,6 +257,22 @@ s_keylen(const char *str) s_fatal("Keys are limited to %u bytes", S_KEYLENMAX); } +static void +s_print_keys(int use_tty) +{ + int fd = s_open_secret(use_tty); + + while (s_read(fd, s.enc, sizeof(s.enc)) == sizeof(s.enc)) { + if (hydro_secretbox_decrypt(&s.x.entry, + s.enc, sizeof(s.enc), 0, + s.ctx_secret, s.x.key)) + continue; + s_write(1, s.x.entry.msg, s_keylen(s.x.entry.msg)); + s_write(1, "\n", 1); + } + close(fd); +} + static const char * s_get_secret(int fd, const char *key, int create) { @@ -290,6 +290,7 @@ s_get_secret(int fd, const char *key, int create) s_fatal("seek: %s", strerror(errno)); return &s.x.entry.msg[len + 1]; } + s.known_key = 1; } if (!create) s_fatal("Secret %s not found", key); @@ -388,6 +389,13 @@ s_do(int argc, char **argv, void *data) int fd = s_open_secret(1); const char *old = s_get_secret(fd, argv[1], op & s_op_create); + if (!old && !s.known_key) { + char check[sizeof(s.x.key)]; + s_ask_pass(check, sizeof(check), "Never used? Retype to confirm: "); + if (!hydro_equal(s.x.key, check, sizeof(check))) + s_fatal("Passphrases don't match!"); + } + unsigned char secret[S_ENTRYSIZE]; size_t len = S_PWDGENLEN; @@ -398,7 +406,7 @@ s_do(int argc, char **argv, void *data) } else { len = isatty(0) ? s_input(secret, sizeof(secret), "Secret: ") : s_read(0, secret, sizeof(secret)); - if (!len && argc == 3) { + if (!len && old && argc == 3) { len = load16_le(s.x.entry.slen); memcpy(secret, old, len); } @@ -442,7 +450,6 @@ s_pass(int argc, char **argv, void *data) printf("Usage: %s KEY [SUBKEY...]\n", argv[0]); return 0; } - close(s_open_secret(1)); uint8_t buf[hydro_pwhash_MASTERKEYBYTES]; @@ -456,10 +463,8 @@ s_pass(int argc, char **argv, void *data) s.ctx_passwd, key, load64_le(s.hdr.opslimit), 0, 1); memcpy(key, buf, sizeof(key)); - if (r) - s_oops(__LINE__); + if (r) s_oops(__LINE__); } - s_normalize_and_show(buf, S_PWDGENLEN); return 0; } @@ -627,7 +632,6 @@ s_set_path(void) if (ret <= 0 || (size_t)ret >= sizeof(s.path)) s_fatal("Invalid path... Check $HOME or $" S_ENV_STORE); - break; } }