1
1
use crate :: proto:: { self , ToProto } ;
2
- use bip39:: { Language , Mnemonic , MnemonicType , Seed } ;
2
+ use bip39:: { Language , Mnemonic } ;
3
3
use ed25519_dalek;
4
4
use failure:: { bail, err_msg, Error } ;
5
5
use failure_derive:: Fail ;
6
6
use hex;
7
7
use num:: BigUint ;
8
8
use once_cell:: { sync:: Lazy } ;
9
- use rand_core:: SeedableRng ;
10
- use rand_chacha:: ChaChaRng ;
11
9
use simple_asn1:: {
12
10
der_decode, der_encode, oid, to_der, ASN1Block , ASN1Class , ASN1DecodeErr , ASN1EncodeErr ,
13
11
FromASN1 , ToASN1 , OID ,
@@ -17,6 +15,7 @@ use std::{
17
15
str:: FromStr ,
18
16
} ;
19
17
use try_from:: { TryFrom , TryInto } ;
18
+ use hmac:: Hmac ;
20
19
21
20
// Types used for (de-)serializing public and secret keys from ASN.1 byte
22
21
// streams.
@@ -370,25 +369,54 @@ impl TryFrom<proto::BasicTypes::Key> for PublicKey {
370
369
pub struct SecretKey ( ed25519_dalek:: SecretKey ) ;
371
370
372
371
impl SecretKey {
373
- /// Generate a `SecretKey` with a BIP-39 mnemonic using a cryptographically
372
+ /// Generate a `SecretKey` with 32 cryptographically random bytes
373
+ pub fn generate ( ) -> Self {
374
+ let mut buf = [ 0u8 ; 32 ] ;
375
+
376
+ getrandom:: getrandom ( & mut buf) . expect ( "Could not retrieve entropy from the os" ) ;
377
+
378
+ let bytes = Self :: derive_seed ( & buf) ;
379
+
380
+ // this should never fail unless getrandom fails which will cause a panic
381
+ SecretKey ( ed25519_dalek:: SecretKey :: from_bytes ( & bytes) . unwrap ( ) )
382
+ }
383
+
384
+ /// Generate a `SecretKey` with 32 bytes of provided entropy
385
+ 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 ( ) )
388
+ }
389
+
390
+ /// Generate a `SecretKey` alongside a BIP-39 mnemonic using a cryptographically
374
391
/// secure random number generator.
375
- ///
376
- /// The `password` is required with the mnemonic to reproduce the secret key.
377
- pub fn generate ( password : & str ) -> ( Self , String ) {
378
- let mnemonic = Mnemonic :: new ( MnemonicType :: Words24 , Language :: English ) ;
392
+ pub fn generate_mnemonic ( ) -> ( Self , String ) {
393
+ let mut entropy = [ 0u8 ; 32 ] ;
379
394
380
- let secret = Self :: generate_with_mnemonic ( & mnemonic, password) ;
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) ;
381
400
382
401
( secret, mnemonic. into_phrase ( ) )
383
402
}
384
403
385
- fn generate_with_mnemonic ( mnemonic : & Mnemonic , password : & str ) -> Self {
386
- let mut seed: [ u8 ; 32 ] = Default :: default ( ) ;
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 ( ) ] ;
387
414
388
- seed. copy_from_slice ( & Seed :: new ( & mnemonic , password ) . as_bytes ( ) [ 0 .. 32 ] ) ;
415
+ let mut seed = [ 0u8 ; 32 ] ;
389
416
390
- let mut rng = ChaChaRng :: from_seed ( seed) ;
391
- SecretKey ( ed25519_dalek:: SecretKey :: generate ( & mut rng) )
417
+ pbkdf2:: pbkdf2 :: < Hmac < sha2:: Sha512 > > ( & password, & salt, 2048 , & mut seed) ;
418
+
419
+ seed
392
420
}
393
421
394
422
/// Construct a `SecretKey` from a slice of bytes.
@@ -421,15 +449,25 @@ impl SecretKey {
421
449
}
422
450
423
451
/// Re-construct a `SecretKey` from the supplied mnemonic and password.
424
- pub fn from_mnemonic ( mnemonic : & str , password : & str ) -> Result < Self , Error > {
452
+ pub fn from_mnemonic ( mnemonic : & str ) -> Result < Self , Error > {
425
453
let mnemonic = Mnemonic :: from_phrase ( mnemonic, Language :: English ) ?;
426
454
427
- Ok ( Self :: generate_with_mnemonic ( & mnemonic, password) )
455
+ let mut entropy = [ 0u8 ; 32 ] ;
456
+
457
+ let seed_entropy = mnemonic. entropy ( ) ;
458
+
459
+ for i in 0 ..32 {
460
+ entropy[ i] = seed_entropy[ i] ;
461
+ }
462
+
463
+ //let entropy: &[u8; 32] = vec!(mnemonic.entropy()).try_into()?;
464
+
465
+ Ok ( Self :: generate_from_entropy ( & entropy) )
428
466
}
429
467
430
468
/// Return the `SecretKey` as raw bytes.
431
469
#[ inline]
432
- pub fn as_bytes ( & self ) -> & [ u8 ; ed25519_dalek:: PUBLIC_KEY_LENGTH ] {
470
+ pub fn as_bytes ( & self ) -> & [ u8 ; ed25519_dalek:: SECRET_KEY_LENGTH ] {
433
471
self . 0 . as_bytes ( )
434
472
}
435
473
@@ -646,7 +684,8 @@ mod tests {
646
684
647
685
#[ test]
648
686
fn test_generate ( ) -> Result < ( ) , Error > {
649
- let ( key, _mnemonic) = SecretKey :: generate ( "" ) ;
687
+ let key = SecretKey :: generate ( ) ;
688
+
650
689
let signature = key. sign ( MESSAGE . as_bytes ( ) ) ;
651
690
let verified = key. public ( ) . verify ( MESSAGE . as_bytes ( ) , & signature) ?;
652
691
@@ -671,8 +710,8 @@ mod tests {
671
710
672
711
#[ test]
673
712
fn test_reconstruct ( ) -> Result < ( ) , Error > {
674
- let ( secret1, mnemonic) = SecretKey :: generate ( "this-is-not-a-password" ) ;
675
- let secret2 = SecretKey :: from_mnemonic ( & mnemonic, "this-is-not-a-password" ) ?;
713
+ let ( secret1, mnemonic) = SecretKey :: generate_mnemonic ( ) ;
714
+ let secret2 = SecretKey :: from_mnemonic ( & mnemonic) ?;
676
715
677
716
assert_eq ! ( secret1. as_bytes( ) , secret2. as_bytes( ) ) ;
678
717
0 commit comments