diff --git a/common/hsm_encryption.c b/common/hsm_encryption.c index b88bb1985..d33c0ff56 100644 --- a/common/hsm_encryption.c +++ b/common/hsm_encryption.c @@ -49,6 +49,27 @@ bool encrypt_hsm_secret(const struct secret *encryption_key, return true; } +bool decrypt_hsm_secret(const struct secret *encryption_key, + const struct encrypted_hsm_secret *cipher, + struct secret *output) +{ + crypto_secretstream_xchacha20poly1305_state crypto_state; + + /* The header part */ + if (crypto_secretstream_xchacha20poly1305_init_pull(&crypto_state, cipher->data, + encryption_key->data) != 0) + return false; + /* The ciphertext part */ + if (crypto_secretstream_xchacha20poly1305_pull(&crypto_state, output->data, + NULL, 0, + cipher->data + HS_HEADER_LEN, + HS_CIPHERTEXT_LEN, + NULL, 0) != 0) + return false; + + return true; +} + void discard_key(struct secret *key TAKES) { /* sodium_munlock() also zeroes the memory. */ diff --git a/common/hsm_encryption.h b/common/hsm_encryption.h index 52c9912fb..e620e1d6c 100644 --- a/common/hsm_encryption.h +++ b/common/hsm_encryption.h @@ -38,6 +38,17 @@ bool encrypt_hsm_secret(const struct secret *encryption_key, const struct secret *hsm_secret, struct encrypted_hsm_secret *output); +/** Decrypt the hsm_secret using a previously derived encryption key. + * @encryption_key: the key derived from the passphrase. + * @cipher: the encrypted hsm_secret to decrypt. + * @output: the resulting hsm_secret. + * + * Return false on decryption failure. + */ +bool decrypt_hsm_secret(const struct secret *encryption_key, + const struct encrypted_hsm_secret *cipher, + struct secret *output); + /** Unlock and zeroize the encryption key memory after use. * @key: the encryption key. If taken, it will be tal_free'd */ diff --git a/hsmd/hsmd.c b/hsmd/hsmd.c index da5b363f0..f2d3cfbf6 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -689,25 +689,13 @@ static void load_hsm(const struct secret *encryption_key) /*~ If an encryption key was passed and the `hsm_secret` is stored * encrypted, recover the seed from the cipher. */ if (encryption_key && st.st_size > 32) { - 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]; + struct encrypted_hsm_secret encrypted_secret; - if (!read_all(fd, &header, crypto_secretstream_xchacha20poly1305_HEADERBYTES)) + if (!read_all(fd, encrypted_secret.data, ENCRYPTED_HSM_SECRET_LEN)) status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Reading xchacha20 header: %s", strerror(errno)); - if (!read_all(fd, cipher, sizeof(cipher))) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Reading encrypted secret: %s", strerror(errno)); - if (crypto_secretstream_xchacha20poly1305_init_pull(&crypto_state, header, - encryption_key->data) != 0) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Initializing the crypto state: %s", strerror(errno)); - if (crypto_secretstream_xchacha20poly1305_pull(&crypto_state, - secretstuff.hsm_secret.data, - NULL, 0, cipher, sizeof(cipher), - NULL, 0) != 0) { + "Reading encrypted hsm_secret: %s", strerror(errno)); + if (!decrypt_hsm_secret(encryption_key, &encrypted_secret, + &secretstuff.hsm_secret)) { /* Exit but don't throw a backtrace when the user made a mistake in typing * its password. Instead exit and `lightningd` will be able to give * an error message. */ diff --git a/tools/hsmtool.c b/tools/hsmtool.c index b80744d32..28e072279 100644 --- a/tools/hsmtool.c +++ b/tools/hsmtool.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -91,31 +90,20 @@ static void get_encrypted_hsm_secret(struct secret *hsm_secret, { int fd; struct secret key; + struct encrypted_hsm_secret encrypted_secret; char *err; - 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]; fd = open(hsm_secret_path, O_RDONLY); if (fd < 0) errx(ERROR_HSM_FILE, "Could not open hsm_secret"); - if (!read_all(fd, header, crypto_secretstream_xchacha20poly1305_HEADERBYTES)) - errx(ERROR_HSM_FILE, "Could not read cipher header"); - if (!read_all(fd, cipher, sizeof(cipher))) - errx(ERROR_HSM_FILE, "Could not read cipher body"); + if (!read_all(fd, encrypted_secret.data, ENCRYPTED_HSM_SECRET_LEN)) + errx(ERROR_HSM_FILE, "Could not read encrypted hsm_secret"); err = hsm_secret_encryption_key(passwd, &key); if (err) errx(ERROR_LIBSODIUM, "%s", err); - if (crypto_secretstream_xchacha20poly1305_init_pull(&crypto_state, header, - key.data) != 0) - errx(ERROR_LIBSODIUM, "Could not initialize the crypto state"); - discard_key(&key); - if (crypto_secretstream_xchacha20poly1305_pull(&crypto_state, hsm_secret->data, - NULL, 0, cipher, sizeof(cipher), - NULL, 0) != 0) + if (!decrypt_hsm_secret(&key, &encrypted_secret, hsm_secret)) errx(ERROR_LIBSODIUM, "Could not retrieve the seed. Wrong password ?"); close(fd);