From dccad7784f3e248019f7e0f06f83a50053d1597a Mon Sep 17 00:00:00 2001 From: darosior Date: Sat, 19 Oct 2019 16:55:51 +0200 Subject: [PATCH] tools/hsmtool: add a tool for encrypting hsm_secret --- tools/hsmtool.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/tools/hsmtool.c b/tools/hsmtool.c index ac5d6d23c..4be37a821 100644 --- a/tools/hsmtool.c +++ b/tools/hsmtool.c @@ -1,9 +1,9 @@ #include -#include #include #include #include #include +#include #include #include #include @@ -20,6 +20,7 @@ static void show_usage(void) printf("./hsmtool [arguments]\n"); printf("methods:\n"); printf(" - decrypt \n"); + printf(" - encrypt \n"); exit(0); } @@ -117,6 +118,75 @@ static int decrypt_hsm(const char *hsm_secret_path, const char *passwd) return 0; } +static int encrypt_hsm(const char *hsm_secret_path, const char *passwd) +{ + int fd; + struct stat st; + struct secret key, hsm_secret; + u8 salt[16] = "c-lightning\0\0\0\0\0"; + crypto_secretstream_xchacha20poly1305_state crypto_state; + u8 header[crypto_secretstream_xchacha20poly1305_HEADERBYTES]; + /* The cipher size is static with xchacha20poly1305. */ + u8 cipher[sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES]; + + if (sodium_init() == -1) + err(ERROR_LIBSODIUM, + "Could not initialize libsodium. Not enough entropy ?"); + + if (stat(hsm_secret_path, &st) != 0) + err(ERROR_HSM_FILE, "Could not stat hsm_secret"); + if (st.st_size > 32) + err(ERROR_USAGE, "hsm_secret is already encrypted"); + fd = open(hsm_secret_path, O_RDONLY); + if (fd < 0) + err(ERROR_HSM_FILE, "Could not open hsm_secret"); + if (!read_all(fd, &hsm_secret, sizeof(hsm_secret))) + err(ERROR_HSM_FILE, "Could not read hsm_secret"); + + /* Derive the encryption key from the password provided, and try to encrypt + * the seed. */ + if (crypto_pwhash(key.data, sizeof(key.data), passwd, strlen(passwd), salt, + crypto_pwhash_argon2id_OPSLIMIT_MODERATE, + crypto_pwhash_argon2id_MEMLIMIT_MODERATE, + crypto_pwhash_ALG_ARGON2ID13) != 0) + err(ERROR_LIBSODIUM, "Could not derive a key from the password."); + if (crypto_secretstream_xchacha20poly1305_init_push(&crypto_state, header, + key.data) != 0) + err(ERROR_LIBSODIUM, "Could not initialize the crypto state"); + if (crypto_secretstream_xchacha20poly1305_push(&crypto_state, cipher, + NULL, hsm_secret.data, + sizeof(hsm_secret.data), + NULL, 0, 0) != 0) + err(ERROR_LIBSODIUM, "Could not encrypt the seed."); + + /* Create a backup file, "just in case". */ + rename(hsm_secret_path, "hsm_secret.backup"); + fd = open(hsm_secret_path, O_CREAT|O_EXCL|O_WRONLY, 0400); + if (fd < 0) + err(ERROR_HSM_FILE, "Could not open new hsm_secret"); + + /* Write the encrypted hsm_secret. */ + if (!write_all(fd, header, sizeof(header)) + || !write_all(fd, cipher, sizeof(cipher))) { + unlink_noerr(hsm_secret_path); + close(fd); + rename("hsm_secret.backup", hsm_secret_path); + err(ERROR_HSM_FILE, "Failure writing cipher to hsm_secret."); + } + + /* Be as paranoïd as in hsmd with the file state on disk. */ + if (!ensure_hsm_secret_exists(fd, hsm_secret_path)) { + unlink_noerr(hsm_secret_path); + rename("hsm_secret.backup", hsm_secret_path); + err(ERROR_HSM_FILE, "Could not ensure hsm_secret existence."); + } + unlink_noerr("hsm_secret.backup"); + + printf("Succesfully encrypted hsm_secret. You'll now have to pass the " + "--encrypted-hsm startup option.\n"); + return 0; +} + int main(int argc, char *argv[]) { const char *method; @@ -134,5 +204,11 @@ int main(int argc, char *argv[]) return decrypt_hsm(argv[2], argv[3]); } + if (streq(method, "encrypt")) { + if (!argv[2] || !argv[3]) + show_usage(); + return encrypt_hsm(argv[2], argv[3]); + } + show_usage(); }