Fix things

This commit is contained in:
Alex 2022-05-20 21:35:50 +02:00
parent 4a228a3ce7
commit 378cbd76d0
Signed by: lx
GPG key ID: 0E496D15096376BE
4 changed files with 62 additions and 29 deletions

1
Cargo.lock generated
View file

@ -648,6 +648,7 @@ dependencies = [
[[package]] [[package]]
name = "k2v-client" name = "k2v-client"
version = "0.1.0" version = "0.1.0"
source = "git+https://git.deuxfleurs.fr/Deuxfleurs/garage.git?branch=improve-k2v-client#413c64d7a93d21adbe75d4a13b08cf63e74a95c7"
dependencies = [ dependencies = [
"base64", "base64",
"http", "http",

View file

@ -29,5 +29,5 @@ tokio = "1.17.0"
toml = "0.5" toml = "0.5"
zstd = { version = "0.9", default-features = false } zstd = { version = "0.9", default-features = false }
#k2v-client = { git = "https://git.deuxfleurs.fr/Deuxfleurs/garage.git" } k2v-client = { git = "https://git.deuxfleurs.fr/Deuxfleurs/garage.git", branch = "improve-k2v-client" }
k2v-client = { path = "../garage/src/k2v-client" } #k2v-client = { path = "../garage/src/k2v-client" }

View file

@ -95,7 +95,7 @@ impl CryptoKeys {
pub async fn init(storage: &StorageCredentials, password: &str) -> Result<Self> { pub async fn init(storage: &StorageCredentials, password: &str) -> Result<Self> {
// Check that salt and public don't exist already // Check that salt and public don't exist already
let k2v = storage.k2v_client()?; let k2v = storage.k2v_client()?;
Self::check_uninitialized(&k2v).await?; let (salt_ct, public_ct) = Self::check_uninitialized(&k2v).await?;
// Generate salt for password identifiers // Generate salt for password identifiers
let mut ident_salt = [0u8; 32]; let mut ident_salt = [0u8; 32];
@ -129,8 +129,8 @@ impl CryptoKeys {
// Write values to storage // Write values to storage
k2v.insert_batch(&[ k2v.insert_batch(&[
k2v_insert_single_key("keys", "salt", None, &ident_salt), k2v_insert_single_key("keys", "salt", salt_ct, &ident_salt),
k2v_insert_single_key("keys", "public", None, &keys.public), k2v_insert_single_key("keys", "public", public_ct, &keys.public),
k2v_insert_single_key("keys", &password_sortkey, None, &password_blob), k2v_insert_single_key("keys", &password_sortkey, None, &password_blob),
]) ])
.await .await
@ -146,7 +146,7 @@ impl CryptoKeys {
) -> Result<Self> { ) -> Result<Self> {
// Check that salt and public don't exist already // Check that salt and public don't exist already
let k2v = storage.k2v_client()?; let k2v = storage.k2v_client()?;
Self::check_uninitialized(&k2v).await?; let (salt_ct, public_ct) = Self::check_uninitialized(&k2v).await?;
// Generate salt for password identifiers // Generate salt for password identifiers
let mut ident_salt = [0u8; 32]; let mut ident_salt = [0u8; 32];
@ -162,8 +162,8 @@ impl CryptoKeys {
// Write values to storage // Write values to storage
k2v.insert_batch(&[ k2v.insert_batch(&[
k2v_insert_single_key("keys", "salt", None, &ident_salt), k2v_insert_single_key("keys", "salt", salt_ct, &ident_salt),
k2v_insert_single_key("keys", "public", None, &keys.public), k2v_insert_single_key("keys", "public", public_ct, &keys.public),
]) ])
.await .await
.context("InsertBatch for salt and public")?; .context("InsertBatch for salt and public")?;
@ -184,7 +184,7 @@ impl CryptoKeys {
let password_blob = { let password_blob = {
let mut val = match k2v.read_item("keys", &password_sortkey).await { let mut val = match k2v.read_item("keys", &password_sortkey).await {
Err(k2v_client::Error::NotFound) => { Err(k2v_client::Error::NotFound) => {
bail!("given password does not exist in storage") bail!("invalid password")
} }
x => x?, x => x?,
}; };
@ -193,7 +193,7 @@ impl CryptoKeys {
} }
match val.value.pop().unwrap() { match val.value.pop().unwrap() {
K2vValue::Value(v) => v, K2vValue::Value(v) => v,
K2vValue::Tombstone => bail!("password is a tombstone"), K2vValue::Tombstone => bail!("invalid password"),
} }
}; };
@ -257,15 +257,15 @@ impl CryptoKeys {
let password_blob = [&kdf_salt[..], &password_sealed].concat(); let password_blob = [&kdf_salt[..], &password_sealed].concat();
// List existing passwords to overwrite existing entry if necessary // List existing passwords to overwrite existing entry if necessary
let existing_passwords = Self::list_existing_passwords(&k2v).await?; let ct = match k2v.read_item("keys", &password_sortkey).await {
let ct = match existing_passwords.get(&password_sortkey) { Err(k2v_client::Error::NotFound) => None,
Some(p) => { v => {
if p.value.iter().any(|x| matches!(x, K2vValue::Value(_))) { let entry = v?;
bail!("Password already exists"); if entry.value.iter().any(|x| matches!(x, K2vValue::Value(_))) {
bail!("password already exists");
} }
Some(p.causality.clone()) Some(entry.causality.clone())
} }
None => None,
}; };
// Write values to storage // Write values to storage
@ -315,11 +315,13 @@ impl CryptoKeys {
// ---- STORAGE UTIL ---- // ---- STORAGE UTIL ----
async fn check_uninitialized(k2v: &K2vClient) -> Result<()> { async fn check_uninitialized(
k2v: &K2vClient,
) -> Result<(Option<CausalityToken>, Option<CausalityToken>)> {
let params = k2v let params = k2v
.read_batch(&[ .read_batch(&[
k2v_read_single_key("keys", "salt"), k2v_read_single_key("keys", "salt", true),
k2v_read_single_key("keys", "public"), k2v_read_single_key("keys", "public", true),
]) ])
.await .await
.context("ReadBatch for salt and public in check_uninitialized")?; .context("ReadBatch for salt and public in check_uninitialized")?;
@ -329,18 +331,41 @@ impl CryptoKeys {
params params
); );
} }
if !params[0].items.is_empty() || !params[1].items.is_empty() { if params[0].items.len() > 1 || params[1].items.len() > 1 {
bail!("`salt` or `public` already exists in keys storage."); bail!(
"invalid response from k2v storage: {:?} (several items in single_item read)",
params
);
} }
Ok(()) let salt_ct = match params[0].items.iter().next() {
None => None,
Some((_, CausalValue { causality, value })) => {
if value.iter().any(|x| matches!(x, K2vValue::Value(_))) {
bail!("key storage already initialized");
}
Some(causality.clone())
}
};
let public_ct = match params[1].items.iter().next() {
None => None,
Some((_, CausalValue { causality, value })) => {
if value.iter().any(|x| matches!(x, K2vValue::Value(_))) {
bail!("key storage already initialized");
}
Some(causality.clone())
}
};
Ok((salt_ct, public_ct))
} }
async fn load_salt_and_public(k2v: &K2vClient) -> Result<([u8; 32], PublicKey)> { async fn load_salt_and_public(k2v: &K2vClient) -> Result<([u8; 32], PublicKey)> {
let mut params = k2v let mut params = k2v
.read_batch(&[ .read_batch(&[
k2v_read_single_key("keys", "salt"), k2v_read_single_key("keys", "salt", false),
k2v_read_single_key("keys", "public"), k2v_read_single_key("keys", "public", false),
]) ])
.await .await
.context("ReadBatch for salt and public in load_salt_and_public")?; .context("ReadBatch for salt and public in load_salt_and_public")?;
@ -351,7 +376,7 @@ impl CryptoKeys {
); );
} }
if params[0].items.len() != 1 || params[1].items.len() != 1 { if params[0].items.len() != 1 || params[1].items.len() != 1 {
bail!("`salt` or `public` do not exist in storage."); bail!("cryptographic keys not initialized for user");
} }
// Retrieve salt from given response // Retrieve salt from given response
@ -453,7 +478,11 @@ pub fn argon2_kdf(salt: &[u8], password: &[u8], output_len: usize) -> Result<Vec
Ok(hash.as_bytes().to_vec()) Ok(hash.as_bytes().to_vec())
} }
pub fn k2v_read_single_key<'a>(partition_key: &'a str, sort_key: &'a str) -> BatchReadOp<'a> { pub fn k2v_read_single_key<'a>(
partition_key: &'a str,
sort_key: &'a str,
tombstones: bool,
) -> BatchReadOp<'a> {
BatchReadOp { BatchReadOp {
partition_key: partition_key, partition_key: partition_key,
filter: Filter { filter: Filter {
@ -464,7 +493,7 @@ pub fn k2v_read_single_key<'a>(partition_key: &'a str, sort_key: &'a str) -> Bat
reverse: false, reverse: false,
}, },
conflicts_only: false, conflicts_only: false,
tombstones: false, tombstones,
single_item: true, single_item: true,
} }
} }

View file

@ -158,7 +158,10 @@ async fn main() -> Result<()> {
let existing_password = let existing_password =
rpassword::prompt_password("Enter existing password to decrypt keys: ")?; rpassword::prompt_password("Enter existing password to decrypt keys: ")?;
let new_password = if gen { let new_password = if gen {
let password = base64::encode(&u128::to_be_bytes(thread_rng().gen())[..10]); let password = base64::encode_config(
&u128::to_be_bytes(thread_rng().gen())[..10],
base64::URL_SAFE_NO_PAD,
);
println!("Your new password: {}", password); println!("Your new password: {}", password);
println!("Keep it safe!"); println!("Keep it safe!");
password password