Store attributes & app pass with argon2

This commit is contained in:
Maximiliano Sandoval R 2021-01-23 14:36:34 +01:00
parent fd4d6e5537
commit 09448846dd
Failed to generate hash of commit
3 changed files with 83 additions and 11 deletions

44
Cargo.lock generated
View file

@ -81,6 +81,18 @@ version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afddf7f520a80dbf76e6f50a35bca42a2331ef227a28b3b6dc5c2e2338d114b1"
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
[[package]]
name = "arrayvec"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
[[package]]
name = "ashpd"
version = "0.1.0"
@ -265,11 +277,12 @@ dependencies = [
"pretty_env_logger",
"qrcode",
"quick-xml",
"rand 0.8.2",
"ring",
"rust-argon2",
"secret-service",
"serde",
"serde_json",
"sha2",
"surf",
"unicase",
"url",
@ -306,6 +319,17 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blake2b_simd"
version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
dependencies = [
"arrayref",
"arrayvec",
"constant_time_eq",
]
[[package]]
name = "block"
version = "0.1.6"
@ -473,6 +497,12 @@ version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28b9d6de7f49e22cf97ad17fc4036ece69300032f45f78f30b4a4482cdc3f4a6"
[[package]]
name = "constant_time_eq"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
[[package]]
name = "cookie"
version = "0.14.3"
@ -2407,6 +2437,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "rust-argon2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
dependencies = [
"base64 0.13.0",
"blake2b_simd",
"constant_time_eq",
"crossbeam-utils",
]
[[package]]
name = "rustc_version"
version = "0.2.3"

View file

@ -25,11 +25,12 @@ percent-encoding = "2.1"
pretty_env_logger = "0.4"
qrcode = {version = "0.12", features = ["image"]}
quick-xml = "0.20"
rand = "0.8"
ring = "0.16"
rust-argon2 = "0.8"
secret-service = "2.0"
serde = "1.0"
serde_json = "1.0"
sha2 = "0.9"
surf = "2.1"
unicase = "2.6"
url = "2.2"

View file

@ -1,6 +1,5 @@
use crate::config;
use secret_service::{Collection, EncryptionType, Error, SecretService};
use sha2::{Digest, Sha512};
use std::collections::HashMap;
pub struct Keyring;
@ -20,6 +19,31 @@ fn password_attributes() -> HashMap<&'static str, &'static str> {
attributes
}
fn random_salt() -> [u8; 64] {
use rand::RngCore;
let mut salt = [0u8; 64];
rand::thread_rng().fill_bytes(&mut salt);
salt
}
fn encode_argon2(secret: &str) -> anyhow::Result<String> {
use argon2::Config;
let password = secret.as_bytes();
let salt = &random_salt();
let config = Config::default();
let hash = argon2::hash_encoded(password, salt, &config)?;
Ok(hash)
}
/// Verifies that the hash generated by `password` corresponds
/// to `hash`.
fn verify_argon2(hash: &str, password: &str) -> anyhow::Result<bool> {
Ok(argon2::verify_encoded(hash, password.as_bytes())?)
}
impl Keyring {
pub fn get_default_collection<'a>(ss: &'a SecretService<'a>) -> Result<Collection<'a>, Error> {
let collection = match ss.get_default_collection() {
@ -38,14 +62,13 @@ impl Keyring {
Ok(())
}
pub fn store(label: &str, token: &str) -> Result<String, Error> {
let token = token.as_bytes();
pub fn store(label: &str, token: &str) -> anyhow::Result<String> {
let ss = SecretService::new(EncryptionType::Dh)?;
let col = Self::get_default_collection(&ss)?;
let token_id = hex::encode(Sha512::digest(token));
let token_id = encode_argon2(token)?;
let attributes = token_attributes(&token_id);
let base64_token = hex::encode(token);
let base64_token = hex::encode(token.as_bytes());
col.create_item(label, attributes, base64_token.as_bytes(), true, "plain")?;
Ok(token_id)
}
@ -85,15 +108,17 @@ impl Keyring {
}
}
pub fn set_password(password: &str) -> Result<(), Error> {
/// Stores password using the Argon2 algorithm with a random 128bit salt.
pub fn set_password(password: &str) -> anyhow::Result<()> {
let ss = SecretService::new(EncryptionType::Dh)?;
let col = Self::get_default_collection(&ss)?;
let encoded_password = encode_argon2(password)?;
let attributes = password_attributes();
col.create_item(
"Authenticator password",
attributes,
password.as_bytes(),
encoded_password.as_bytes(),
true,
"plain",
)?;
@ -113,14 +138,18 @@ impl Keyring {
}
}
pub fn is_current_password(password: &str) -> Result<bool, Error> {
pub fn is_current_password(password: &str) -> anyhow::Result<bool> {
let ss = SecretService::new(EncryptionType::Dh)?;
let col = Self::get_default_collection(&ss)?;
let attributes = password_attributes();
let items = col.search_items(attributes)?;
Ok(match items.get(0) {
Some(i) => i.get_secret()? == password.as_bytes(),
Some(i) => {
let secret = &i.get_secret()?;
let stored_pass = std::str::from_utf8(secret)?;
verify_argon2(stored_pass, password)?
}
None => false,
})
}