Skip to content

Add support for mnemonics in hsm_secret #8400

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

sangbida
Copy link
Collaborator

@sangbida sangbida commented Jul 8, 2025

Important

25.09 FREEZE July 28TH: Non-bugfix PRs not ready by this date will wait for 25.12.

RC1 is scheduled on August 11th

The final release is scheduled for September 1st.

Checklist

Before submitting the PR, ensure the following tasks are completed. If an item is not applicable to your PR, please mark it as checked:

  • The changelog has been updated in the relevant commit(s) according to the guidelines.
  • Tests have been added or modified to reflect the changes.
  • Documentation has been reviewed and updated as needed.
  • Related issues have been listed and linked, including any that this PR closes.

Comment on lines 2 to 16
#include <ccan/tal/str/str.h>
#include <ccan/tal/tal.h>
#include <common/errcode.h>
#include <common/utils.h>
#include <common/hsm_secret.h>
#include <errno.h>
#include <termios.h>
#include <unistd.h>
#include <ccan/crypto/sha256/sha256.h>
#include <ccan/mem/mem.h>
#include <sodium.h>
#include <wally_bip39.h>
#include <sys/stat.h>

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These need to be in alphabetical order!

case HSM_SECRET_INVALID:
return false;
}
return false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

abort()

return HSM_SECRET_ENCRYPTED;

/* Check if it starts with our type bytes (mnemonic formats) */
if (len > 32) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if (len < 32)
return HSM_SECRET_INVALID;

Comment on lines 96 to 101
static void hash_passphrase(const char *passphrase, u8 hash[PASSPHRASE_HASH_LEN])
{
struct sha256 sha;
sha256(&sha, passphrase, strlen(passphrase));
memcpy(hash, sha.u.u8, PASSPHRASE_HASH_LEN);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have a sha256 type for a reason, let's use it, not convert to u8[]

Comment on lines 111 to 133
/* First 32 bytes are the stored passphrase hash */
const u8 *stored_hash = hsm_secret;
u8 computed_hash[32];

hash_passphrase(passphrase, computed_hash);
return memcmp(stored_hash, computed_hash, 32) == 0;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

struct sha256 actual, expected;

/* First 32 bytes are the stored passphrase hash */
memcpy(&expected, hsm_secret, sizeof(struct sha256));
sha256(&actual, passphrase, strlen(passphrase));

return sha256_eq(&expected, &actual);

Comment on lines +418 to +419
if (strlen(passphrase) == 0) {
passphrase = NULL;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mildly prefer if (streq(passphrase, "")) ?

if (bip39_mnemonic_to_seed(mnemonic, passphrase, bip32_seed, sizeof(bip32_seed), &bip32_seed_len) != WALLY_OK)
errx(ERROR_LIBWALLY, "Unable to derive BIP32 seed from BIP39 mnemonic");

/* Write to file using your new mnemonic format */
int fd = open(hsm_secret_path, O_CREAT|O_EXCL|O_WRONLY, 0400);
if (fd < 0) {
errx(ERROR_USAGE, "Unable to create hsm_secret file");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err() not errx()

tools/hsmtool.c Outdated
sha256(&sha, passphrase, strlen(passphrase));

if (!write_all(fd, sha.u.u8, PASSPHRASE_HASH_LEN))
errx(ERROR_USAGE, "Error writing passphrase hash to hsm_secret file");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err...

tools/hsmtool.c Outdated
if (passphrase) {
/* Write passphrase hash (32 bytes) + mnemonic for protected format */
struct sha256 sha;
sha256(&sha, passphrase, strlen(passphrase));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be hash of the final seed. This is a bit trickier: we need hsm_secret to expose that "calculate seed from mnemonic and passphrase" function (or opencode it with libwally?)

Comment on lines -562 to -566
u8 bip32_seed[BIP39_SEED_LEN_512];
size_t bip32_seed_len;

if (bip39_mnemonic_to_seed(mnemonic, passphrase, bip32_seed, sizeof(bip32_seed), &bip32_seed_len) != WALLY_OK)
errx(ERROR_LIBWALLY, "Unable to derive BIP32 seed from BIP39 mnemonic");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need this for below.,

@sangbida sangbida force-pushed the bip39-hsm branch 2 times, most recently from 5de3e77 to 1ae8dc0 Compare July 17, 2025 05:15
sangbida added 3 commits July 23, 2025 16:08
This is a newer API to replace hsm_encryption.c and hsm_encryption.c, this tidies up the API to be used and also cleans things up to support our new formts. Our hsm_secret formats now include:
- Legacy 32-byte plain format
- Legacy 73-byte encrypted format
- New mnemonic format without passphrase (32 zero bytes + mnemonic)
- New mnemonic format with passphrase (32-byte hash + mnemonic)

This commit includes support to detect the format based on the file size and content structure. The hsm will store mnemonics in the hsm_secret file as:

`passphraseHash`mnemonic`
Changelog-Added: `hsmtool` now supports hsm_secret files using a 12-word mnemonic.
In preparation for BIP-39, we need to hand the passphrase (if any) to HSMD.

So we extend the hsmd wire protocol to allow that.
sangbida added 2 commits July 24, 2025 15:27
Changelog-Changed: hsmd: New nodes will now be created with a BIP-39 12-word phrase as their root secret.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants