diff --git a/common/hsm_encryption.c b/common/hsm_encryption.c index c9a85f773..b88bb1985 100644 --- a/common/hsm_encryption.c +++ b/common/hsm_encryption.c @@ -1,10 +1,8 @@ #include #include -#include #include #include - char *hsm_secret_encryption_key(const char *pass, struct secret *key) { u8 salt[16] = "c-lightning\0\0\0\0\0"; @@ -31,6 +29,26 @@ char *hsm_secret_encryption_key(const char *pass, struct secret *key) return NULL; } +bool encrypt_hsm_secret(const struct secret *encryption_key, + const struct secret *hsm_secret, + struct encrypted_hsm_secret *output) +{ + crypto_secretstream_xchacha20poly1305_state crypto_state; + + if (crypto_secretstream_xchacha20poly1305_init_push(&crypto_state, output->data, + encryption_key->data) != 0) + return false; + if (crypto_secretstream_xchacha20poly1305_push(&crypto_state, + output->data + HS_HEADER_LEN, + NULL, hsm_secret->data, + sizeof(hsm_secret->data), + /* Additional data and tag */ + 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 ae358c000..52c9912fb 100644 --- a/common/hsm_encryption.h +++ b/common/hsm_encryption.h @@ -4,7 +4,20 @@ #include #include #include +#include +/* Length of the encrypted hsm secret header. */ +#define HS_HEADER_LEN crypto_secretstream_xchacha20poly1305_HEADERBYTES +/* From libsodium: "The ciphertext length is guaranteed to always be message + * length + ABYTES" */ +#define HS_CIPHERTEXT_LEN \ + (sizeof(struct secret) + crypto_secretstream_xchacha20poly1305_ABYTES) +/* Total length of an encrypted hsm_secret */ +#define ENCRYPTED_HSM_SECRET_LEN (HS_HEADER_LEN + HS_CIPHERTEXT_LEN) + +struct encrypted_hsm_secret { + u8 data[ENCRYPTED_HSM_SECRET_LEN]; +}; /** Derive the hsm_secret encryption key from a passphrase. * @pass: the passphrase string. @@ -14,6 +27,17 @@ */ char *hsm_secret_encryption_key(const char *pass, struct secret *encryption_key); +/** Encrypt the hsm_secret using a previously derived encryption key. + * @encryption_key: the key derived from the passphrase. + * @hsm_secret: the plaintext hsm_secret to encrypt. + * @output: the resulting encrypted hsm_secret. + * + * Return false on encryption failure. + */ +bool encrypt_hsm_secret(const struct secret *encryption_key, + const struct secret *hsm_secret, + struct encrypted_hsm_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 d7dfd7bef..da5b363f0 100644 --- a/hsmd/hsmd.c +++ b/hsmd/hsmd.c @@ -563,28 +563,16 @@ static void bitcoin_key(struct privkey *privkey, struct pubkey *pubkey, */ static void create_encrypted_hsm(int fd, const struct secret *encryption_key) { - 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]; - - crypto_secretstream_xchacha20poly1305_init_push(&crypto_state, header, - encryption_key->data); - crypto_secretstream_xchacha20poly1305_push(&crypto_state, cipher, - NULL, - secretstuff.hsm_secret.data, - sizeof(secretstuff.hsm_secret.data), - /* Additional data and tag */ - NULL, 0, 0); - if (!write_all(fd, header, sizeof(header))) { - unlink_noerr("hsm_secret"); + struct encrypted_hsm_secret cipher; + + if (!encrypt_hsm_secret(encryption_key, &secretstuff.hsm_secret, + &cipher)) status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Writing header of encrypted secret: %s", strerror(errno)); - } - if (!write_all(fd, cipher, sizeof(cipher))) { + "Encrypting hsm_secret"); + if (!write_all(fd, cipher.data, ENCRYPTED_HSM_SECRET_LEN)) { unlink_noerr("hsm_secret"); status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Writing encrypted secret: %s", strerror(errno)); + "Writing encrypted hsm_secret: %s", strerror(errno)); } } diff --git a/tools/hsmtool.c b/tools/hsmtool.c index 14f3e4679..b80744d32 100644 --- a/tools/hsmtool.c +++ b/tools/hsmtool.c @@ -227,11 +227,8 @@ static int encrypt_hsm(const char *hsm_secret_path) { int fd; struct secret key, hsm_secret; + struct encrypted_hsm_secret encrypted_hsm_secret; char *passwd, *passwd_confirmation, *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]; const char *dir, *backup; /* This checks the file existence, too. */ @@ -264,15 +261,8 @@ static int encrypt_hsm(const char *hsm_secret_path) err = hsm_secret_encryption_key(passwd, &key); if (err) errx(ERROR_LIBSODIUM, "%s", err); - if (crypto_secretstream_xchacha20poly1305_init_push(&crypto_state, header, - key.data) != 0) - errx(ERROR_LIBSODIUM, "Could not initialize the crypto state"); - discard_key(&key); - if (crypto_secretstream_xchacha20poly1305_push(&crypto_state, cipher, - NULL, hsm_secret.data, - sizeof(hsm_secret.data), - NULL, 0, 0) != 0) - errx(ERROR_LIBSODIUM, "Could not encrypt the seed."); + if (!encrypt_hsm_secret(&key, &hsm_secret, &encrypted_hsm_secret)) + errx(ERROR_LIBSODIUM, "Could not encrypt the hsm_secret seed."); /* Once the encryption key derived, we don't need it anymore. */ free(passwd); @@ -285,8 +275,8 @@ static int encrypt_hsm(const char *hsm_secret_path) errx(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))) { + if (!write_all(fd, encrypted_hsm_secret.data, + sizeof(encrypted_hsm_secret.data))) { unlink_noerr(hsm_secret_path); close(fd); rename(backup, hsm_secret_path);