use crate::{
ipc::{req::AuthReq, resp::AuthGranted},
Result, SafeAuthReq,
};
use sn_client::api::Client;
use sn_interface::types::{Keypair, RegisterAddress};
use hmac::Hmac;
use rand_07::{rngs::StdRng, SeedableRng};
use sha3::Sha3_256;
use std::{
collections::HashSet,
net::SocketAddr,
path::{Path, PathBuf},
sync::Arc,
};
use tiny_keccak::{Hasher, Sha3};
use xor_name::{XorName, XOR_NAME_LEN};
const SHA3_512_HASH_LEN: usize = 64;
#[allow(dead_code)]
const SAFE_TYPE_TAG: u64 = 1_300;
pub fn derive_secrets(acc_passphrase: &[u8], acc_password: &[u8]) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
let mut passphrase_hasher = Sha3::v512();
let mut passphrase_hash = [0; SHA3_512_HASH_LEN];
passphrase_hasher.update(acc_passphrase);
passphrase_hasher.finalize(&mut passphrase_hash);
let passphrase = passphrase_hash.to_vec();
let mut salt_hasher = Sha3::v512();
let mut salt_hash = [0; SHA3_512_HASH_LEN];
let salt_bytes = &passphrase_hash[SHA3_512_HASH_LEN / 2..];
salt_hasher.update(salt_bytes);
salt_hasher.finalize(&mut salt_hash);
let salt = salt_hash.to_vec();
let mut password_hasher = Sha3::v512();
let mut password_hash = [0; SHA3_512_HASH_LEN];
password_hasher.update(acc_password);
password_hasher.finalize(&mut password_hash);
let password = password_hash.to_vec();
(passphrase, password, salt)
}
fn create_ed25519_keypair_from_seed(seeder: &[u8]) -> Keypair {
let mut hasher = Sha3::v256();
let mut seed = [0; 32];
hasher.update(seeder);
hasher.finalize(&mut seed);
let mut rng = StdRng::from_seed(seed);
let keypair = ed25519_dalek::Keypair::generate(&mut rng);
Keypair::Ed25519(Arc::new(keypair))
}
pub fn derive_location_and_keypair(passphrase: &str, password: &str) -> Result<(XorName, Keypair)> {
let (passphrase, password, salt) = derive_secrets(passphrase.as_bytes(), password.as_bytes());
let map_data_location = generate_network_address(&passphrase, &salt)?;
let mut seed = password;
seed.extend(salt.iter());
let keypair = create_ed25519_keypair_from_seed(&seed);
Ok((map_data_location, keypair))
}
pub fn generate_network_address(passphrase: &[u8], salt: &[u8]) -> Result<XorName> {
let mut id = XorName([0; XOR_NAME_LEN]);
const ITERATIONS: u32 = 10_000u32;
pbkdf2::pbkdf2::<Hmac<Sha3_256>>(passphrase, salt, ITERATIONS, &mut id.0[..]);
Ok(id)
}
#[derive(Default)]
pub struct SafeAuthenticator {
#[allow(dead_code)]
safe: Option<(Client, RegisterAddress)>,
#[allow(dead_code)]
config_path: Option<PathBuf>,
#[allow(dead_code)]
bootstrap_contacts: Option<HashSet<SocketAddr>>,
}
impl SafeAuthenticator {
pub fn new(
_config_dir_path: Option<&Path>,
_bootstrap_contacts: Option<HashSet<SocketAddr>>,
) -> Self {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub async fn create(&mut self, _passphrase: &str, _password: &str) -> Result<()> {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub async fn unlock(&mut self, _passphrase: &str, _password: &str) -> Result<()> {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub fn lock(&mut self) -> Result<()> {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub fn is_a_safe_unlocked(&self) -> bool {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub async fn decode_req(&self, _req: &str) -> Result<SafeAuthReq> {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub async fn revoke_app(&self, _y: &str) -> Result<()> {
unimplemented!()
}
pub async fn authorise_app(&self, _req: &str) -> Result<String> {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
pub async fn authenticate(&self, _auth_req: AuthReq) -> Result<AuthGranted> {
unimplemented!("Authenticator hasn't yet been updated to work with the new Safe Network");
}
}
#[cfg(test)]
mod tests {
use super::*;
use sn_interface::types::PublicKey;
use anyhow::{Context, Result};
use proptest::prelude::*;
#[test]
fn get_deterministic_pk_from_known_seed() -> Result<()> {
let seed = b"bacon";
let pk = create_ed25519_keypair_from_seed(seed).public_key();
let public_key_bytes: [u8; ed25519_dalek::PUBLIC_KEY_LENGTH] = [
239, 124, 31, 157, 76, 101, 124, 119, 164, 143, 80, 234, 249, 84, 0, 22, 91, 128, 67,
92, 39, 182, 197, 184, 83, 44, 41, 127, 78, 175, 205, 198,
];
let ed_pk = ed25519_dalek::PublicKey::from_bytes(&public_key_bytes)
.with_context(|| "Cannot deserialise expected key".to_string())?;
let expected_pk = PublicKey::from(ed_pk);
assert_eq!(pk, expected_pk);
Ok(())
}
proptest! {
#[test]
fn proptest_always_get_same_info_from_from_phrase_and_pw(s in "\\PC*", p in "\\PC*") {
let (location, keypair) = derive_location_and_keypair(&s, &p).expect("could not derive location/keypair");
let (location_again, keypair_again) = derive_location_and_keypair(&s, &p).expect("could not derive location/keypair");
prop_assert_eq!(location, location_again);
prop_assert_eq!(keypair, keypair_again);
}
}
}