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]]
name = "k2v-client"
version = "0.1.0"
source = "git+https://git.deuxfleurs.fr/Deuxfleurs/garage.git?branch=improve-k2v-client#413c64d7a93d21adbe75d4a13b08cf63e74a95c7"
dependencies = [
"base64",
"http",

View File

@ -29,5 +29,5 @@ tokio = "1.17.0"
toml = "0.5"
zstd = { version = "0.9", default-features = false }
#k2v-client = { git = "https://git.deuxfleurs.fr/Deuxfleurs/garage.git" }
k2v-client = { path = "../garage/src/k2v-client" }
k2v-client = { git = "https://git.deuxfleurs.fr/Deuxfleurs/garage.git", branch = "improve-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> {
// Check that salt and public don't exist already
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
let mut ident_salt = [0u8; 32];
@ -129,8 +129,8 @@ impl CryptoKeys {
// Write values to storage
k2v.insert_batch(&[
k2v_insert_single_key("keys", "salt", None, &ident_salt),
k2v_insert_single_key("keys", "public", None, &keys.public),
k2v_insert_single_key("keys", "salt", salt_ct, &ident_salt),
k2v_insert_single_key("keys", "public", public_ct, &keys.public),
k2v_insert_single_key("keys", &password_sortkey, None, &password_blob),
])
.await
@ -146,7 +146,7 @@ impl CryptoKeys {
) -> Result<Self> {
// Check that salt and public don't exist already
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
let mut ident_salt = [0u8; 32];
@ -162,8 +162,8 @@ impl CryptoKeys {
// Write values to storage
k2v.insert_batch(&[
k2v_insert_single_key("keys", "salt", None, &ident_salt),
k2v_insert_single_key("keys", "public", None, &keys.public),
k2v_insert_single_key("keys", "salt", salt_ct, &ident_salt),
k2v_insert_single_key("keys", "public", public_ct, &keys.public),
])
.await
.context("InsertBatch for salt and public")?;
@ -184,7 +184,7 @@ impl CryptoKeys {
let password_blob = {
let mut val = match k2v.read_item("keys", &password_sortkey).await {
Err(k2v_client::Error::NotFound) => {
bail!("given password does not exist in storage")
bail!("invalid password")
}
x => x?,
};
@ -193,7 +193,7 @@ impl CryptoKeys {
}
match val.value.pop().unwrap() {
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();
// List existing passwords to overwrite existing entry if necessary
let existing_passwords = Self::list_existing_passwords(&k2v).await?;
let ct = match existing_passwords.get(&password_sortkey) {
Some(p) => {
if p.value.iter().any(|x| matches!(x, K2vValue::Value(_))) {
bail!("Password already exists");
let ct = match k2v.read_item("keys", &password_sortkey).await {
Err(k2v_client::Error::NotFound) => None,
v => {
let entry = v?;
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
@ -315,11 +315,13 @@ impl CryptoKeys {
// ---- STORAGE UTIL ----
async fn check_uninitialized(k2v: &K2vClient) -> Result<()> {
async fn check_uninitialized(
k2v: &K2vClient,
) -> Result<(Option<CausalityToken>, Option<CausalityToken>)> {
let params = k2v
.read_batch(&[
k2v_read_single_key("keys", "salt"),
k2v_read_single_key("keys", "public"),
k2v_read_single_key("keys", "salt", true),
k2v_read_single_key("keys", "public", true),
])
.await
.context("ReadBatch for salt and public in check_uninitialized")?;
@ -329,18 +331,41 @@ impl CryptoKeys {
params
);
}
if !params[0].items.is_empty() || !params[1].items.is_empty() {
bail!("`salt` or `public` already exists in keys storage.");
if params[0].items.len() > 1 || params[1].items.len() > 1 {
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)> {
let mut params = k2v
.read_batch(&[
k2v_read_single_key("keys", "salt"),
k2v_read_single_key("keys", "public"),
k2v_read_single_key("keys", "salt", false),
k2v_read_single_key("keys", "public", false),
])
.await
.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 {
bail!("`salt` or `public` do not exist in storage.");
bail!("cryptographic keys not initialized for user");
}
// 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())
}
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 {
partition_key: partition_key,
filter: Filter {
@ -464,7 +493,7 @@ pub fn k2v_read_single_key<'a>(partition_key: &'a str, sort_key: &'a str) -> Bat
reverse: false,
},
conflicts_only: false,
tombstones: false,
tombstones,
single_item: true,
}
}

View File

@ -158,7 +158,10 @@ async fn main() -> Result<()> {
let existing_password =
rpassword::prompt_password("Enter existing password to decrypt keys: ")?;
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!("Keep it safe!");
password