@@ -66,6 +66,7 @@ int bip32_from_seed(bip32_key *key, const unsigned char *seed, size_t seed_len)
6666 memcpy (key -> chain_code , output + BIP32_PRIVKEY_SIZE , BIP32_CHAINCODE_SIZE );
6767
6868exit :
69+ sodium_memzero (output , crypto_auth_hmacsha512_BYTES );
6970 secp256k1_context_destroy (ctx );
7071 return retcode ;
7172}
@@ -164,6 +165,9 @@ int bip32_index_derive(bip32_key *target, const bip32_key *source, uint32_t inde
164165
165166 bip32_hmac_sha512 (output , source -> chain_code , BIP32_CHAINCODE_SIZE , hmac_msg , hmac_msg_len );
166167
168+ // hmac_msg potentially contains privkey bytes.
169+ sodium_memzero (hmac_msg , hmac_msg_len );
170+
167171 memcpy (target -> chain_code , output + BIP32_PRIVKEY_SIZE , BIP32_CHAINCODE_SIZE );
168172
169173 if (source -> is_private ) {
@@ -222,19 +226,6 @@ int bip32_index_derive(bip32_key *target, const bip32_key *source, uint32_t inde
222226 return retcode ;
223227}
224228
225-
226- // Returns true if invalid path characters are detected in a path string.
227- static bool has_invalid_path_characters (const char * str ) {
228- const char * valid = "m/0123456789hH'pP" ;
229- while (* str ) {
230- if (!strchr (valid , * str )) {
231- return true;
232- }
233- str ++ ;
234- }
235- return false;
236- }
237-
238229int bip32_derive_from_str (bip32_key * target , const char * source , const char * path ) {
239230 if (!target || !source || !path || strncmp (path , "m" , 1 ) != 0 ) {
240231 return 0 ;
@@ -250,6 +241,7 @@ int bip32_derive_from_str(bip32_key* target, const char* source, const char* pat
250241 strncmp (source , "xpub" , 4 ) == 0 ||
251242 strncmp (source , "tpub" , 4 ) == 0 ) {
252243 if (!bip32_deserialize (& basekey , source , strlen (source ))) {
244+ sodium_memzero (& basekey , sizeof (bip32_key ));
253245 return 0 ;
254246 }
255247 }
@@ -261,6 +253,7 @@ int bip32_derive_from_str(bip32_key* target, const char* source, const char* pat
261253 return 0 ;
262254 }
263255 if (!bip32_from_seed (& basekey , seedbytes , bin_len )) {
256+ sodium_memzero (& basekey , sizeof (bip32_key ));
264257 return 0 ;
265258 }
266259 } else {
@@ -269,6 +262,7 @@ int bip32_derive_from_str(bip32_key* target, const char* source, const char* pat
269262
270263 if (bip32_derive (& basekey , path )) {
271264 memcpy (target , & basekey , sizeof (bip32_key ));
265+ sodium_memzero (& basekey , sizeof (bip32_key ));
272266 return 1 ;
273267 }
274268 return 0 ;
@@ -284,6 +278,18 @@ int bip32_derive_from_seed(bip32_key* target, const unsigned char* seed, size_t
284278 return 0 ;
285279}
286280
281+ // Returns true if invalid path characters are detected in a path string.
282+ static bool has_invalid_path_characters (const char * str ) {
283+ const char * valid = "m/0123456789hH'pP" ;
284+ while (* str ) {
285+ if (!strchr (valid , * str )) {
286+ return true;
287+ }
288+ str ++ ;
289+ }
290+ return false;
291+ }
292+
287293// Do an in-place derivation on `key`.
288294int bip32_derive (bip32_key * key , const char * path ) {
289295 if (!path || strncmp (path , "m" , 1 ) != 0 || has_invalid_path_characters (path )) {
@@ -314,6 +320,7 @@ int bip32_derive(bip32_key* key, const char* path) {
314320 if (bip32_index_derive (key , & tmp , path_index ) != 1 ) {
315321 return 0 ;
316322 }
323+ sodium_memzero (& tmp , sizeof (bip32_key ));
317324 p = strchr (end , '/' );
318325 }
319326
@@ -323,7 +330,7 @@ int bip32_derive(bip32_key* key, const char* path) {
323330#define SER_SIZE 78
324331#define SER_PLUS_CHECKSUM_SIZE (SER_SIZE + 4)
325332
326- int bip32_serialize (const bip32_key * key , char * str , size_t str_len ) {
333+ int bip32_serialize (const bip32_key * key , char * str , size_t * str_len ) {
327334 unsigned char data [SER_PLUS_CHECKSUM_SIZE ];
328335 uint32_t version ;
329336
@@ -362,7 +369,10 @@ int bip32_serialize(const bip32_key *key, char *str, size_t str_len) {
362369 bip32_sha256_double (hash , data , 78 );
363370 memcpy (data + SER_SIZE , hash , 4 );
364371
365- return b58enc (str , & str_len , data , SER_PLUS_CHECKSUM_SIZE );
372+ bool b58_ok = bip32_b58_encode (str , str_len , data , SER_PLUS_CHECKSUM_SIZE );
373+ sodium_memzero (data , SER_PLUS_CHECKSUM_SIZE );
374+
375+ return b58_ok ? 1 : 0 ;
366376}
367377
368378#define BIP32_BASE58_BYTES_LEN 82
@@ -371,7 +381,8 @@ int bip32_deserialize(bip32_key *key, const char *str, const size_t str_len) {
371381 unsigned char data [BIP32_BASE58_BYTES_LEN ];
372382 size_t data_len = BIP32_BASE58_BYTES_LEN ;
373383
374- if (!b58tobin (data , & data_len , str , str_len ) || data_len != BIP32_BASE58_BYTES_LEN ) {
384+ if (!bip32_b58_decode (data , & data_len , str , str_len ) || data_len != BIP32_BASE58_BYTES_LEN ) {
385+ sodium_memzero (data , BIP32_BASE58_BYTES_LEN );
375386 return 0 ;
376387 }
377388
@@ -426,16 +437,22 @@ int bip32_deserialize(bip32_key *key, const char *str, const size_t str_len) {
426437
427438 if (key -> is_private ) {
428439 if (data [45 ] != 0 ) {
440+ sodium_memzero (data , BIP32_BASE58_BYTES_LEN );
429441 secp256k1_context_destroy (ctx );
430442 return 0 ;
431443 }
444+
432445 memcpy (key -> key .privkey , data + 46 , BIP32_PRIVKEY_SIZE );
446+ sodium_memzero (data , BIP32_BASE58_BYTES_LEN );
447+
433448 if (!secp256k1_ec_seckey_verify (ctx , key -> key .privkey )) {
434449 secp256k1_context_destroy (ctx );
435450 return 0 ;
436451 }
437452 } else {
438453 memcpy (key -> key .pubkey , data + 45 , BIP32_PUBKEY_SIZE );
454+ sodium_memzero (data , BIP32_BASE58_BYTES_LEN );
455+
439456 secp256k1_pubkey pubkey ;
440457 if (!secp256k1_ec_pubkey_parse (ctx , & pubkey , key -> key .pubkey , BIP32_PUBKEY_SIZE )) {
441458 secp256k1_context_destroy (ctx );
@@ -484,3 +501,11 @@ void bip32_hmac_sha512(
484501 crypto_auth_hmacsha512_update (& state , msg , msg_len );
485502 crypto_auth_hmacsha512_final (& state , hmac_out );
486503}
504+
505+ bool bip32_b58_encode (char * str_out , size_t * out_size , const unsigned char * data , size_t data_size ) {
506+ return b58enc (str_out , out_size , data , data_size );
507+ }
508+
509+ bool bip32_b58_decode (unsigned char * bin_out , size_t * out_size , const char * str_in , size_t str_size ) {
510+ return b58tobin (bin_out , out_size , str_in , str_size );
511+ }
0 commit comments