Skip to content

Commit

Permalink
fix(key_manager): remove trailing '.' from hashing domains, fix WASM …
Browse files Browse the repository at this point in the history
…tests (#4378)

Description
---
- remove `tari_common` dependency from key manager as it does not support the wasm target.
- remove trailing `.` from hashing domains by using labels
- remove extra allocation in `CipherSeed::generate_mac`

Motivation and Context
---
`tari_common` includes `fs2` which does not support WASM targets causing [failed CI builds](https://github.com/tari-project/tari/runs/7645710771?check_suite_focus=true). This is currently breaking `development` branch tests.

Using a blank label appends a "." onto the domain, the current correct usage of the api is to use a label

How Has This Been Tested?
---
Existing tests pass
  • Loading branch information
sdbondi committed Aug 3, 2022
1 parent 7a25028 commit 214a986
Show file tree
Hide file tree
Showing 6 changed files with 39 additions and 46 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion base_layer/key_manager/Cargo.toml
Expand Up @@ -10,11 +10,11 @@ edition = "2021"
[lib]
crate-type = ["lib", "cdylib"]

# NB: All dependencies must support or be gated for the WASM target.
[dependencies]
tari_common_types = { version = "^0.34", path = "../../base_layer/common_types" }
tari_crypto = { git = "https://github.com/tari-project/tari-crypto.git", tag = "v0.15.3" }
tari_utilities = { git = "https://github.com/tari-project/tari_utilities.git", tag = "v0.4.5" }
tari_common = { path = "../../common" }

arrayvec = "0.7.1"
argon2 = { version = "0.2", features = ["std"] }
Expand Down
32 changes: 14 additions & 18 deletions base_layer/key_manager/src/cipher_seed.rs
Expand Up @@ -20,12 +20,7 @@
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::{
convert::TryFrom,
mem::size_of,
ops::Add,
time::{Duration, SystemTime, UNIX_EPOCH},
};
use std::{convert::TryFrom, mem::size_of};

use argon2::{
password_hash::{Salt, SaltString},
Expand All @@ -44,16 +39,16 @@ use chacha20::{
use crc32fast::Hasher as CrcHasher;
use rand::{rngs::OsRng, RngCore};
use serde::{Deserialize, Serialize};
use tari_common::mac_domain_hasher;
use tari_crypto::hash::blake2::Blake256;
use tari_utilities::ByteArray;

use crate::{
error::KeyManagerError,
mac_domain_hasher,
mnemonic::{from_bytes, to_bytes, to_bytes_with_language, Mnemonic, MnemonicLanguage},
KeyManagerArgon2Encoding,
KeyManagerChacha20Encoding,
KeyManagerMacGeneration,
LABEL_ARGON_ENCODING,
LABEL_CHACHA20_ENCODING,
LABEL_MAC_GENERATION,
};

const CIPHER_SEED_VERSION: u8 = 0u8;
Expand Down Expand Up @@ -123,8 +118,9 @@ pub struct CipherSeed {
impl CipherSeed {
#[cfg(not(target_arch = "wasm32"))]
pub fn new() -> Self {
use std::time::{Duration, SystemTime, UNIX_EPOCH};
const SECONDS_PER_DAY: u64 = 24 * 60 * 60;
let birthday_genesis_date = UNIX_EPOCH.add(Duration::from_secs(BIRTHDAY_GENESIS_FROM_UNIX_EPOCH));
let birthday_genesis_date = UNIX_EPOCH + Duration::from_secs(BIRTHDAY_GENESIS_FROM_UNIX_EPOCH);
let days = SystemTime::now()
.duration_since(birthday_genesis_date)
.unwrap()
Expand Down Expand Up @@ -264,7 +260,7 @@ impl CipherSeed {
// encryption nonce for ChaCha20 encryption, generated as a domain separated hash of the given salt. Following
// https://libsodium.gitbook.io/doc/advanced/stream_ciphers/chacha20, as of the IEF variant, the produced encryption
// nonce should be 96-bit long
let encryption_nonce = &mac_domain_hasher::<Blake256, KeyManagerChacha20Encoding>()
let encryption_nonce = mac_domain_hasher::<Blake256>(LABEL_CHACHA20_ENCODING)
.chain(salt)
.finalize();

Expand All @@ -273,9 +269,9 @@ impl CipherSeed {
let nonce_ga = Nonce::from_slice(encryption_nonce);

// we take the last 32 bytes of the generated derived encryption key for ChaCha20 cipher, see documentation
let derived_encryption_key = Self::generate_domain_separated_passphrase_hash(passphrase, salt)?[32..].to_vec();
let derived_encryption_key = Self::generate_domain_separated_passphrase_hash(passphrase, salt)?;

let key = Key::from_slice(derived_encryption_key.as_slice());
let key = Key::from_slice(&derived_encryption_key[32..]);
let mut cipher = ChaCha20::new(key, nonce_ga);
cipher.apply_keystream(data.as_mut_slice());

Expand Down Expand Up @@ -320,14 +316,14 @@ impl CipherSeed {
}

// we take the first 32 bytes of the generated derived encryption key for MAC generation, see documentation
let passphrase_key = Self::generate_domain_separated_passphrase_hash(passphrase, salt)?[..32].to_vec();
let passphrase_key = Self::generate_domain_separated_passphrase_hash(passphrase, salt)?;

Ok(mac_domain_hasher::<Blake256, KeyManagerMacGeneration>()
Ok(mac_domain_hasher::<Blake256>(LABEL_MAC_GENERATION)
.chain(birthday)
.chain(entropy)
.chain(cipher_seed_version)
.chain(salt)
.chain(passphrase_key.as_slice())
.chain(&passphrase_key[32..])
.finalize()
.as_ref()[..CIPHER_SEED_MAC_BYTES]
.to_vec())
Expand All @@ -338,7 +334,7 @@ impl CipherSeed {

// we produce a domain separated hash of the given salt, for Argon2 encryption use. As suggested in
// https://en.wikipedia.org/wiki/Argon2, we shall use a 16-byte length hash salt
let argon2_salt = mac_domain_hasher::<Blake256, KeyManagerArgon2Encoding>()
let argon2_salt = mac_domain_hasher::<Blake256>(LABEL_ARGON_ENCODING)
.chain(salt)
.finalize();
let argon2_salt = &argon2_salt.as_ref()[..ARGON2_SALT_BYTES];
Expand Down
8 changes: 3 additions & 5 deletions base_layer/key_manager/src/key_manager.rs
Expand Up @@ -25,15 +25,13 @@ use std::marker::PhantomData;
use derivative::Derivative;
use digest::Digest;
use serde::{Deserialize, Serialize};
use tari_common::mac_domain_hasher;
use tari_crypto::{
hash::blake2::Blake256,
hashing::LengthExtensionAttackResistant,
keys::SecretKey,
tari_utilities::byte_array::ByteArrayError,
};

use crate::{cipher_seed::CipherSeed, KeyManagerDomain};
use crate::{cipher_seed::CipherSeed, mac_domain_hasher, LABEL_DERIVE_KEY};

#[derive(Clone, Derivative, Serialize, Deserialize)]
#[derivative(Debug)]
Expand Down Expand Up @@ -89,9 +87,9 @@ where
/// hash function H which is Length attack resistant, such as Blake2b.
pub fn derive_key(&self, key_index: u64) -> Result<DerivedKey<K>, ByteArrayError> {
// apply domain separation to generate derive key. Under the hood, the hashing api prepends the length of each
// piece of data for concatenation, reducing the risk of collisions due to redundance of variable length
// piece of data for concatenation, reducing the risk of collisions due to redundancy of variable length
// input
let derive_key = mac_domain_hasher::<Blake256, KeyManagerDomain>()
let derive_key = mac_domain_hasher::<D>(LABEL_DERIVE_KEY)
.chain(self.seed.entropy())
.chain(self.branch_seed.as_str().as_bytes())
.chain(key_index.to_le_bytes())
Expand Down
32 changes: 16 additions & 16 deletions base_layer/key_manager/src/lib.rs
@@ -1,7 +1,11 @@
// Copyright 2022 The Tari Project
// SPDX-License-Identifier: BSD-3-Clause

use tari_crypto::hash_domain;
use digest::Digest;
use tari_crypto::{
hash_domain,
hashing::{DomainSeparatedHasher, LengthExtensionAttackResistant},
};

pub mod cipher_seed;
pub mod diacritics;
Expand All @@ -15,18 +19,14 @@ pub mod mnemonic_wordlists;
pub mod wasm;

hash_domain!(KeyManagerDomain, "com.tari.tari_project.base_layer.key_manager", 1);
hash_domain!(
KeyManagerMacGeneration,
"com.tari.tari_project.base_layer.key_manager.mac_generation",
1
);
hash_domain!(
KeyManagerArgon2Encoding,
"com.tari.tari_project.base_layer.key_manager.argon2_encoding",
1
);
hash_domain!(
KeyManagerChacha20Encoding,
"com.tari.tari_project.base_layer.key_manager.chacha20_encoding",
1
);

const LABEL_ARGON_ENCODING: &str = "argon2_encoding";
const LABEL_CHACHA20_ENCODING: &str = "chacha20_encoding";
const LABEL_MAC_GENERATION: &str = "mac_generation";
const LABEL_DERIVE_KEY: &str = "derive_key";

pub(crate) fn mac_domain_hasher<D: Digest + LengthExtensionAttackResistant>(
label: &'static str,
) -> DomainSeparatedHasher<D, KeyManagerDomain> {
DomainSeparatedHasher::<D, KeyManagerDomain>::new_with_label(label)
}
10 changes: 5 additions & 5 deletions base_layer/key_manager/src/wasm.rs
Expand Up @@ -179,11 +179,11 @@ mod test {

#[wasm_bindgen_test]
fn it_creates_key_manager_from() {
let bytes = &[
0u8, 175, 181, 246, 157, 116, 78, 216, 151, 75, 19, 156, 105, 61, 136, 116, 128, 66, 73, 68, 229, 223, 123,
127, 116, 217, 17, 5, 250, 33, 50, 157, 17,
let bytes = [
0, 2, 116, 75, 54, 160, 21, 1, 43, 55, 107, 155, 189, 230, 182, 215, 17, 191, 94, 156, 114, 136, 40, 175,
144, 166, 93, 233, 179, 11, 8, 49, 139,
];
let seed = CipherSeed::from_enciphered_bytes(bytes, None).unwrap();
let seed = CipherSeed::from_enciphered_bytes(&bytes, None).unwrap();
let seed = JsValue::from_serde(&seed).unwrap();

let js = key_manager_from(seed, "asdf".into(), 0);
Expand All @@ -193,7 +193,7 @@ mod test {
let next_key = response.key_manager.next_key().unwrap();
assert_eq!(
next_key.k.to_hex(),
"00afb5f69d744ed8974b139c693d887480424944e5df7b7f74d91105fa21329d11".to_string()
"84feaddf54f1b4321db67f7aae382c338d03c56280a417651c4e0cde3363d00a".to_string()
)
}

Expand Down

0 comments on commit 214a986

Please sign in to comment.