Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ peripherals = { path = "modules/peripherals" }
bootsplash = { path = "modules/bootsplash" }
internationalization = { path = "modules/internationalization" }
testing = { path = "modules/testing" }
device = { path = "modules/device" }

# - Drivers
drivers_core = { path = "drivers/core" }
Expand Down Expand Up @@ -199,6 +200,7 @@ members = [
"modules/internationalization/macros",
"modules/graphics/fonts_generator",
"modules/testing",
"modules/device",
]

[patch.crates-io]
Expand Down
3 changes: 3 additions & 0 deletions drivers/shared/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ edition = "2024"
file_system = { workspace = true }
log = { workspace = true }
shared = { workspace = true }
device = { workspace = true }

getrandom = { version = "0.3.3" }
sha2 = { version = "0.10", features = ["asm"] }

[dev-dependencies]
critical-section = { workspace = true, features = ["std"] }
107 changes: 107 additions & 0 deletions drivers/shared/src/devices/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use device::hash::{self, HashAlgorithm};
use file_system::{
BaseOperations, CharacterDevice, Context, ControlArgument, ControlCommand, Error,
MountOperations, Result, Size,
};
use sha2::{Digest, Sha224, Sha256, Sha384, Sha512, Sha512_224, Sha512_256, digest::DynDigest};

#[derive(Clone)]
struct HashDeviceContext {
hasher: Box<dyn DynDigest>,
}

unsafe impl Send for HashDeviceContext {}
unsafe impl Sync for HashDeviceContext {}

impl HashDeviceContext {
fn new(algorithm: HashAlgorithm) -> Result<Self> {
let hasher: Box<dyn DynDigest> = match algorithm {
HashAlgorithm::Sha224 => Box::new(Sha224::new()),
HashAlgorithm::Sha256 => Box::new(Sha256::new()),
HashAlgorithm::Sha384 => Box::new(Sha384::new()),
HashAlgorithm::Sha512 => Box::new(Sha512::new()),
HashAlgorithm::Sha512_224 => Box::new(Sha512_224::new()),
HashAlgorithm::Sha512_256 => Box::new(Sha512_256::new()),
_ => return Err(Error::InvalidParameter),
};

Ok(Self { hasher })
}
}

pub struct HashDevice;

impl BaseOperations for HashDevice {
fn open(&self, context: &mut Context) -> Result<()> {
context.set_private_data(Box::new(HashDeviceContext::new(HashAlgorithm::Sha256)?));
Ok(())
}

fn close(&self, context: &mut Context) -> Result<()> {
context.take_private_data_of_type::<HashDeviceContext>();
Ok(())
}

fn read(&self, context: &mut Context, buffer: &mut [u8], _: Size) -> Result<usize> {
let hash_context = context
.get_private_data_mutable_of_type::<HashDeviceContext>()
.ok_or_else(|| file_system::Error::InvalidParameter)?;

if buffer.len() < hash_context.hasher.output_size() {
return Err(Error::InvalidParameter);
}

let result = hash_context.hasher.clone().finalize();
let length = result.len();
buffer[..length].copy_from_slice(&result);
Ok(length)
}

fn write(&self, context: &mut Context, buffer: &[u8], _: Size) -> Result<usize> {
let hash_context = context
.get_private_data_mutable_of_type::<HashDeviceContext>()
.ok_or_else(|| file_system::Error::InvalidParameter)?;

hash_context.hasher.update(buffer);
Ok(buffer.len())
}

fn control(
&self,
context: &mut Context,
command: ControlCommand,
argument: &mut ControlArgument,
) -> Result<()> {
let hash_context = context
.get_private_data_mutable_of_type::<HashDeviceContext>()
.ok_or_else(|| file_system::Error::InvalidParameter)?;

match command {
hash::RESET => {
hash_context.hasher.reset();
Ok(())
}
hash::SET_ALGORITHM => {
let algorithm = argument
.cast::<HashAlgorithm>()
.ok_or_else(|| file_system::Error::InvalidParameter)?;

*hash_context = HashDeviceContext::new(*algorithm)?;
Ok(())
}
_ => Err(file_system::Error::UnsupportedOperation),
}
}

fn clone_context(&self, context: &Context) -> Result<Context> {
let hash_context = context
.get_private_data_of_type::<HashDeviceContext>()
.ok_or_else(|| file_system::Error::InvalidParameter)?;

Ok(Context::new(Some(hash_context.clone())))
}
}

