Skip to content

#44 password hasher threading #46

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 13, 2024
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
77 changes: 75 additions & 2 deletions src/argon2.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{
ffi::{c_char, CStr, CString},
slice, thread,
ffi::{c_char, CStr, CString}, slice, sync::mpsc, thread
};

extern crate rayon;
Expand Down Expand Up @@ -75,6 +74,48 @@ fn argon2_verify_fail_test() {
assert_eq!(false, is_valid);
}

#[no_mangle]
pub extern "C" fn argon2_verify_threadpool(hashed_pass: *const c_char, password: *const c_char) -> bool {
let hashed_pass_string = unsafe {
assert!(!hashed_pass.is_null());
CStr::from_ptr(hashed_pass)
}
.to_str()
.unwrap();

let password_string = unsafe {
assert!(!password.is_null());
CStr::from_ptr(password)
}
.to_str()
.unwrap()
.as_bytes();
let (sender, receiver) = mpsc::channel();
rayon::spawn(move || {
let parsed_hash = PasswordHash::new(&hashed_pass_string).unwrap();
let thread_result = Argon2::default()
.verify_password(password_string, &parsed_hash)
.is_ok();
sender.send(thread_result);
});
let result = receiver.recv().unwrap();
result
}

#[test]
fn argon2_verify_threadpool_test() {
let password = "PasswordToVerify";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let password_ptr = password_bytes.as_ptr() as *const i8;
let hashed_password = argon2_hash_threadpool(password_ptr);
let hashed_password_ctr = unsafe { CString::from_raw(hashed_password) };
let hashed_password_bytes = hashed_password_ctr.as_bytes_with_nul();
let hashed_password_ptr = hashed_password_bytes.as_ptr() as *const i8;
let is_valid = argon2_verify_threadpool(hashed_password_ptr, password_ptr);
assert_eq!(true, is_valid);
}

