1
1
use crate :: proto:: { self , ToProto } ;
2
- use bip39:: { Language , Mnemonic } ;
2
+ use bip39:: { Language , Mnemonic , MnemonicType , Seed } ;
3
3
use ed25519_dalek;
4
4
use failure:: { bail, err_msg, Error } ;
5
5
use failure_derive:: Fail ;
@@ -15,7 +15,9 @@ use std::{
15
15
str:: FromStr ,
16
16
} ;
17
17
use try_from:: { TryFrom , TryInto } ;
18
- use hmac:: Hmac ;
18
+ use hmac:: { Hmac , Mac } ;
19
+ use sha2:: Sha512 ;
20
+ use failure:: _core:: ops:: Deref ;
19
21
20
22
// Types used for (de-)serializing public and secret keys from ASN.1 byte
21
23
// streams.
@@ -366,61 +368,58 @@ impl TryFrom<proto::BasicTypes::Key> for PublicKey {
366
368
367
369
/// An EdDSA secret key.
368
370
#[ repr( C ) ]
369
- pub struct SecretKey ( ed25519_dalek:: SecretKey ) ;
371
+ pub struct SecretKey {
372
+ pub value : ed25519_dalek:: SecretKey ,
373
+ chain_code : Option < [ u8 ; 32 ] >
374
+ }
370
375
371
376
impl SecretKey {
372
377
/// Generate a `SecretKey` with 32 cryptographically random bytes
378
+ ///
379
+ /// This `SecretKey` will _not_ support child key derivation.
373
380
pub fn generate ( ) -> Self {
374
- let mut buf = [ 0u8 ; 32 ] ;
375
-
376
- getrandom:: getrandom ( & mut buf) . expect ( "Could not retrieve entropy from the os" ) ;
381
+ let mut bytes: [ u8 ; 32 ] = Default :: default ( ) ;
377
382
378
- let bytes = Self :: derive_seed ( & buf) ;
383
+ getrandom:: getrandom ( & mut bytes)
384
+ . expect ( "Could not retrieve secure entropy from the os" ) ;
379
385
380
- // this should never fail unless getrandom fails which will cause a panic
381
- SecretKey ( ed25519_dalek:: SecretKey :: from_bytes ( & bytes) . unwrap ( ) )
386
+ Self :: generate_from_entropy ( & bytes)
382
387
}
383
388
384
389
/// Generate a `SecretKey` with 32 bytes of provided entropy
390
+ ///
391
+ /// This `SecretKey` will _not_ support child key derivation.
392
+ #[ inline]
385
393
pub fn generate_from_entropy ( entropy : & [ u8 ; 32 ] ) -> Self {
386
- // this should never fail since entropy is required to be a 32-length u8 array
387
- SecretKey ( ed25519_dalek :: SecretKey :: from_bytes ( entropy) . unwrap ( ) )
394
+ // this should never fail since 32 byte arrays are guaranteed to be compatible
395
+ Self :: from_bytes ( entropy) . unwrap ( )
388
396
}
389
397
390
398
/// Generate a `SecretKey` alongside a BIP-39 mnemonic using a cryptographically
391
399
/// secure random number generator.
400
+ ///
401
+ /// Generated `SecretKey` will support deriving child keys with `.derive_child()`.
402
+ #[ inline]
392
403
pub fn generate_mnemonic ( ) -> ( Self , String ) {
393
- let mut entropy = [ 0u8 ; 32 ] ;
394
-
395
- getrandom:: getrandom ( & mut entropy) . expect ( "Could not retrieve entropy from the os" ) ;
396
-
397
- // this should never fail as 32 is a valid entropy length
398
- let mnemonic = Mnemonic :: from_entropy ( & entropy, Language :: English ) . unwrap ( ) ;
399
- let secret = Self :: generate_from_entropy ( & entropy) ;
400
-
401
- ( secret, mnemonic. into_phrase ( ) )
404
+ Self :: generate_mnemonic_with_passphrase ( "" )
402
405
}
403
406
404
- /// Duplicating what is done here:
405
- /// https://github.com/hashgraph/hedera-keygen-java/blob/master/src/main/java/com/hedera/sdk/keygen/CryptoUtils.java#L43
406
- fn derive_seed ( entropy : & [ u8 ] ) -> [ u8 ; 32 ] {
407
- let password = entropy
408
- . into_iter ( )
409
- . chain ( [ u8:: max_value ( ) ; 8 ] . iter ( ) )
410
- . map ( |u| { * u } )
411
- . collect :: < Vec < u8 > > ( ) ;
412
-
413
- let salt = [ u8:: max_value ( ) ] ;
414
-
415
- let mut seed = [ 0u8 ; 32 ] ;
416
-
417
- pbkdf2:: pbkdf2 :: < Hmac < sha2:: Sha512 > > ( & password, & salt, 2048 , & mut seed) ;
407
+ /// Generate a `SecretKey` alongside a BIP-39 mnemonic using a cryptographically
408
+ /// secure random number generate and provided passphrase
409
+ ///
410
+ /// Generated `SecretKey` will support deriving child keys with `.derive_child()`.
411
+ pub fn generate_mnemonic_with_passphrase ( passphrase : & str ) -> ( Self , String ) {
412
+ let mnemonic_phrase = Mnemonic :: new ( MnemonicType :: Words24 , Language :: English ) . into_phrase ( ) ;
418
413
419
- seed
414
+ // Cannot fail since it is being passed in compatible generated values
415
+ ( Self :: from_mnemonic_with_passphrase ( & mnemonic_phrase, passphrase) . unwrap ( ) , mnemonic_phrase)
420
416
}
421
417
422
418
/// Construct a `SecretKey` from a slice of bytes.
423
419
/// Bytes are expected to be either a raw key or encoded in ASN.1.
420
+ ///
421
+ /// This `SecretKey` will _not_ support child key derivation as it is impossible
422
+ /// to determine if the original key was generated with compatibility
424
423
pub fn from_bytes ( bytes : impl AsRef < [ u8 ] > ) -> Result < Self , Error > {
425
424
let bytes = bytes. as_ref ( ) ;
426
425
@@ -429,9 +428,10 @@ impl SecretKey {
429
428
{
430
429
// If the buffer looks like a {secret}{public} byte string; just pull the secret
431
430
// key bytes off of it
432
- return Ok ( SecretKey ( ed25519_dalek:: SecretKey :: from_bytes (
433
- & bytes[ ..ed25519_dalek:: SECRET_KEY_LENGTH ] ,
434
- ) ?) ) ;
431
+ return Ok ( SecretKey {
432
+ value : ed25519_dalek:: SecretKey :: from_bytes ( & bytes[ ..ed25519_dalek:: SECRET_KEY_LENGTH ] , ) ?,
433
+ chain_code : None
434
+ } ) ;
435
435
}
436
436
437
437
let info: PrivateKeyInfo = der_decode ( & bytes) ?;
@@ -443,32 +443,56 @@ impl SecretKey {
443
443
) ;
444
444
}
445
445
446
- Ok ( SecretKey ( ed25519_dalek:: SecretKey :: from_bytes (
447
- & info. private_key [ 2 ..] ,
448
- ) ?) )
446
+ Ok ( SecretKey {
447
+ value : ed25519_dalek:: SecretKey :: from_bytes ( & info. private_key [ 2 ..] , ) ?,
448
+ chain_code : None
449
+ } )
449
450
}
450
451
451
- /// Re-construct a `SecretKey` from the supplied mnemonic and password.
452
+ /// Re-construct a `SecretKey` from a supplied 24-word mnemonic and passphrase.
453
+ ///
454
+ /// There is no corresponding `to_mnemonic()` as the mnemonic cannot be recovered from the key.
455
+ ///
456
+ /// Mnemonics generated by the Android and iOS wallets will work
457
+ ///
458
+ /// Returned key will support deriving child keys with `.derive_child()`
459
+ #[ inline]
452
460
pub fn from_mnemonic ( mnemonic : & str ) -> Result < Self , Error > {
461
+ Self :: from_mnemonic_with_passphrase ( mnemonic, "" )
462
+ }
463
+
464
+ /// Re-construct a `SecretKey` from a supplied 24-word mnemonic and passphrase.
465
+ ///
466
+ /// There is no corresponding `to_mnemonic_with_passphrase()` as the mnemonic cannot be
467
+ /// recovered from the key.
468
+ ///
469
+ /// Mnemonics generated by the Android and iOS wallets will work
470
+ ///
471
+ /// Returned key will support deriving child keys with `.derive_child()`
472
+ pub fn from_mnemonic_with_passphrase ( mnemonic : & str , passphrase : & str ) -> Result < Self , Error > {
453
473
let mnemonic = Mnemonic :: from_phrase ( mnemonic, Language :: English ) ?;
454
474
455
- let mut entropy = [ 0u8 ; 32 ] ;
475
+ let seed = Seed :: new ( & mnemonic , passphrase ) ;
456
476
457
- let seed_entropy = mnemonic. entropy ( ) ;
477
+ let mut key_bytes: [ u8 ; 32 ] = Default :: default ( ) ;
478
+ key_bytes. copy_from_slice ( & seed. as_bytes ( ) [ 0 ..32 ] ) ;
458
479
459
- for i in 0 ..32 {
460
- entropy[ i] = seed_entropy[ i] ;
461
- }
480
+ let mut chain_code: [ u8 ; 32 ] = Default :: default ( ) ;
481
+ chain_code. copy_from_slice ( & seed. as_bytes ( ) [ 32 ..64 ] ) ;
462
482
463
- //let entropy: &[u8; 32] = vec!(mnemonic.entropy()).try_into()?;
483
+ for i in [ 44u32 , 3030u32 , 0u32 , 0u32 ] . iter ( ) {
484
+ let ( new_key_bytes, new_chain_code) = Self :: derive_child_key_bytes ( & key_bytes, & chain_code, i) ?;
464
485
465
- Ok ( Self :: generate_from_entropy ( & entropy) )
466
- }
486
+ key_bytes. copy_from_slice ( & new_key_bytes) ;
487
+ chain_code. copy_from_slice ( & new_chain_code) ;
488
+ }
467
489
468
- /// Return the `SecretKey` as raw bytes.
469
- #[ inline]
470
- pub fn as_bytes ( & self ) -> & [ u8 ; ed25519_dalek:: SECRET_KEY_LENGTH ] {
471
- self . 0 . as_bytes ( )
490
+ let secret_key = SecretKey {
491
+ value : ed25519_dalek:: SecretKey :: from_bytes ( & key_bytes) ?,
492
+ chain_code : Some ( chain_code)
493
+ } ;
494
+
495
+ Ok ( secret_key)
472
496
}
473
497
474
498
/// Format a `SecretKey` as a vec of bytes in ASN.1 format.
@@ -477,7 +501,7 @@ impl SecretKey {
477
501
algorithm : AlgorithmIdentifier {
478
502
algorithm : OID_ED25519 . clone ( ) ,
479
503
} ,
480
- private_key : self . 0 . to_bytes ( ) . to_vec ( ) ,
504
+ private_key : self . to_bytes ( ) . to_vec ( ) ,
481
505
} )
482
506
// NOTE: Not possible to fail. Only fail case the library has is if OIDs are
483
507
// given incorrectly.
@@ -487,23 +511,49 @@ impl SecretKey {
487
511
/// Derive a `PublicKey` from this `SecretKey`.
488
512
#[ inline]
489
513
pub fn public ( & self ) -> PublicKey {
490
- PublicKey ( ed25519_dalek:: PublicKey :: from ( & self . 0 ) )
514
+ PublicKey ( ed25519_dalek:: PublicKey :: from ( & self . value ) )
491
515
}
492
516
493
517
/// Sign a message with this `SecretKey`.
494
518
#[ inline]
495
519
pub fn sign ( & self , message : impl AsRef < [ u8 ] > ) -> Signature {
496
520
Signature (
497
- ed25519_dalek:: ExpandedSecretKey :: from ( & self . 0 )
521
+ ed25519_dalek:: ExpandedSecretKey :: from ( & self . value )
498
522
. sign ( message. as_ref ( ) , & self . public ( ) . 0 ) ,
499
523
)
500
524
}
525
+
526
+ /// SLIP-10/BIP-32 child key derivation
527
+ fn derive_child_key_bytes ( parent_key : & [ u8 ; 32 ] , chain_code : & [ u8 ; 32 ] , index : & u32 ) -> Result < ( [ u8 ; 32 ] , [ u8 ; 32 ] ) , Error > {
528
+ // This can't fail since 32 bytes is a valid key length
529
+ let mut hmac = Hmac :: < Sha512 > :: new_varkey ( chain_code) . unwrap ( ) ;
530
+
531
+ let mut input= [ 0u8 ; 37 ] ;
532
+
533
+ input[ 0 ] = 0u8 ;
534
+ input[ 1 ..33 ] . copy_from_slice ( parent_key) ;
535
+ input[ 34 ..37 ] . copy_from_slice ( & index. to_be_bytes ( ) ) ;
536
+
537
+ input[ 33 ] = input[ 33 ] | 128u8 ;
538
+
539
+ hmac. input ( & input) ;
540
+
541
+ let hmac = hmac. result ( ) . code ( ) ;
542
+
543
+ let mut new_key_bytes: [ u8 ; 32 ] = Default :: default ( ) ;
544
+ let mut chain_code: [ u8 ; 32 ] = Default :: default ( ) ;
545
+ new_key_bytes. copy_from_slice ( & hmac. as_slice ( ) [ 0 ..32 ] ) ;
546
+ chain_code. copy_from_slice ( & hmac. as_slice ( ) [ 32 ..64 ] ) ;
547
+
548
+ Ok ( ( new_key_bytes, chain_code) )
549
+ }
550
+
501
551
}
502
552
503
553
impl Clone for SecretKey {
504
554
#[ inline]
505
555
fn clone ( & self ) -> Self {
506
- Self :: from_bytes ( self . 0 . as_bytes ( ) ) . unwrap ( )
556
+ Self :: from_bytes ( self . as_bytes ( ) ) . unwrap ( )
507
557
}
508
558
}
509
559
@@ -555,6 +605,15 @@ impl Debug for SecretKey {
555
605
}
556
606
}
557
607
608
+ impl Deref for SecretKey {
609
+ type Target = ed25519_dalek:: SecretKey ;
610
+
611
+ #[ inline]
612
+ fn deref ( & self ) -> & Self :: Target {
613
+ & self . value
614
+ }
615
+ }
616
+
558
617
/// Format a `SecretKey` as a hex representation of its bytes in ASN.1 format.
559
618
impl Display for SecretKey {
560
619
#[ inline]
@@ -653,7 +712,7 @@ mod tests {
653
712
let secret_key2: SecretKey = KEY_SECRET_HEX . parse ( ) ?;
654
713
655
714
assert_eq ! ( public_key1, public_key2) ;
656
- assert_eq ! ( secret_key1. 0 . as_bytes( ) , secret_key2. 0 . as_bytes( ) ) ;
715
+ assert_eq ! ( secret_key1. as_bytes( ) , secret_key2. as_bytes( ) ) ;
657
716
assert_eq ! ( public_key1, secret_key1. public( ) ) ;
658
717
assert_eq ! ( public_key2, secret_key2. public( ) ) ;
659
718
assert_eq ! ( secret_key2. public( ) , secret_key1. public( ) ) ;
0 commit comments