bcmyers / argonautica

Idiomatic argon2 password hashing for several languages
Apache License 2.0
144 stars 29 forks source link

How to reuse a `Hasher` and `Verifier`? #23

Open little-dude opened 4 years ago

little-dude commented 4 years ago

I'd like to keep a hasher around and use it to hash password. Something like:

pub struct AuthService {
    secret_key: String,
    hasher: Hasher<'static>,
    verifier: Verifier<'static>,
}

impl AuthService {
    pub fn new(secret_key: String, hasher_iterations: u32, hasher_memory: u32) -> Self {
        let mut hasher = Hasher::default();
        hasher
            .configure_memory_size(hasher_memory)
            .configure_iterations(hasher_iterations);
        Self {
            secret_key,
            hasher,
            verifier: Verifier::default(),
        }
    }

    pub fn hash_password(&self, password: &str) -> String {
        self.hasher
            .with_password(password)
            .with_secret_key(&self.secret_key)
            .hash()
            .unwrap()
    }

    pub fn verify_password(&self, password: &str, hash: &str) -> bool {
        self.verifier
            .with_hash(hash)
            .with_password(password)
            .with_secret_key(&self.secret_key)
            .verify()
            .unwrap()
    }
}

But the problem is that the lifetime parameter of both Hasher and Verifier are tied to the lifetime of the password itself. With the code above, the compiler expects my passwords to have the 'static lifetime:

  --> src/main.rs:25:14
   |
23 |     pub fn hash_password(&self, password: &str) -> String {
   |                                           ---- help: add explicit lifetime `'static` to the type of `password`: `&'static str`
24 |         self.hasher
25 |             .with_password(password)
   |              ^^^^^^^^^^^^^ lifetime `'static` required

error[E0621]: explicit lifetime required in the type of `password`
  --> src/main.rs:33:14
   |
31 |     pub fn verify_password(&self, password: &str, hash: &str) -> bool {
   |                                             ---- help: add explicit lifetime `'static` to the type of `password`: `&'static str`
32 |         self.verifier
33 |             .with_hash(hash)
   |              ^^^^^^^^^ lifetime `'static` required

My questions are:

little-dude commented 4 years ago

Another solution is to turn the password and secret key into actual Strings, but again that seems rather inefficient:

pub struct AuthService {
    secret_key: String,
    hasher: Hasher<'static>,
    verifier: Verifier<'static>,
}

impl AuthService {
    pub fn new(secret_key: String, hasher_iterations: u32, hasher_memory: u32) -> Self {
        let mut hasher = Hasher::default();
        hasher
            .configure_memory_size(hasher_memory)
            .configure_iterations(hasher_iterations);
        Self {
            secret_key,
            hasher,
            verifier: Verifier::default(),
        }
    }

    pub fn hash_password(&mut self, password: &str) -> String {
        self.hasher
            .with_password(password.to_string())
            .with_secret_key(self.secret_key.clone())
            .hash()
            .unwrap()
    }

    pub fn verify_password(&mut self, password: &str, hash: &str) -> bool {
        self.verifier
            .with_hash(hash)
            .with_password(password.to_string())
            .with_secret_key(self.secret_key.clone())
            .verify()
            .unwrap()
    }
}