npm

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/npm
Log | Files | Refs

commit db16ad84d951cf2f79a35f7bb675092d0115a601
parent b57aebdaa7e467592af1ee1608bd3892da112a3e
Author: Nihal Jere <nihal@nihaljere.xyz>
Date:   Fri, 30 Jul 2021 10:00:39 -0500

npwm: rewrite

Diffstat:
Mcommon.h | 9++++++---
Mnpwm.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; }