diff --git a/src/argon2.rs b/src/argon2.rs index 8001d61..4ad878a 100644 --- a/src/argon2.rs +++ b/src/argon2.rs @@ -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; @@ -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, @@ -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, diff --git a/src/bcrypt.rs b/src/bcrypt.rs index 0dd56ab..def6296 100644 --- a/src/bcrypt.rs +++ b/src/bcrypt.rs @@ -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}; @@ -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 { @@ -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()); @@ -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); -} +} \ No newline at end of file diff --git a/src/scrypt.rs b/src/scrypt.rs index 81fc18e..a0cd509 100644 --- a/src/scrypt.rs +++ b/src/scrypt.rs @@ -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}, @@ -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, @@ -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); +} \ No newline at end of file