impl MountOperations for HashDevice {}

impl CharacterDevice for HashDevice {}
2 changes: 2 additions & 0 deletions drivers/shared/src/devices/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
mod hash;
mod random;

pub use hash::*;
pub use random::*;
7 changes: 6 additions & 1 deletion examples/native/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,12 @@ async fn main() {
CharacterDevice,
drivers_shared::devices::RandomDevice
),
(&"/devices/null", CharacterDevice, drivers_core::NullDevice)
(&"/devices/null", CharacterDevice, drivers_core::NullDevice),
(
&"/devices/hasher",
CharacterDevice,
drivers_shared::devices::HashDevice
),
]
)
.await
Expand Down
5 changes: 5 additions & 0 deletions examples/wasm/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,11 @@ async fn main() {
CharacterDevice,
drivers_wasm::devices::HttpClientDevice
),
(
&"/devices/hasher",
CharacterDevice,
drivers_shared::devices::HashDevice
),
]
)
.await
Expand Down
3 changes: 1 addition & 2 deletions modules/authentication/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ virtual_file_system = { workspace = true }
users = { workspace = true }
task = { workspace = true }
file_system = { workspace = true }
device = { workspace = true }

# External dependencies
sha2 = { version = "0.10", features = ["asm"] } # SHA-512 cryptographic hashing
miniserde = { workspace = true }
5 changes: 5 additions & 0 deletions modules/authentication/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ pub enum Error {
FailedToGetUserIdentifier(users::Error),
/// Failed to close a file
FailedToCloseFile(virtual_file_system::Error),
/// Failed to hash
FailedToHashPassword(virtual_file_system::Error),
}

impl Display for Error {
Expand Down Expand Up @@ -160,6 +162,9 @@ impl Display for Error {
Self::FailedToCloseFile(error) => {
write!(formatter, "Failed to close file: {error}")
}
Self::FailedToHashPassword(error) => {
write!(formatter, "Failed to hash password: {error}")
}
}
}
}
Expand Down
62 changes: 49 additions & 13 deletions modules/authentication/src/hash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@ use alloc::{
format,
string::{String, ToString},
};
use virtual_file_system::File;
use device::hash::{HashAlgorithm, SET_ALGORITHM};
use file_system::AccessFlags;
use task::TaskIdentifier;
use virtual_file_system::{File, VirtualFileSystem};

use crate::{Error, RANDOM_DEVICE_PATH, Result};

