diff --git a/src/api.rs b/src/api.rs index 9289bd7..1b81be5 100644 --- a/src/api.rs +++ b/src/api.rs @@ -31,7 +31,6 @@ use sdk_common::sp_client::silentpayments::{ Error as SpError, }; use serde_json::{Error as SerdeJsonError, Value}; -use shamir::SecretData; use serde::{Deserialize, Serialize}; use tsify::Tsify; @@ -330,17 +329,6 @@ impl recover_data { } } -#[derive(Debug, Tsify, Serialize, Deserialize)] -#[tsify(from_wasm_abi)] -#[allow(non_camel_case_types)] -pub struct shamir_shares(Vec>); - -impl shamir_shares { - fn as_inner(&self) -> &[Vec] { - &self.0 - } -} - #[derive(Debug, Tsify, Serialize, Deserialize)] #[tsify(from_wasm_abi, into_wasm_abi)] #[allow(non_camel_case_types)] @@ -357,14 +345,12 @@ pub fn login_user( user_password: String, pre_id: String, recover: recover_data, - shares: shamir_shares, outputs: outputs_list, ) -> ApiResult<()> { let res = User::login( pre_id, user_password, recover.as_inner(), - shares.as_inner(), outputs.as_inner(), )?; diff --git a/src/user.rs b/src/user.rs index 7d3ea0a..1236ee2 100644 --- a/src/user.rs +++ b/src/user.rs @@ -12,7 +12,6 @@ use serde_json::{json, Value}; use tsify::Tsify; use wasm_bindgen::prelude::*; -use shamir::SecretData; use std::collections::HashMap; use std::fs::File; use std::io::{Cursor, Read, Write}; @@ -34,9 +33,6 @@ use sdk_common::crypto::{ type PreId = String; -const MANAGERS_NUMBER: u8 = 10; -const QUORUM_SHARD: f32 = 0.8; - pub static CONNECTED_USER: OnceLock> = OnceLock::new(); pub fn lock_connected_user() -> Result> { @@ -141,7 +137,6 @@ pub struct User { pub peers: Vec, recover_data: Vec, revoke_data: Option>, - shares: Vec>, outputs: Vec, } @@ -162,23 +157,19 @@ impl User { revoke_data.extend_from_slice(revoke.get_client().try_get_secret_spend_key()?.as_ref()); // Take the 2 recover keys - // split recover spend key let recover_spend_key = user_wallets .try_get_recover()? .get_client() .try_get_secret_spend_key()? .clone(); - let (part1_key, part2_key) = recover_spend_key.as_ref().split_at(SECRET_KEY_SIZE / 2); let mut recover_data = Vec::::with_capacity(180); // 32 * 3 + (12+16)*3 // generate 3 tokens of 32B entropy let mut entropy_1: [u8; 32] = Aes256Gcm::generate_key(&mut rng).into(); let mut entropy_2: [u8; 32] = Aes256Gcm::generate_key(&mut rng).into(); - let mut entropy_3: [u8; 32] = Aes256Gcm::generate_key(&mut rng).into(); recover_data.extend_from_slice(&entropy_1); recover_data.extend_from_slice(&entropy_2); - recover_data.extend_from_slice(&entropy_3); // hash the concatenation let mut engine = sha256::HashEngine::default(); @@ -187,57 +178,26 @@ impl User { let hash1 = sha256::Hash::from_engine(engine); // take it as a AES key - let part1_encryption = Aes256Encryption::import_key( - Purpose::Login, - part1_key.to_vec(), + let recover_key_encryption = Aes256Encryption::import_key( + Purpose::ThirtyTwoBytes, + recover_spend_key.secret_bytes().to_vec(), hash1.to_byte_array(), Aes256Gcm::generate_nonce(&mut rng).into(), )?; // encrypt the part1 of the key - let cipher_recover_part1 = part1_encryption.encrypt_with_aes_key()?; + let cipher_recover = recover_key_encryption.encrypt_with_aes_key()?; - recover_data.extend_from_slice(&cipher_recover_part1); + recover_data.extend_from_slice(&cipher_recover); //Pre ID - let pre_id: PreId = Self::compute_pre_id(&user_password, &cipher_recover_part1); - - // encrypt the part 2 of the key - let mut engine = sha256::HashEngine::default(); - engine.write_all(&user_password.as_bytes()); - engine.write_all(&entropy_2); - let hash2 = sha256::Hash::from_engine(engine); - - // take it as a AES key - let part2_encryption = Aes256Encryption::import_key( - Purpose::Login, - part2_key.to_vec(), - hash2.to_byte_array(), - Aes256Gcm::generate_nonce(&mut rng).into(), - )?; - - // encrypt the part2 of the key - let cipher_recover_part2 = part2_encryption.encrypt_with_aes_key()?; - - //create shardings - let threshold = (MANAGERS_NUMBER as f32 * QUORUM_SHARD).floor(); - debug_assert!(threshold > 0.0 && threshold <= u8::MAX as f32); - let sharding = shamir::SecretData::with_secret( - &cipher_recover_part2.to_lower_hex_string(), - threshold as u8, - ); - - let shares: Vec> = (1..MANAGERS_NUMBER) - .map(|x| { - sharding.get_share(x).unwrap() // Let's trust it for now - }) - .collect(); + let pre_id: PreId = Self::compute_pre_id(&user_password, &cipher_recover); //scan key: let mut engine = sha256::HashEngine::default(); engine.write_all(&user_password.as_bytes()); - engine.write_all(&entropy_3); - let hash3 = sha256::Hash::from_engine(engine); + engine.write_all(&entropy_2); + let hash2 = sha256::Hash::from_engine(engine); let scan_key_encryption = Aes256Encryption::import_key( Purpose::ThirtyTwoBytes, @@ -247,7 +207,7 @@ impl User { .get_scan_key() .secret_bytes() .to_vec(), - hash3.to_byte_array(), + hash2.to_byte_array(), Aes256Gcm::generate_nonce(&mut rng).into(), )?; @@ -264,7 +224,6 @@ impl User { peers: vec![], recover_data, revoke_data: Some(revoke_data), - shares, outputs: all_outputs, }) } @@ -282,7 +241,6 @@ impl User { pre_id: PreId, user_password: String, recover_data: &[u8], - shares: &[Vec], outputs: &[OutputList], ) -> Result<()> { // if we are already logged in, abort @@ -294,40 +252,32 @@ impl User { let mut retrieved_scan_key = [0u8; 32]; let mut entropy1 = [0u8; 32]; let mut entropy2 = [0u8; 32]; - let mut entropy3 = [0u8; 32]; let mut cipher_scan_key = [0u8; 60]; // cipher length == plain.len() + 16 + nonce.len() - let mut part1_ciphertext = [0u8; 44]; + let mut cipher_spend_key = [0u8; 60]; let mut reader = Cursor::new(recover_data); reader.read_exact(&mut entropy1)?; reader.read_exact(&mut entropy2)?; - reader.read_exact(&mut entropy3)?; - reader.read_exact(&mut part1_ciphertext)?; + reader.read_exact(&mut cipher_spend_key)?; reader.read_exact(&mut cipher_scan_key)?; // We can retrieve the pre_id and check that it matches - let retrieved_pre_id = Self::compute_pre_id(&user_password, &part1_ciphertext); + let retrieved_pre_id = Self::compute_pre_id(&user_password, &cipher_spend_key); // If pre_id is not the same, password is probably false, or the client is feeding us garbage if retrieved_pre_id != pre_id { return Err(Error::msg("pre_id and recover_data don't match")); } - retrieved_spend_key[..16].copy_from_slice(&Self::recover_part1( + retrieved_spend_key.copy_from_slice(&Self::recover_key_slice( &user_password, &entropy1, - part1_ciphertext.to_vec(), - )?); - - retrieved_spend_key[16..].copy_from_slice(&Self::recover_part2( - &user_password, - &entropy2, - shares, + cipher_spend_key.to_vec(), )?); retrieved_scan_key.copy_from_slice(&Self::recover_key_slice( &user_password, - &entropy3, + &entropy2, cipher_scan_key.to_vec(), )?); @@ -370,78 +320,14 @@ impl User { aes_dec.decrypt_with_key() } - fn recover_part1(password: &str, entropy: &[u8], ciphertext: Vec) -> Result> { - let mut engine = sha256::HashEngine::default(); - engine.write_all(&password.as_bytes()); - engine.write_all(&entropy); - let hash = sha256::Hash::from_engine(engine); - - let aes_dec = Aes256Decryption::new(Purpose::Login, ciphertext, hash.to_byte_array())?; - - aes_dec.decrypt_with_key() - } - - fn recover_part2(password: &str, entropy: &[u8], shares: &[Vec]) -> Result> { - let mut engine = sha256::HashEngine::default(); - engine.write_all(&password.as_bytes()); - engine.write_all(&entropy); - let hash = sha256::Hash::from_engine(engine); - - let threshold = (MANAGERS_NUMBER as f32 * QUORUM_SHARD).floor(); - debug_assert!(threshold > 0.0 && threshold <= u8::MAX as f32); - - let part2_key_enc = Vec::from_hex( - &SecretData::recover_secret(threshold as u8, shares.to_vec()) - .ok_or_else(|| anyhow::Error::msg("Failed to retrieve the sharded secret"))?, - )?; - - let aes_dec = Aes256Decryption::new(Purpose::Login, part2_key_enc, hash.to_byte_array())?; - - aes_dec.decrypt_with_key() - } - - fn compute_pre_id(user_password: &str, cipher_recover_part1: &[u8]) -> PreId { + fn compute_pre_id(user_password: &str, cipher_recover: &[u8]) -> PreId { let mut engine = sha256::HashEngine::default(); engine.write_all(&user_password.as_bytes()); - engine.write_all(&cipher_recover_part1); + engine.write_all(&cipher_recover); let pre_id = sha256::Hash::from_engine(engine); pre_id.to_string() } - - //not used - // pub fn pbkdf2(password: &str, data: &str) -> String { - // let data_salt = data.trim_end_matches('='); - // let salt = SaltString::from_b64(data_salt) - // .map(|s| s) - // .unwrap_or_else(|_| panic!("Failed to parse salt value from base64 string")); - - // let mut password_hash = String::new(); - // if let Ok(pwd) = Scrypt.hash_password(password.as_bytes(), &salt) { - // password_hash.push_str(&pwd.to_string()); - // } - // sha_256(&password_hash) - // } - - // // Test sharing JS side - // pub fn get_shares(&self) -> Vec { - // self.sharding.shares_format_str.clone() - // } - - // //Test sharing Js side - // pub fn get_secret(&self, shardings: Vec) -> String { - // let mut shares_vec = Vec::new(); - - // for s in shardings.iter() { - // let bytes_vec: Vec = s - // .trim_matches(|c| c == '[' || c == ']') - // .split(',') - // .filter_map(|s| s.trim().parse().ok()) - // .collect(); - // shares_vec.push(bytes_vec); - // } - // self.sharding.recover_secrete(shares_vec.clone()) - // } } #[cfg(test)] @@ -521,7 +407,6 @@ mod tests { user.pre_id.clone(), USER_PASSWORD.to_owned(), &user.recover_data, - &user.shares, &user_wallets.get_all_outputs(), );