Skip to content
This repository was archived by the owner on May 8, 2021. It is now read-only.

Commit fc8b848

Browse files
committed
reverts to proper slip-10/bip-32 based key generation
1 parent 087c355 commit fc8b848

File tree

1 file changed

+118
-59
lines changed

1 file changed

+118
-59
lines changed

src/crypto.rs

+118-59
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::proto::{self, ToProto};
2-
use bip39::{Language, Mnemonic};
2+
use bip39::{Language, Mnemonic, MnemonicType, Seed};
33
use ed25519_dalek;
44
use failure::{bail, err_msg, Error};
55
use failure_derive::Fail;
@@ -15,7 +15,9 @@ use std::{
1515
str::FromStr,
1616
};
1717
use try_from::{TryFrom, TryInto};
18-
use hmac::Hmac;
18+
use hmac::{Hmac, Mac};
19+
use sha2::Sha512;
20+
use failure::_core::ops::Deref;
1921

2022
// Types used for (de-)serializing public and secret keys from ASN.1 byte
2123
// streams.
@@ -366,61 +368,58 @@ impl TryFrom<proto::BasicTypes::Key> for PublicKey {
366368

367369
/// An EdDSA secret key.
368370
#[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+
}
370375

371376
impl SecretKey {
372377
/// Generate a `SecretKey` with 32 cryptographically random bytes
378+
///
379+
/// This `SecretKey` will _not_ support child key derivation.
373380
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();
377382

378-
let bytes = Self::derive_seed(&buf);
383+
getrandom::getrandom(&mut bytes)
384+
.expect("Could not retrieve secure entropy from the os");
379385

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)
382387
}
383388

384389
/// Generate a `SecretKey` with 32 bytes of provided entropy
390+
///
391+
/// This `SecretKey` will _not_ support child key derivation.
392+
#[inline]
385393
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()
388396
}
389397

390398
/// Generate a `SecretKey` alongside a BIP-39 mnemonic using a cryptographically
391399
/// secure random number generator.
400+
///
401+
/// Generated `SecretKey` will support deriving child keys with `.derive_child()`.
402+
#[inline]
392403
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("")
402405
}
403406

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();
418413

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)
420416
}
421417

422418
/// Construct a `SecretKey` from a slice of bytes.
423419
/// 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
424423
pub fn from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
425424
let bytes = bytes.as_ref();
426425

@@ -429,9 +428,10 @@ impl SecretKey {
429428
{
430429
// If the buffer looks like a {secret}{public} byte string; just pull the secret
431430
// 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+
});
435435
}
436436

437437
let info: PrivateKeyInfo = der_decode(&bytes)?;
@@ -443,32 +443,56 @@ impl SecretKey {
443443
);
444444
}
445445

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+
})
449450
}
450451

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]
452460
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> {
453473
let mnemonic = Mnemonic::from_phrase(mnemonic, Language::English)?;
454474

455-
let mut entropy = [0u8; 32];
475+
let seed = Seed::new(&mnemonic, passphrase);
456476

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]);
458479

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]);
462482

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)?;
464485

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+
}
467489

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)
472496
}
473497

474498
/// Format a `SecretKey` as a vec of bytes in ASN.1 format.
@@ -477,7 +501,7 @@ impl SecretKey {
477501
algorithm: AlgorithmIdentifier {
478502
algorithm: OID_ED25519.clone(),
479503
},
480-
private_key: self.0.to_bytes().to_vec(),
504+
private_key: self.to_bytes().to_vec(),
481505
})
482506
// NOTE: Not possible to fail. Only fail case the library has is if OIDs are
483507
// given incorrectly.
@@ -487,23 +511,49 @@ impl SecretKey {
487511
/// Derive a `PublicKey` from this `SecretKey`.
488512
#[inline]
489513
pub fn public(&self) -> PublicKey {
490-
PublicKey(ed25519_dalek::PublicKey::from(&self.0))
514+
PublicKey(ed25519_dalek::PublicKey::from(&self.value))
491515
}
492516

493517
/// Sign a message with this `SecretKey`.
494518
#[inline]
495519
pub fn sign(&self, message: impl AsRef<[u8]>) -> Signature {
496520
Signature(
497-
ed25519_dalek::ExpandedSecretKey::from(&self.0)
521+
ed25519_dalek::ExpandedSecretKey::from(&self.value)
498522
.sign(message.as_ref(), &self.public().0),
499523
)
500524
}
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+
501551
}
502552

503553
impl Clone for SecretKey {
504554
#[inline]
505555
fn clone(&self) -> Self {
506-
Self::from_bytes(self.0.as_bytes()).unwrap()
556+
Self::from_bytes(self.as_bytes()).unwrap()
507557
}
508558
}
509559

@@ -555,6 +605,15 @@ impl Debug for SecretKey {
555605
}
556606
}
557607

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+
558617
/// Format a `SecretKey` as a hex representation of its bytes in ASN.1 format.
559618
impl Display for SecretKey {
560619
#[inline]
@@ -653,7 +712,7 @@ mod tests {
653712
let secret_key2: SecretKey = KEY_SECRET_HEX.parse()?;
654713

655714
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());
657716
assert_eq!(public_key1, secret_key1.public());
658717
assert_eq!(public_key2, secret_key2.public());
659718
assert_eq!(secret_key2.public(), secret_key1.public());

0 commit comments

Comments
 (0)