commit db16ad84d951cf2f79a35f7bb675092d0115a601
parent b57aebdaa7e467592af1ee1608bd3892da112a3e
Author: Nihal Jere <nihal@nihaljere.xyz>
Date: Fri, 30 Jul 2021 10:00:39 -0500
npwm: rewrite
Diffstat:
M | common.h | | | 9 | ++++++--- |
M | npwm.c | | | 202 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------- |
2 files changed, 151 insertions(+), 60 deletions(-)
diff --git a/common.h b/common.h
@@ -1,10 +1,13 @@
-#define PASSWORD_MAX_LEN 512
+#define PASSWORD_MAX_LEN 511
#define PASSPHRASE_MAX_LEN 512
#define KEY_LEN 32
#define NONCE_LEN 12
#define SALT_LEN 8
-#define ROUNDS 2000
-#define DEFAULT_LEN 40
+
+// Argon2 parameters
+#define T_COST 250
+#define M_COST 2*1024 // 2 mibibytes
+#define PARALLELISM 1
#if SALT_LEN == 0 || SALT_LEN > SIZE_MAX - 4
#error Invalid salt size
diff --git a/npwm.c b/npwm.c
@@ -10,68 +10,156 @@
#include "chacha20.h"
#include "common.h"
-#include "pkcs5_pbkdf2.h"
+#include "argon2/argon2.h"
#include "util.h"
-int main(int argc, char *argv[]) {
- char encrypted[SALT_LEN + PASSWORD_MAX_LEN];
- char key[KEY_LEN];
- char nonce[NONCE_LEN];
- char salt[SALT_LEN];
- char *c;
- size_t len;
-
- /* TODO add usage */
- if (argc != 3)
- die("invalid args");
-
- if (strcmp(argv[1], "-e") == 0) {
- if (getrandom(salt, SALT_LEN, 0) < SALT_LEN)
- die("failed to generate salt");
-
- if (pkcs5_pbkdf2(argv[2], strlen(argv[2]), salt, SALT_LEN, key,
- KEY_LEN, ROUNDS) == -1)
- die("key derivation failed");
-
- if (getrandom(nonce, NONCE_LEN, 0) < NONCE_LEN)
- die("failed to generate nonce");
-
- errno = 0;
-
- memcpy(encrypted, salt, SALT_LEN);
- memset(encrypted + SALT_LEN, 0, PASSWORD_MAX_LEN);
-
- fgets(encrypted + SALT_LEN, PASSWORD_MAX_LEN, stdin);
- if ((c = strchr(encrypted + SALT_LEN, '\n')) == NULL)
- die("password is too long");
-
- *c = 0;
- len = c - encrypted - SALT_LEN + 1;
-
- br_chacha20_ct_run(key, nonce, 0, encrypted, SALT_LEN + len);
-
- fwrite(nonce, sizeof(char), NONCE_LEN, stdout);
- fwrite(salt, sizeof(char), SALT_LEN, stdout);
- fwrite(encrypted, sizeof(char), SALT_LEN + len, stdout);
- } else if (strcmp(argv[1], "-d") == 0) {
- if (fread(nonce, sizeof(char), NONCE_LEN, stdin) < NONCE_LEN)
- die("failed to read nonce");
-
- if (fread(salt, sizeof(char), SALT_LEN, stdin) < SALT_LEN)
- die("failed to read salt");
+char *argv0;
+
+char data[SALT_LEN + PASSWORD_MAX_LEN + 1];
+char encryptee[PASSWORD_MAX_LEN];
+char encryptor[PASSWORD_MAX_LEN+1];
+char key[KEY_LEN];
+char nonce[NONCE_LEN];
+char salt[SALT_LEN];
+
+void
+clear()
+{
+ memset(data, 0, sizeof(data));
+ memset(encryptee, 0, sizeof(encryptee));
+ memset(encryptor, 0, sizeof(encryptor));
+ memset(key, 0, sizeof(key));
+ memset(nonce, 0, sizeof(nonce));
+ memset(salt, 0, sizeof(salt));
+}
- len = fread(encrypted, sizeof(char), SALT_LEN + PASSWORD_MAX_LEN,
- stdin) - SALT_LEN - 1;
+ssize_t
+get_password(char *buf)
+{
+ fgets(buf, PASSWORD_MAX_LEN+1, stdin);
+ // XXX: is strlen problematic because it isn't constant time and acts on a secret?
+ size_t len = strlen(buf);
- if (pkcs5_pbkdf2(argv[2], strlen(argv[2]), salt, SALT_LEN, key,
- KEY_LEN, ROUNDS) == -1)
- die("key derivation failed");
+ /* the last character of the line should be '\n', which should not be
+ * included in the password */
+ if (len == PASSWORD_MAX_LEN && buf[PASSWORD_MAX_LEN-1] != '\n')
+ return -1;
- br_chacha20_ct_run(key, nonce, 0, encrypted, SALT_LEN + len);
+ buf[len-1] = '\0';
+ return len - 1;
+}
- if (memcmp(encrypted, salt, SALT_LEN) != 0)
- die("invalid input!");
+void
+error(const char *s)
+{
+ fprintf(stderr, "%s: %s\n", argv0, s);
+}
- fwrite(encrypted + SALT_LEN, sizeof(char), len, stdout);
- }
+int main(int argc, char *argv[]) {
+ char *c;
+ size_t len;
+ FILE *file = NULL;
+
+ /* TODO add usage */
+ if (argc == 2 && strcmp(argv[1], "-e"))
+ die("invalid args");
+
+ if (argc == 3 && strcmp(argv[1], "-d"))
+ die("invalid args");
+
+ if (argc < 2)
+ die("invalid args");
+
+ argv0 = argv[0];
+
+ if (strcmp(argv[1], "-e") == 0) {
+ if (getrandom(salt, SALT_LEN, 0) < SALT_LEN) {
+ error("failed to generate salt");
+ goto fail;
+ }
+
+ len = get_password(encryptor);
+ if (len < 0) {
+ error("master password too long");
+ goto fail;
+ }
+
+ if (argon2id_hash_raw(T_COST, M_COST, PARALLELISM, encryptor, len, salt, SALT_LEN, key, KEY_LEN) < 0) {
+ error("key derivation failed");
+ goto fail;
+ }
+
+ if (getrandom(nonce, NONCE_LEN, 0) < NONCE_LEN) {
+ error("failed to generate nonce");
+ goto fail;
+ }
+
+ memcpy(data, salt, SALT_LEN);
+
+ len = get_password(encryptee);
+ if (len < 0) {
+ error("password to encrypt is too long");
+ goto fail;
+ }
+
+ memset(data, 0, SALT_LEN + PASSWORD_MAX_LEN);
+ memcpy(data, salt, SALT_LEN);
+ memcpy(data + SALT_LEN, encryptee, PASSWORD_MAX_LEN);
+
+ br_chacha20_ct_run(key, nonce, 0, data, SALT_LEN + PASSWORD_MAX_LEN);
+
+ fwrite(nonce, sizeof(char), NONCE_LEN, stdout);
+ fwrite(salt, sizeof(char), SALT_LEN, stdout);
+ fwrite(data, sizeof(char), SALT_LEN + PASSWORD_MAX_LEN, stdout);
+ } else if (strcmp(argv[1], "-d") == 0) {
+ file = fopen(argv[2], "r");
+ if (file == NULL) {
+ error("failed to open file");
+ goto fail;
+ }
+
+ len = fread(nonce, sizeof(char), NONCE_LEN, file);
+ if (len < NONCE_LEN) {
+ error("failed to read nonce");
+ goto fail;
+ }
+
+ len = fread(salt, sizeof(char), SALT_LEN, file);
+ if (len < SALT_LEN) {
+ error("failed to read salt");
+ goto fail;
+ }
+
+ len = fread(data, sizeof(char), SALT_LEN + PASSWORD_MAX_LEN, file);
+ if (len < SALT_LEN + PASSWORD_MAX_LEN) {
+ error("failed to read encrypted data");
+ goto fail;
+ }
+
+ len = get_password(encryptor);
+
+ if (argon2id_hash_raw(T_COST, M_COST, PARALLELISM, encryptor, len, salt, SALT_LEN, key, KEY_LEN) < 0) {
+ error("key derivation failed");
+ goto fail;
+ }
+
+ br_chacha20_ct_run(key, nonce, 0, data, SALT_LEN + PASSWORD_MAX_LEN);
+
+ if (memcmp(data, salt, SALT_LEN) != 0) {
+ error("incorrect master password");
+ goto fail;
+ }
+
+ puts(data + SALT_LEN);
+ fclose(file);
+ }
+
+ clear();
+ return 0;
+
+fail:
+ if (file)
+ fclose(file);
+ clear();
+ return 1;
}