Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(key_manager): remove trailing '.' from hashing domains, fix WASM tests #4378

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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