utils (crypto/database): update cryptographic functions/add comments and tests in database

This commit is contained in:
MedzikUser 2022-04-18 00:07:37 +02:00
parent 0867e44d58
commit 5b79b4f7e2
No known key found for this signature in database
GPG Key ID: A5FAC1E185C112DB
8 changed files with 166 additions and 55 deletions

26
Cargo.lock generated
View File

@ -275,6 +275,7 @@ dependencies = [
"sha-1",
"sha2",
"toml",
"uuid",
]
[[package]]
@ -535,6 +536,21 @@ dependencies = [
"digest",
]
[[package]]
name = "sha1"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
dependencies = [
"sha1_smol",
]
[[package]]
name = "sha1_smol"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]]
name = "sha2"
version = "0.10.2"
@ -694,6 +710,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "uuid"
version = "0.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
dependencies = [
"getrandom",
"sha1",
]
[[package]]
name = "vcpkg"
version = "0.2.15"

View File

@ -1,6 +1,6 @@
[workspace]
members = [
"core",
"utils",
"core"
]
resolver = "2"

View File

@ -1,6 +1,9 @@
mod init;
use homedisk_utils::{config::Config, database::Database};
use homedisk_utils::{
config::Config,
database::{Database, User},
};
#[tokio::main]
async fn main() {
@ -8,5 +11,11 @@ async fn main() {
let _config = Config::parse().expect("parse configuration file");
let _db = Database::open().expect("open SQLite database");
let _db = Database::open("homedisk.db").expect("open SQLite database");
let user = User::new("medzik", "password").unwrap();
println!("{:?}", user);
_db.create_user(user).unwrap();
}

View File

@ -1,8 +1,5 @@
CREATE TABLE user (
id INTEGER PRIMARY KEY,
username TEXT NOT NULL,
id TEXT PRIMARY KEY UNIQUE,
username TEXT NOT NULL UNIQUE,
password TEXT NOT NULL
);
/* create root user with password 'root' */
INSERT INTO user (username, password) VALUES ('root', '99adc231b045331e514a516b4b7680f588e3823213abe901738bc3ad67b2f6fcb3c64efb93d18002588d3ccc1a49efbae1ce20cb43df36b38651f11fa75678e8');

View File

@ -7,7 +7,7 @@ edition = "2021"
full = ["crypto", "config", "database"]
crypto = ["sha-1", "sha2", "hex"]
config = ["toml", "anyhow", "dirs"]
database = ["rusqlite"]
database = ["rusqlite", "uuid"]
[dependencies]
log = "0.4.16"
@ -43,3 +43,7 @@ optional = true
version = "0.27.0"
features = ["bundled"]
optional = true
[dependencies.uuid]
version = "0.8.2"
features = ["v4", "v5"]
optional = true

View File

@ -1,4 +1,4 @@
use hex::encode;
pub use hex::encode;
use sha1::Sha1;
use sha2::{Digest, Sha256, Sha512};
@ -7,73 +7,102 @@ use super::{Error, Result};
/// create a cryptographic hash from a string (sha1, sha256, sha512)
///
/// ```
/// use homedisk_utils::crypto::hasher;
/// use homedisk_utils::crypto::{CryptographicHash, encode};
///
/// let sha1 = hasher("SHA-1", "test string".to_string()).unwrap();
/// assert_eq!(sha1, "661295c9cbf9d6b2f6428414504a8deed3020641".to_string())
/// let mut sha1 = CryptographicHash::new("SHA-1").unwrap();
/// sha1.update(b"test sha1 hash");
///
/// let hash = encode(sha1.finalize());
///
/// assert_eq!(hash, "7726bd9560e1ad4a1a4f056cae5c0c9ea8bacfc2".to_string())
/// ```
pub fn hasher(algo: &str, input: String) -> Result<String> {
let hash = match algo {
"SHA-1" | "SHA1" | "Sha1" | "sha1" => {
let mut hasher = Sha1::new();
hasher.update(input.as_bytes());
#[derive(Debug, Clone)]
pub enum CryptographicHash {
Sha1(Sha1),
Sha256(Sha256),
Sha512(Sha512),
}
encode(hasher.finalize())
impl CryptographicHash {
pub fn new(algo: &str) -> Result<Self> {
match algo {
"SHA-1" | "SHA1" | "Sha1" | "sha1" => Ok(Self::Sha1(Sha1::new())),
"SHA-256" | "SHA256" | "Sha256" | "sha256" => Ok(Self::Sha256(Sha256::new())),
"SHA-512" | "SHA512" | "Sha512" | "sha512" => Ok(Self::Sha512(Sha512::new())),
_ => Err(Error::UnknownAlgorithm("digest", algo.to_string())),
}
}
"SHA-256" | "SHA256" | "Sha256" | "sha256" => {
let mut hasher = Sha256::new();
hasher.update(input.as_bytes());
encode(hasher.finalize())
pub fn update(&mut self, input: &[u8]) {
match self {
Self::Sha1(sha1) => sha1.update(input),
Self::Sha256(sha256) => sha256.update(input),
Self::Sha512(sha512) => sha512.update(input),
}
}
"SHA-512" | "SHA512" | "Sha512" | "sha512" => {
let mut hasher = Sha512::new();
hasher.update(input.as_bytes());
encode(hasher.finalize())
pub fn finalize(&mut self) -> Vec<u8> {
match self {
Self::Sha1(sha1) => sha1.finalize_reset().to_vec(),
Self::Sha256(sha256) => sha256.finalize_reset().to_vec(),
Self::Sha512(sha512) => sha512.finalize_reset().to_vec(),
}
}
_ => return Err(Error::UnknownAlgorithm("digest", algo.to_string())),
};
pub fn hash(algo: &str, input: &[u8]) -> Result<Vec<u8>> {
let mut hasher = Self::new(algo)?;
Ok(hash)
hasher.update(input);
Ok(hasher.finalize())
}
}
#[cfg(test)]
mod tests {
use crate::crypto::{hasher, Error};
use crate::crypto::{encode, CryptographicHash, Error};
#[test]
fn sha1() {
let sha1 = hasher("sha1", "test string".to_string()).unwrap();
assert_eq!(sha1, "661295c9cbf9d6b2f6428414504a8deed3020641".to_string());
let mut sha1 = CryptographicHash::new("SHA-1").unwrap();
sha1.update(b"test sha1 hash");
let hash = encode(sha1.finalize());
assert_eq!(hash, "7726bd9560e1ad4a1a4f056cae5c0c9ea8bacfc2".to_string())
}
#[test]
fn sha256() {
let sha1 = hasher("sha256", "test string".to_string()).unwrap();
let mut sha256 = CryptographicHash::new("SHA-256").unwrap();
sha256.update(b"test sha256 hash");
let hash = encode(sha256.finalize());
assert_eq!(
sha1,
"d5579c46dfcc7f18207013e65b44e4cb4e2c2298f4ac457ba8f82743f31e930b".to_string()
);
hash,
"eaf6e4198f39ccd63bc3e957d43bf4ef67f12c318c8e3cdc2567a37339902dac".to_string()
)
}
#[test]
fn sha512() {
let sha1 = hasher("sha512", "test string".to_string()).unwrap();
let mut sha512 = CryptographicHash::new("SHA-512").unwrap();
sha512.update(b"test sha512 hash");
let hash = encode(sha512.finalize());
assert_eq!(
sha1,
"10e6d647af44624442f388c2c14a787ff8b17e6165b83d767ec047768d8cbcb71a1a3226e7cc7816bc79c0427d94a9da688c41a3992c7bf5e4d7cc3e0be5dbac".to_string()
);
hash,
"b43b4d7178014c92f55be828d66c9f98211fc67b385f7790a5b4b2fcb89fe1831645b5a4c17f3f7f11d8f34d2800a77a2b8faa5a0fb9d6b8f7befbc29a9ce795".to_string()
)
}
#[test]
fn unknown_algorithm() {
let algo = "unknow_algo";
let err = hasher(algo, "test string".to_string()).unwrap_err();
let err = CryptographicHash::new(algo).unwrap_err();
assert_eq!(err, Error::UnknownAlgorithm("digest", algo.to_string()));
assert_eq!(err, Error::UnknownAlgorithm("digest", algo.to_string()))
}
}

View File

@ -1,8 +1,6 @@
use log::debug;
use rusqlite::Connection;
use crate::crypto;
use super::{user, Error};
pub struct Database {
@ -10,22 +8,40 @@ pub struct Database {
}
impl Database {
pub fn open() -> Result<Self, Error> {
/// Open SQLite Database file
/// ```
/// use homedisk_utils::database::Database;
///
/// Database::open("/tmp/homedisk.db").unwrap();
/// ```
pub fn open(path: &str) -> Result<Self, Error> {
debug!("opening SQLite database");
let conn = Connection::open("homedisk.db")?;
let conn = Connection::open(path)?;
Ok(Self { conn })
}
pub fn create_user(&mut self, user: user::User) -> Result<usize, Error> {
/// Create new User
/// ```
/// use std::fs;
///
/// use rusqlite::Connection;
/// use homedisk_utils::database::{Database, User};
///
/// let db = Database { conn: Connection::open_in_memory().unwrap() };
/// let user = User::new("medzik", "SuperSecretPassword123").unwrap();
///
/// db.conn.execute(&fs::read_to_string("../template.sql").unwrap(), []).unwrap();
///
/// db.create_user(user).unwrap();
/// ```
pub fn create_user(&self, user: user::User) -> Result<usize, Error> {
debug!("creating user - {}", user.username);
// hash password using sha512
let password = crypto::hasher("sha512", user.password)?;
Ok(self.conn.execute(
"INSERT INTO user (username, password) VALUES (?1, ?2)",
[user.username, password],
"INSERT INTO user (id, username, password) VALUES (?1, ?2, ?3)",
[user.id, user.username, user.password],
)?)
}
}

View File

@ -1,5 +1,35 @@
use hex::encode;
use uuid::Uuid;
use crate::crypto::{self, CryptographicHash};
#[derive(Debug)]
pub struct User {
pub id: String,
pub username: String,
pub password: String,
}
impl User {
/// Create a new User type (note **this doesn't create a new user in the database!**)
///
/// This function creates a unique UUID for the user and creates a password hash using SHA-512
/// ```
/// use homedisk_utils::database::User;
///
/// let user = User::new("medzik", "SuperSecretPassword123!").unwrap();
/// ```
pub fn new(username: &str, password: &str) -> Result<Self, crypto::Error> {
// create user UUID
let sha1_name = CryptographicHash::hash("SHA-1", username.as_bytes())?;
let id = Uuid::new_v5(&Uuid::NAMESPACE_X500, &sha1_name).to_string();
let password = encode(CryptographicHash::hash("SHA-512", password.as_bytes())?);
Ok(Self {
id,
username: username.to_string(),
password,
})
}
}