1
1
#include "config.h"
2
+ #include <ccan/crypto/sha256/sha256.h>
3
+ #include <ccan/mem/mem.h>
2
4
#include <ccan/tal/str/str.h>
3
5
#include <ccan/tal/tal.h>
4
6
#include <common/errcode.h>
5
- #include <common/utils.h>
6
7
#include <common/hsm_secret.h>
8
+ #include <common/utils.h>
7
9
#include <errno.h>
10
+ #include <sodium.h>
11
+ #include <sys/stat.h>
8
12
#include <termios.h>
9
13
#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>
15
15
16
16
/* Length of the encrypted hsm secret header. */
17
17
#define HS_HEADER_LEN crypto_secretstream_xchacha20poly1305_HEADERBYTES
@@ -70,11 +70,15 @@ bool hsm_secret_needs_passphrase(const u8 *hsm_secret, size_t len)
70
70
case HSM_SECRET_INVALID :
71
71
return false;
72
72
}
73
- return false ;
73
+ abort () ;
74
74
}
75
75
76
76
enum hsm_secret_type detect_hsm_secret_type (const u8 * hsm_secret , size_t len )
77
77
{
78
+ /* Check for invalid cases first and return early */
79
+ if (len < HSM_SECRET_PLAIN_SIZE )
80
+ return HSM_SECRET_INVALID ;
81
+
78
82
/* Legacy 32-byte plain format */
79
83
if (len == HSM_SECRET_PLAIN_SIZE )
80
84
return HSM_SECRET_PLAIN ;
@@ -84,20 +88,29 @@ enum hsm_secret_type detect_hsm_secret_type(const u8 *hsm_secret, size_t len)
84
88
return HSM_SECRET_ENCRYPTED ;
85
89
86
90
/* 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 ;
94
95
}
95
96
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 )
97
99
{
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;
101
114
}
102
115
103
116
/* Validate the passphrase for a mnemonic secret */
@@ -108,28 +121,34 @@ bool validate_mnemonic_passphrase(const u8 *hsm_secret, size_t len, const char *
108
121
if (type != HSM_SECRET_MNEMONIC_WITH_PASS )
109
122
return true; /* No validation needed */
110
123
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 ));
130
+ size_t mnemonic_len = len - sizeof (struct sha256 );
114
131
115
- hash_passphrase (passphrase , computed_hash );
116
- return memcmp (stored_hash , computed_hash , 32 ) == 0 ;
132
+ if (!derive_seed_hash (mnemonic_start , passphrase , & computed_hash ))
133
+ return false;
134
+
135
+ return sha256_eq (stored_hash , & computed_hash );
117
136
}
118
137
119
138
static bool decrypt_hsm_secret (const struct secret * encryption_key ,
120
- const struct encrypted_hsm_secret * cipher ,
139
+ const u8 * cipher ,
121
140
struct secret * output )
122
141
{
123
142
crypto_secretstream_xchacha20poly1305_state crypto_state ;
124
143
125
144
/* The header part */
126
- if (crypto_secretstream_xchacha20poly1305_init_pull (& crypto_state , cipher -> data ,
145
+ if (crypto_secretstream_xchacha20poly1305_init_pull (& crypto_state , cipher ,
127
146
encryption_key -> data ) != 0 )
128
147
return false;
129
148
/* The ciphertext part */
130
149
if (crypto_secretstream_xchacha20poly1305_pull (& crypto_state , output -> data ,
131
150
NULL , 0 ,
132
- cipher -> data + HS_HEADER_LEN ,
151
+ cipher + HS_HEADER_LEN ,
133
152
HS_CIPHERTEXT_LEN ,
134
153
NULL , 0 ) != 0 )
135
154
return false;
@@ -166,6 +185,7 @@ const char *hsm_secret_error_str(enum hsm_secret_error err)
166
185
}
167
186
return "Unknown error" ;
168
187
}
188
+
169
189
static struct hsm_secret * extract_plain_secret (const tal_t * ctx ,
170
190
const u8 * hsm_secret ,
171
191
size_t len ,
@@ -180,6 +200,7 @@ static struct hsm_secret *extract_plain_secret(const tal_t *ctx,
180
200
* err = HSM_SECRET_OK ;
181
201
return hsms ;
182
202
}
203
+
183
204
static struct hsm_secret * extract_encrypted_secret (const tal_t * ctx ,
184
205
const u8 * hsm_secret ,
185
206
size_t len ,
@@ -204,7 +225,7 @@ static struct hsm_secret *extract_encrypted_secret(const tal_t *ctx,
204
225
memset (& hsms -> secret , 0 , sizeof (hsms -> secret ));
205
226
206
227
/* Attempt decryption */
207
- decrypt_success = decrypt_hsm_secret (encryption_key , ( const struct encrypted_hsm_secret * ) hsm_secret , & hsms -> secret );
228
+ decrypt_success = decrypt_hsm_secret (encryption_key , hsm_secret , & hsms -> secret );
208
229
209
230
/* Clear encryption key immediately after use */
210
231
discard_key (encryption_key );
@@ -317,15 +338,15 @@ struct hsm_secret *extract_hsm_secret(const tal_t *ctx,
317
338
318
339
bool encrypt_legacy_hsm_secret (const struct secret * encryption_key ,
319
340
const struct secret * hsm_secret ,
320
- struct encrypted_hsm_secret * output )
341
+ u8 * output )
321
342
{
322
343
crypto_secretstream_xchacha20poly1305_state crypto_state ;
323
344
324
- if (crypto_secretstream_xchacha20poly1305_init_push (& crypto_state , output -> data ,
345
+ if (crypto_secretstream_xchacha20poly1305_init_push (& crypto_state , output ,
325
346
encryption_key -> data ) != 0 )
326
347
return false;
327
348
if (crypto_secretstream_xchacha20poly1305_push (& crypto_state ,
328
- output -> data + HS_HEADER_LEN ,
349
+ output + HS_HEADER_LEN ,
329
350
NULL , hsm_secret -> data ,
330
351
sizeof (hsm_secret -> data ),
331
352
/* Additional data and tag */
0 commit comments