Fix things
This commit is contained in:
parent
4a228a3ce7
commit
378cbd76d0
4 changed files with 62 additions and 29 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -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",
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue