mirror of
https://github.com/bitwarden/server
synced 2025-12-15 07:43:54 +00:00
Add hash password
This commit is contained in:
19
util/RustSdk/RustSdkException.cs
Normal file
19
util/RustSdk/RustSdkException.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace Bit.RustSDK;
|
||||
|
||||
/// <summary>
|
||||
/// Exception thrown when the Rust SDK operations fail
|
||||
/// </summary>
|
||||
public class RustSdkException : Exception
|
||||
{
|
||||
public RustSdkException() : base("An error occurred in the Rust SDK operation")
|
||||
{
|
||||
}
|
||||
|
||||
public RustSdkException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
|
||||
public RustSdkException(string message, Exception innerException) : base(message, innerException)
|
||||
{
|
||||
}
|
||||
}
|
||||
83
util/RustSdk/RustSdkService.cs
Normal file
83
util/RustSdk/RustSdkService.cs
Normal file
@@ -0,0 +1,83 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Bit.RustSDK;
|
||||
|
||||
/// <summary>
|
||||
/// Service implementation that provides a C# friendly interface to the Rust SDK
|
||||
/// </summary>
|
||||
public class RustSdkService
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds two integers using the native implementation
|
||||
/// </summary>
|
||||
/// <param name="x">First integer</param>
|
||||
/// <param name="y">Second integer</param>
|
||||
/// <returns>The sum of x and y</returns>
|
||||
public int Add(int x, int y)
|
||||
{
|
||||
try
|
||||
{
|
||||
return NativeMethods.my_add(x, y);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RustSdkException($"Failed to perform addition operation: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hashes a password using the native implementation
|
||||
/// </summary>
|
||||
/// <param name="email">User email</param>
|
||||
/// <param name="password">User password</param>
|
||||
/// <returns>The hashed password as a string</returns>
|
||||
/// <exception cref="ArgumentNullException">Thrown when email or password is null</exception>
|
||||
/// <exception cref="ArgumentException">Thrown when email or password is empty</exception>
|
||||
/// <exception cref="RustSdkException">Thrown when the native operation fails</exception>
|
||||
public unsafe string HashPassword(string email, string password)
|
||||
{
|
||||
// Convert strings to null-terminated byte arrays
|
||||
var emailBytes = Encoding.UTF8.GetBytes(email + '\0');
|
||||
var passwordBytes = Encoding.UTF8.GetBytes(password + '\0');
|
||||
|
||||
try
|
||||
{
|
||||
fixed (byte* emailPtr = emailBytes)
|
||||
fixed (byte* passwordPtr = passwordBytes)
|
||||
{
|
||||
var resultPtr = NativeMethods.hash_password(emailPtr, passwordPtr);
|
||||
|
||||
var result = TakeAndDestroyRustString(resultPtr);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
catch (RustSdkException)
|
||||
{
|
||||
throw; // Re-throw our custom exceptions
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw new RustSdkException($"Failed to hash password: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static unsafe string TakeAndDestroyRustString(byte* ptr)
|
||||
{
|
||||
if (ptr == null)
|
||||
{
|
||||
throw new RustSdkException("Pointer is null");
|
||||
}
|
||||
|
||||
var result = Marshal.PtrToStringUTF8((IntPtr)ptr);
|
||||
NativeMethods.free_c_string(ptr);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
throw new RustSdkException("Failed to convert native result to string");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
30
util/RustSdk/RustSdkServiceFactory.cs
Normal file
30
util/RustSdk/RustSdkServiceFactory.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
namespace Bit.RustSDK;
|
||||
|
||||
/// <summary>
|
||||
/// Factory for creating Rust SDK service instances
|
||||
/// </summary>
|
||||
public static class RustSdkServiceFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new instance of the Rust SDK service
|
||||
/// </summary>
|
||||
/// <returns>A new IRustSdkService instance</returns>
|
||||
public static RustSdkService Create()
|
||||
{
|
||||
return new RustSdkService();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a singleton instance of the Rust SDK service (thread-safe)
|
||||
/// </summary>
|
||||
/// <returns>A singleton IRustSdkService instance</returns>
|
||||
public static RustSdkService CreateSingleton()
|
||||
{
|
||||
return SingletonHolder.Instance;
|
||||
}
|
||||
|
||||
private static class SingletonHolder
|
||||
{
|
||||
internal static readonly RustSdkService Instance = new RustSdkService();
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,49 @@
|
||||
use std::{
|
||||
ffi::{c_char, CStr, CString},
|
||||
num::NonZeroU32,
|
||||
};
|
||||
|
||||
use bitwarden_crypto::{HashPurpose, Kdf, MasterKey};
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn my_add(x: i32, y: i32) -> i32 {
|
||||
x + y
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// The `email` and `password` pointers must be valid null-terminated C strings.
|
||||
/// Both pointers must be non-null and point to valid memory for the duration of the function call.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn hash_password(
|
||||
email: *const c_char,
|
||||
password: *const c_char,
|
||||
) -> *const c_char {
|
||||
let kdf = Kdf::PBKDF2 {
|
||||
iterations: NonZeroU32::new(600_000).unwrap(),
|
||||
};
|
||||
|
||||
let email = CStr::from_ptr(email).to_str().unwrap();
|
||||
let password = CStr::from_ptr(password).to_str().unwrap();
|
||||
|
||||
let master_key = MasterKey::derive(password, email, &kdf).unwrap();
|
||||
|
||||
let res = master_key
|
||||
.derive_master_key_hash(password.as_bytes(), HashPurpose::ServerAuthorization)
|
||||
.unwrap();
|
||||
|
||||
let res = CString::new(res).unwrap();
|
||||
|
||||
res.into_raw()
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// The `str` pointer must be a valid pointer previously returned by `CString::into_raw`
|
||||
/// and must not have already been freed. After calling this function, the pointer must not be used again.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn free_c_string(str: *mut c_char) {
|
||||
unsafe {
|
||||
drop(CString::from_raw(str));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,12 +8,16 @@ public class UserSeeder
|
||||
{
|
||||
public static User CreateUser(string email)
|
||||
{
|
||||
var nativeService = RustSdkServiceFactory.CreateSingleton();
|
||||
Console.WriteLine(NativeMethods.my_add(2, 3));
|
||||
|
||||
var password = nativeService.HashPassword(email, "asdfasdfasdf");
|
||||
|
||||
return new User
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Email = email,
|
||||
MasterPassword = "AQAAAAIAAYagAAAAEBATmF66OHMpHuHKc1CsGZQ1ltHUHyhYK+7e4re3bVFi16SOpLpDfzdFswnvFQs2Rg==",
|
||||
MasterPassword = password,
|
||||
SecurityStamp = "4830e359-e150-4eae-be2a-996c81c5e609",
|
||||
Key = "2.z/eLKFhd62qy9RzXu3UHgA==|fF6yNupiCIguFKSDTB3DoqcGR0Xu4j+9VlnMyT5F3PaWIcGhzQKIzxdB95nhslaCQv3c63M7LBnvzVo1J9SUN85RMbP/57bP1HvhhU1nvL8=|IQPtf8v7k83MFZEhazSYXSdu98BBU5rqtvC4keVWyHM=",
|
||||
PublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0Ww2chogqCpaAR7Uw448am4b7vDFXiM5kXjFlGfXBlrAdAqTTggEvTDlMNYqPlCo+mBM6iFmTTUY9rpZBvFskMnKvsvpJ47/fehAH2o2e3Ulv/5NFevaVCMCmpkBDtbMbO1A4a3btdRtCP8DsKWMefHauEpaoLxNTLWnOIZVfCMjsSgx2EvULHAZPTtbFwm4+UVKniM4ds4jvOsD85h4jn2aLs/jWJXFfxN8iVSqEqpC2TBvsPdyHb49xQoWWfF0Z6BiNqeNGKEU9Uos1pjL+kzhEzzSpH31PZT/ufJ/oo4+93wrUt57hb6f0jxiXhwd5yQ+9F6wVwpbfkq0IwhjOwIDAQAB",
|
||||
|
||||
Reference in New Issue
Block a user