#[no_mangle]
pub extern "C" fn argon2_verify_thread(
hashed_pass: *const c_char,
Expand Down Expand Up @@ -148,6 +189,38 @@ fn argon2_hash_test() {
assert_ne!(password, hashed_password_str);
}

#[no_mangle]
pub extern "C" fn argon2_hash_threadpool(pass_to_hash: *const c_char) -> *mut c_char {
let pass_bytes = unsafe {
assert!(!pass_to_hash.is_null());
CStr::from_ptr(pass_to_hash)
}
.to_str()
.unwrap()
.as_bytes();
let (sender, receiver) = mpsc::channel();
rayon::spawn(move || {
let salt = SaltString::generate(&mut OsRng);
let argon2 = Argon2::default();
let password_hash = argon2.hash_password(pass_bytes, &salt).unwrap().to_string();
sender.send(password_hash);
});
let result = CString::new(receiver.recv().unwrap()).unwrap().into_raw();
result
}

#[test]
fn argon2_hash_threadpool_test() {
let password = "DontUseThisPassword";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let password_ptr = password_bytes.as_ptr() as *const i8;
let hashed_password_ptr = argon2_hash_threadpool(password_ptr);
let hashed_password_ctr = unsafe { CString::from_raw(hashed_password_ptr) };
let hashed_password_str = hashed_password_ctr.to_str().unwrap();
assert_ne!(password, hashed_password_str);
}

#[no_mangle]
pub extern "C" fn argon2_hash_thread(
passwords_to_hash: *const *const c_char,
Expand Down
67 changes: 57 additions & 10 deletions src/bcrypt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use std::{
ffi::{c_char, CStr, CString},
thread,
ffi::{c_char, CStr, CString}, sync::mpsc, thread
};

use bcrypt::{hash, verify, DEFAULT_COST};
Expand Down Expand Up @@ -31,6 +30,36 @@ fn bcrypt_hash_test() {
assert_ne!(hashed_password_str, password);
}

#[no_mangle]
pub extern "C" fn bcrypt_hash_threadpool(pass_to_hash: *const c_char) -> *mut c_char {
let string_pass = unsafe {
assert!(!pass_to_hash.is_null());

CStr::from_ptr(pass_to_hash)
}
.to_str()
.unwrap();
let (sender, receiver) = mpsc::channel();
rayon::spawn(move || {
let hashed_password = hash(string_pass, DEFAULT_COST).unwrap();
sender.send(hashed_password);
});
let result = CString::new(receiver.recv().unwrap()).unwrap().into_raw();
result
}

#[test]
fn bcrypt_hash_threadpool_test() {
let password = "PasswordToHash";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let passsword_ptr = password_bytes.as_ptr() as *const i8;
let hashed_password = bcrypt_hash_threadpool(passsword_ptr);
let hashed_password_ctr = unsafe { CString::from_raw(hashed_password) };
let hashed_password_str = hashed_password_ctr.to_str().unwrap();
assert_ne!(hashed_password_str, password);
}

#[no_mangle]
pub extern "C" fn bcrypt_verify(pass: *const c_char, hash: *const c_char) -> bool {
let string_pass = unsafe {
Expand All @@ -51,8 +80,22 @@ pub extern "C" fn bcrypt_verify(pass: *const c_char, hash: *const c_char) -> boo
return verify(string_pass, string_hash).unwrap();
}

#[test]
fn bcrypt_verify_test() {
let password = "PasswordToHash";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let password_ptr = password_bytes.as_ptr() as *const i8;
let hashed_password = bcrypt_hash(password_ptr);
let hashed_password_ctr = unsafe { CString::from_raw(hashed_password) };
let hashed_password_bytes = hashed_password_ctr.as_bytes_with_nul();
let hashed_password_ptr = hashed_password_bytes.as_ptr() as *const i8;
let is_valid = bcrypt_verify(password_ptr, hashed_password_ptr);
assert_eq!(true, is_valid);
}

#[no_mangle]
pub extern "C" fn bcrypt_verify_thread(pass: *const c_char, hash: *const c_char) -> bool {
pub extern "C" fn bcrypt_verify_threadpool(pass: *const c_char, hash: *const c_char) -> bool {
let string_pass = unsafe {
assert!(!pass.is_null());

Expand All @@ -68,21 +111,25 @@ pub extern "C" fn bcrypt_verify_thread(pass: *const c_char, hash: *const c_char)
}
.to_str()
.unwrap();
return thread::spawn(move || return verify(string_pass, string_hash).unwrap())
.join()
.unwrap();
let (sender, receiver) = mpsc::channel();
rayon::spawn(move || {
let thread_result = verify(string_pass, string_hash).unwrap();
sender.send(thread_result);
});
let result = receiver.recv().unwrap();
result
}

#[test]
fn bcrypt_verify_test() {
fn bcrypt_verify_threadpool_test() {
let password = "PasswordToHash";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let password_ptr = password_bytes.as_ptr() as *const i8;
let hashed_password = bcrypt_hash(password_ptr);
let hashed_password = bcrypt_hash_threadpool(password_ptr);
let hashed_password_ctr = unsafe { CString::from_raw(hashed_password) };
let hashed_password_bytes = hashed_password_ctr.as_bytes_with_nul();
let hashed_password_ptr = hashed_password_bytes.as_ptr() as *const i8;
let is_valid = bcrypt_verify(password_ptr, hashed_password_ptr);
let is_valid = bcrypt_verify_threadpool(password_ptr, hashed_password_ptr);
assert_eq!(true, is_valid);
}
}
82 changes: 81 additions & 1 deletion src/scrypt.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::ffi::{c_char, CStr, CString};
use std::{ffi::{c_char, CStr, CString}, sync::mpsc};

use scrypt::{
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
Expand Down Expand Up @@ -35,6 +35,40 @@ fn scrypt_hash_test() {
assert_ne!(hashed_str, password);
}

#[no_mangle]
pub extern "C" fn scrypt_hash_threadpool(pass_to_hash: *const c_char) -> *mut c_char {
let string_pass = unsafe {
assert!(!pass_to_hash.is_null());

CStr::from_ptr(pass_to_hash)
}
.to_str()
.unwrap();
let (sender, receiver) = mpsc::channel();
rayon::spawn(move || {
let salt = SaltString::generate(&mut OsRng);
let hashed = Scrypt
.hash_password(string_pass.as_bytes(), &salt)
.unwrap()
.to_string();
sender.send(hashed);
});
let result = CString::new(receiver.recv().unwrap()).unwrap().into_raw();
result
}

#[test]
fn scrypt_hash_threadpool_test() {
let password = "PasswordToTest";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let password_ptr = password_bytes.as_ptr() as *const i8;
let hashed = scrypt_hash_threadpool(password_ptr);
let hashed_ctr = unsafe { CString::from_raw(hashed) };
let hashed_str = hashed_ctr.to_str().unwrap();
assert_ne!(hashed_str, password);
}

#[no_mangle]
pub extern "C" fn scrypt_verify(
pass_to_check: *const c_char,
Expand Down Expand Up @@ -75,3 +109,49 @@ fn scrypt_verify_test() {
let is_valid = scrypt_verify(password_ptr, hashed_ptr);
assert_eq!(true, is_valid);
}

#[no_mangle]
pub extern "C" fn scrypt_verify_threadpool(
pass_to_check: *const c_char,
hash_to_check: *const c_char,
) -> bool {
let string_pass = unsafe {
assert!(!pass_to_check.is_null());

CStr::from_ptr(pass_to_check)
}
.to_str()
.unwrap();

let string_hash = unsafe {
assert!(!hash_to_check.is_null());

CStr::from_ptr(hash_to_check)
}
.to_str()
.unwrap();
let (sender, receiver) = mpsc::channel();
rayon::spawn(move || {
let parsed_hash = PasswordHash::new(&string_hash).unwrap();
let thread_result = Scrypt
.verify_password(string_pass.as_bytes(), &parsed_hash)
.is_ok();
sender.send(thread_result);
});
let result = receiver.recv().unwrap();
result
}

#[test]
fn scrypt_verify_threadpool_test() {
let password = "NotThePasswordYouAreLookingFor";
let password_cstr = CString::new(password).unwrap();
let password_bytes = password_cstr.as_bytes_with_nul();
let password_ptr = password_bytes.as_ptr() as *const i8;
let hash = scrypt_hash_threadpool(password_ptr);
let hash_ctr = unsafe { CString::from_raw(hash) };
let hashed_bytes = hash_ctr.as_bytes_with_nul();
let hashed_ptr = hashed_bytes.as_ptr() as *const i8;
let is_valid = scrypt_verify_threadpool(password_ptr, hashed_ptr);
assert_eq!(true, is_valid);
}
Loading