rm shamir from user
This commit is contained in:
parent
28d4ad8d50
commit
1e79dfd7f6
14
src/api.rs
14
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<Vec<u8>>);
|
||||
|
||||
impl shamir_shares {
|
||||
fn as_inner(&self) -> &[Vec<u8>] {
|
||||
&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(),
|
||||
)?;
|
||||
|
||||
|
149
src/user.rs
149
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<Mutex<UserWallets>> = OnceLock::new();
|
||||
|
||||
pub fn lock_connected_user() -> Result<MutexGuard<'static, UserWallets>> {
|
||||
@ -141,7 +137,6 @@ pub struct User {
|
||||
pub peers: Vec<Peer>,
|
||||
recover_data: Vec<u8>,
|
||||
revoke_data: Option<Vec<u8>>,
|
||||
shares: Vec<Vec<u8>>,
|
||||
outputs: Vec<OutputList>,
|
||||
}
|
||||
|
||||
@ -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::<u8>::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<Vec<u8>> = (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<u8>],
|
||||
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<u8>) -> Result<Vec<u8>> {
|
||||
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<u8>]) -> Result<Vec<u8>> {
|
||||
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<String> {
|
||||
// self.sharding.shares_format_str.clone()
|
||||
// }
|
||||
|
||||
// //Test sharing Js side
|
||||
// pub fn get_secret(&self, shardings: Vec<String>) -> String {
|
||||
// let mut shares_vec = Vec::new();
|
||||
|
||||
// for s in shardings.iter() {
|
||||
// let bytes_vec: Vec<u8> = 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(),
|
||||
);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user