11#include "config.h"
2+ #include <ccan/crypto/sha256/sha256.h>
3+ #include <ccan/mem/mem.h>
24#include <ccan/tal/str/str.h>
35#include <ccan/tal/tal.h>
46#include <common/errcode.h>
5- #include <common/utils.h>
67#include <common/hsm_secret.h>
8+ #include <common/utils.h>
79#include <errno.h>
10+ #include <sodium.h>
11+ #include <sys/stat.h>
812#include <termios.h>
913#include <unistd.h>
10- #include <ccan/crypto/sha256/sha256.h>
11- #include <ccan/mem/mem.h>
12- #include <sodium.h>
13- #include <wally_bip39.h>
14- #include <sys/stat.h>
14+ #include <wally_bip39.h>
1515
1616/* Length of the encrypted hsm secret header. */
1717#define HS_HEADER_LEN crypto_secretstream_xchacha20poly1305_HEADERBYTES
@@ -70,11 +70,15 @@ bool hsm_secret_needs_passphrase(const u8 *hsm_secret, size_t len)
7070 case HSM_SECRET_INVALID :
7171 return false;
7272 }
73- return false ;
73+ abort () ;
7474}
7575
7676enum hsm_secret_type detect_hsm_secret_type (const u8 * hsm_secret , size_t len )
7777{
78+ /* Check for invalid cases first and return early */
79+ if (len < HSM_SECRET_PLAIN_SIZE )
80+ return HSM_SECRET_INVALID ;
81+
7882 /* Legacy 32-byte plain format */
7983 if (len == HSM_SECRET_PLAIN_SIZE )
8084 return HSM_SECRET_PLAIN ;
@@ -84,20 +88,29 @@ enum hsm_secret_type detect_hsm_secret_type(const u8 *hsm_secret, size_t len)
8488 return HSM_SECRET_ENCRYPTED ;
8589
8690 /* Check if it starts with our type bytes (mnemonic formats) */
87- if (len > 32 ) {
88- if (memeqzero (hsm_secret , 32 ))
89- return HSM_SECRET_MNEMONIC_NO_PASS ;
90- else
91- return HSM_SECRET_MNEMONIC_WITH_PASS ;
92- }
93- return HSM_SECRET_INVALID ;
91+ if (memeqzero (hsm_secret , 32 ))
92+ return HSM_SECRET_MNEMONIC_NO_PASS ;
93+ else
94+ return HSM_SECRET_MNEMONIC_WITH_PASS ;
9495}
9596
96- static void hash_passphrase (const char * passphrase , u8 hash [PASSPHRASE_HASH_LEN ])
97+ /* Helper function to derive seed hash from mnemonic + passphrase */
98+ bool derive_seed_hash (const char * mnemonic , const char * passphrase , struct sha256 * seed_hash )
9799{
98- struct sha256 sha ;
99- sha256 (& sha , passphrase , strlen (passphrase ));
100- memcpy (hash , sha .u .u8 , PASSPHRASE_HASH_LEN );
100+ if (!passphrase ) {
101+ /* No passphrase - return zero hash */
102+ memset (seed_hash , 0 , sizeof (* seed_hash ));
103+ return true;
104+ }
105+
106+ u8 bip32_seed [BIP39_SEED_LEN_512 ];
107+ size_t bip32_seed_len ;
108+
109+ if (bip39_mnemonic_to_seed (mnemonic , passphrase , bip32_seed , sizeof (bip32_seed ), & bip32_seed_len ) != WALLY_OK )
110+ return false;
111+
112+ sha256 (seed_hash , bip32_seed , sizeof (bip32_seed ));
113+ return true;
101114}
102115
103116/* Validate the passphrase for a mnemonic secret */
@@ -108,28 +121,33 @@ bool validate_mnemonic_passphrase(const u8 *hsm_secret, size_t len, const char *
108121 if (type != HSM_SECRET_MNEMONIC_WITH_PASS )
109122 return true; /* No validation needed */
110123
111- /* First 32 bytes are the stored passphrase hash */
112- const u8 * stored_hash = hsm_secret ;
113- u8 computed_hash [32 ];
124+ /* First 32 bytes are the stored seed hash */
125+ const struct sha256 * stored_hash = (const struct sha256 * )hsm_secret ;
126+ struct sha256 computed_hash ;
127+
128+ /* Extract mnemonic portion (skip first 32 bytes which are seed hash) */
129+ const char * mnemonic_start = (const char * )(hsm_secret + sizeof (struct sha256 ));
114130
115- hash_passphrase (passphrase , computed_hash );
116- return memcmp (stored_hash , computed_hash , 32 ) == 0 ;
131+ if (!derive_seed_hash (mnemonic_start , passphrase , & computed_hash ))
132+ return false;
133+
134+ return sha256_eq (stored_hash , & computed_hash );
117135}
118136
119137static bool decrypt_hsm_secret (const struct secret * encryption_key ,
120- const struct encrypted_hsm_secret * cipher ,
138+ const u8 * cipher ,
121139 struct secret * output )
122140{
123141 crypto_secretstream_xchacha20poly1305_state crypto_state ;
124142
125143 /* The header part */
126- if (crypto_secretstream_xchacha20poly1305_init_pull (& crypto_state , cipher -> data ,
144+ if (crypto_secretstream_xchacha20poly1305_init_pull (& crypto_state , cipher ,
127145 encryption_key -> data ) != 0 )
128146 return false;
129147 /* The ciphertext part */
130148 if (crypto_secretstream_xchacha20poly1305_pull (& crypto_state , output -> data ,
131149 NULL , 0 ,
132- cipher -> data + HS_HEADER_LEN ,
150+ cipher + HS_HEADER_LEN ,
133151 HS_CIPHERTEXT_LEN ,
134152 NULL , 0 ) != 0 )
135153 return false;
@@ -166,6 +184,7 @@ const char *hsm_secret_error_str(enum hsm_secret_error err)
166184 }
167185 return "Unknown error" ;
168186}
187+
169188static struct hsm_secret * extract_plain_secret (const tal_t * ctx ,
170189 const u8 * hsm_secret ,
171190 size_t len ,
@@ -180,6 +199,7 @@ static struct hsm_secret *extract_plain_secret(const tal_t *ctx,
180199 * err = HSM_SECRET_OK ;
181200 return hsms ;
182201}
202+
183203static struct hsm_secret * extract_encrypted_secret (const tal_t * ctx ,
184204 const u8 * hsm_secret ,
185205 size_t len ,
@@ -204,7 +224,7 @@ static struct hsm_secret *extract_encrypted_secret(const tal_t *ctx,
204224 memset (& hsms -> secret , 0 , sizeof (hsms -> secret ));
205225
206226 /* Attempt decryption */
207- decrypt_success = decrypt_hsm_secret (encryption_key , ( const struct encrypted_hsm_secret * ) hsm_secret , & hsms -> secret );
227+ decrypt_success = decrypt_hsm_secret (encryption_key , hsm_secret , & hsms -> secret );
208228
209229 /* Clear encryption key immediately after use */
210230 discard_key (encryption_key );
@@ -317,15 +337,15 @@ struct hsm_secret *extract_hsm_secret(const tal_t *ctx,
317337
318338bool encrypt_legacy_hsm_secret (const struct secret * encryption_key ,
319339 const struct secret * hsm_secret ,
320- struct encrypted_hsm_secret * output )
340+ u8 * output )
321341{
322342 crypto_secretstream_xchacha20poly1305_state crypto_state ;
323343
324- if (crypto_secretstream_xchacha20poly1305_init_push (& crypto_state , output -> data ,
344+ if (crypto_secretstream_xchacha20poly1305_init_push (& crypto_state , output ,
325345 encryption_key -> data ) != 0 )
326346 return false;
327347 if (crypto_secretstream_xchacha20poly1305_push (& crypto_state ,
328- output -> data + HS_HEADER_LEN ,
348+ output + HS_HEADER_LEN ,
329349 NULL , hsm_secret -> data ,
330350 sizeof (hsm_secret -> data ),
331351 /* Additional data and tag */
0 commit comments