Expand All @@ -40,11 +43,10 @@ use crate::{Error, RANDOM_DEVICE_PATH, Result};
///
/// The salt generation converts random bytes to lowercase letters (a-z)
/// for readability while maintaining sufficient entropy for security.
pub async fn generate_salt() -> Result<String> {
let virtual_file_system = virtual_file_system::get_instance();

let task = task::get_instance().get_current_task_identifier().await;

pub async fn generate_salt(
virtual_file_system: &VirtualFileSystem<'_>,
task: TaskIdentifier,
) -> Result<String> {
let mut buffer = [0_u8; 16];

File::read_slice_from_path(virtual_file_system, task, RANDOM_DEVICE_PATH, &mut buffer)
Expand Down Expand Up @@ -78,15 +80,49 @@ pub async fn generate_salt() -> Result<String> {
/// This function uses SHA-512, which is cryptographically secure and resistant
/// to collision attacks. The salt prevents rainbow table attacks and ensures
/// that identical passwords have different hashes.
pub fn hash_password(password: &str, salt: &str) -> String {
use sha2::Digest;
pub async fn hash_password(
virtual_file_system: &VirtualFileSystem<'_>,
task: TaskIdentifier,
password: &str,
salt: &str,
) -> Result<String> {
let mut file = File::open(
virtual_file_system,
task,
"/devices/hasher",
AccessFlags::READ_WRITE.into(),
)
.await
.map_err(Error::FailedToHashPassword)?;

let mut algorithm = HashAlgorithm::Sha512;

file.control(SET_ALGORITHM, &mut algorithm)
.await
.map_err(Error::FailedToHashPassword)?;

file.write(password.as_bytes())
.await
.map_err(Error::FailedToHashPassword)?;

file.write(salt.as_bytes())
.await
.map_err(Error::FailedToHashPassword)?;

let mut hasher = sha2::Sha512::new();
let mut hash_buffer = [0_u8; 512 / 8];

hasher.update(password.as_bytes());
hasher.update(salt.as_bytes());
file.read(&mut hash_buffer)
.await
.map_err(Error::FailedToHashPassword)?;

file.close(virtual_file_system)
.await
.map_err(Error::FailedToCloseFile)?;

let hash = hasher.finalize();
let hash = hash_buffer
.iter()
.map(|byte| format!("{:02x}", byte))
.collect::<String>();

format!("{hash:x}")
Ok(hash)
}
28 changes: 15 additions & 13 deletions modules/authentication/src/user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,14 +204,11 @@ pub async fn authenticate_user<'a>(
) -> Result<UserIdentifier> {
let path = get_user_file_path(user_name)?;

let mut user_file = File::open(
virtual_file_system,
task::get_instance().get_current_task_identifier().await,
path,
AccessFlags::Read.into(),
)
.await
.map_err(Error::FailedToOpenUserFile)?;
let task = task::get_instance().get_current_task_identifier().await;

let mut user_file = File::open(virtual_file_system, task, path, AccessFlags::Read.into())
.await
.map_err(Error::FailedToOpenUserFile)?;

let mut buffer = Vec::new();

Expand All @@ -228,7 +225,10 @@ pub async fn authenticate_user<'a>(
let user: User = miniserde::json::from_str(core::str::from_utf8(&buffer).unwrap())
.map_err(Error::FailedToParseUserFile)?;

if hash_password(password, user.get_salt()) == user.get_hash() {
let hashed_password =
hash_password(virtual_file_system, task, password, user.get_salt()).await?;

if hashed_password == user.get_hash() {
Ok(user.get_identifier())
} else {
Err(Error::InvalidPassword)
Expand Down Expand Up @@ -289,9 +289,11 @@ pub async fn create_user<'a>(
.map_err(Error::FailedToCreateUser)?;

// - Hash password.
let salt = generate_salt().await?;
let task = task::get_instance().get_current_task_identifier().await;

let salt = generate_salt(virtual_file_system, task).await?;

let hash = hash_password(password, &salt);
let hash = hash_password(virtual_file_system, task, password, &salt).await?;

// - Write user file.
let user = User::new(
Expand Down Expand Up @@ -360,9 +362,9 @@ pub async fn change_user_password<'a>(
) -> Result<()> {
let task = task::get_instance().get_current_task_identifier().await;

let salt = generate_salt().await?;
let salt = generate_salt(virtual_file_system, task).await?;

let hash = hash_password(new_password, &salt);
let hash = hash_password(virtual_file_system, task, new_password, &salt).await?;

let user_file_path = Path::new(USERS_FOLDER_PATH)
.to_owned()
Expand Down
7 changes: 7 additions & 0 deletions modules/device/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "device"
version = "0.1.0"
edition = "2024"

[dependencies]
file_system = { workspace = true }
18 changes: 18 additions & 0 deletions modules/device/src/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use file_system::{ControlCommand, ControlDirectionFlags};

#[repr(u8)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HashAlgorithm {
Md5 = 0,
Sha1 = 1,
Sha224 = 2,
Sha256 = 3,
Sha384 = 4,
Sha512 = 5,
Sha512_224 = 6,
Sha512_256 = 7,
}

pub const RESET: ControlCommand = ControlCommand::new::<()>(ControlDirectionFlags::Write, b'H', 0);
pub const SET_ALGORITHM: ControlCommand =
ControlCommand::new::<HashAlgorithm>(ControlDirectionFlags::Write, b'H', 1);
1 change: 1 addition & 0 deletions modules/device/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod hash;
7 changes: 6 additions & 1 deletion modules/testing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,12 @@ pub async fn initialize(graphics_enabled: bool) -> Standard {
CharacterDevice,
drivers_std::devices::TimeDevice
),
(&"/devices/null", CharacterDevice, drivers_core::NullDevice)
(&"/devices/null", CharacterDevice, drivers_core::NullDevice),
(
&"/devices/hasher",
CharacterDevice,
drivers_shared::devices::HashDevice
),
]
)
.await
Expand Down
Loading