set_master_pass now asks for the master password twice
This commit is contained in:
71
cryptography/src/hashing.rs
Normal file
71
cryptography/src/hashing.rs
Normal file
@ -0,0 +1,71 @@
|
||||
use entity::master_pass;
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use scrypt::{scrypt, Params};
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
pub const HASH_LENGTH: usize = 64;
|
||||
pub const SALT_LENGTH: usize = 64;
|
||||
|
||||
static PARAMS: Lazy<Params> = Lazy::new(|| Params::new(14, 8, 1, HASH_LENGTH).unwrap());
|
||||
|
||||
/// Hashes the bytes with Scrypt with the given salt
|
||||
#[inline]
|
||||
pub fn hash_scrypt(bytes: &[u8], salt: &[u8]) -> [u8; HASH_LENGTH] {
|
||||
let mut hash = [0; HASH_LENGTH];
|
||||
scrypt(bytes, salt, &PARAMS, &mut hash).unwrap();
|
||||
hash
|
||||
}
|
||||
|
||||
/// Verifieble scrypt hashed bytes
|
||||
pub struct HashedBytes<T, U>
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
U: AsRef<[u8]>,
|
||||
{
|
||||
pub hash: T,
|
||||
pub salt: U,
|
||||
}
|
||||
|
||||
impl HashedBytes<[u8; HASH_LENGTH], [u8; SALT_LENGTH]> {
|
||||
#[inline]
|
||||
pub fn new(bytes: &[u8]) -> Self {
|
||||
let mut salt = [0; 64];
|
||||
OsRng.fill_bytes(&mut salt);
|
||||
Self {
|
||||
hash: hash_scrypt(bytes, &salt),
|
||||
salt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> HashedBytes<T, U>
|
||||
where
|
||||
T: AsRef<[u8]>,
|
||||
U: AsRef<[u8]>,
|
||||
{
|
||||
#[inline]
|
||||
pub fn verify(&self, bytes: &[u8]) -> bool {
|
||||
let hash = hash_scrypt(bytes, self.salt.as_ref());
|
||||
hash.ct_eq(self.hash.as_ref()).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a master_pass::Model> for HashedBytes<&'a [u8], &'a [u8]> {
|
||||
#[inline]
|
||||
fn from(value: &'a master_pass::Model) -> Self {
|
||||
HashedBytes {
|
||||
hash: &value.password_hash,
|
||||
salt: &value.salt,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<master_pass::Model> for HashedBytes<Vec<u8>, Vec<u8>> {
|
||||
fn from(value: master_pass::Model) -> Self {
|
||||
Self {
|
||||
hash: value.password_hash,
|
||||
salt: value.salt,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
//! Functions to encrypt the database models
|
||||
|
||||
pub mod account;
|
||||
pub mod hashing;
|
||||
pub mod master_pass;
|
||||
pub mod passwords;
|
||||
pub mod prelude;
|
||||
|
@ -1,35 +1,6 @@
|
||||
use super::hashing::HashedBytes;
|
||||
use entity::master_pass;
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::{rngs::OsRng, RngCore};
|
||||
use scrypt::{scrypt, Params};
|
||||
use sea_orm::ActiveValue::Set;
|
||||
use subtle::ConstantTimeEq;
|
||||
|
||||
const HASH_LENGTH: usize = 64;
|
||||
const SALT_LENGTH: usize = 64;
|
||||
|
||||
static PARAMS: Lazy<Params> = Lazy::new(|| Params::new(14, 8, 1, HASH_LENGTH).unwrap());
|
||||
|
||||
/// Hashes the password with Scrypt with the given salt
|
||||
#[inline]
|
||||
fn hash_password(password: &[u8], salt: &[u8]) -> [u8; HASH_LENGTH] {
|
||||
let mut password_hash = [0; HASH_LENGTH];
|
||||
scrypt(password, salt, &PARAMS, &mut password_hash).unwrap();
|
||||
password_hash
|
||||
}
|
||||
|
||||
pub trait VerifyMasterPassExt {
|
||||
fn verify(&self, password: &str) -> bool;
|
||||
}
|
||||
|
||||
impl VerifyMasterPassExt for master_pass::Model {
|
||||
/// Checks that the given password hash matches the one of the model
|
||||
#[inline]
|
||||
fn verify(&self, password: &str) -> bool {
|
||||
let hashed = hash_password(password.as_bytes(), &self.salt);
|
||||
hashed.ct_eq(&self.password_hash).into()
|
||||
}
|
||||
}
|
||||
|
||||
pub trait MasterPassFromUnencryptedExt {
|
||||
fn from_unencrypted(user_id: u64, password: &str) -> master_pass::ActiveModel;
|
||||
@ -39,13 +10,11 @@ impl MasterPassFromUnencryptedExt for master_pass::ActiveModel {
|
||||
/// Hashes the password and creates an ActiveModel with all fields set to Set variant
|
||||
#[inline]
|
||||
fn from_unencrypted(user_id: u64, password: &str) -> Self {
|
||||
let mut salt = [0; SALT_LENGTH];
|
||||
OsRng.fill_bytes(&mut salt);
|
||||
let password_hash = hash_password(password.as_bytes(), &salt);
|
||||
let hash = HashedBytes::new(password.as_bytes());
|
||||
Self {
|
||||
user_id: Set(user_id),
|
||||
salt: Set(salt.into()),
|
||||
password_hash: Set(password_hash.into()),
|
||||
password_hash: Set(hash.hash.to_vec()),
|
||||
salt: Set(hash.salt.to_vec()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user