mirror of
https://github.com/bitwarden/server
synced 2025-12-15 07:43:54 +00:00
105 lines
3.2 KiB
Rust
105 lines
3.2 KiB
Rust
#![allow(clippy::missing_safety_doc)]
|
|
use std::{
|
|
ffi::{c_char, CStr, CString},
|
|
num::NonZeroU32,
|
|
};
|
|
|
|
use base64::{engine::general_purpose::STANDARD, Engine};
|
|
|
|
use bitwarden_crypto::{
|
|
AsymmetricPublicCryptoKey, BitwardenLegacyKeyBytes, HashPurpose, Kdf, MasterKey,
|
|
SpkiPublicKeyBytes, SymmetricCryptoKey, UnsignedSharedKey, UserKey,
|
|
};
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn generate_user_keys(
|
|
email: *const c_char,
|
|
password: *const c_char,
|
|
) -> *const c_char {
|
|
// TODO: We might want to make KDF configurable in the future.
|
|
let kdf = Kdf::PBKDF2 {
|
|
iterations: NonZeroU32::new(5_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 master_password_hash = master_key
|
|
.derive_master_key_hash(password.as_bytes(), HashPurpose::ServerAuthorization)
|
|
.unwrap();
|
|
let (user_key, encrypted_user_key) = master_key.make_user_key().unwrap();
|
|
let keypair = user_key.make_key_pair().unwrap();
|
|
|
|
let json = serde_json::json!({
|
|
"masterPasswordHash": master_password_hash,
|
|
"key": user_key.0.to_base64(),
|
|
"encryptedUserKey": encrypted_user_key.to_string(),
|
|
"publicKey": keypair.public.to_string(),
|
|
"privateKey": keypair.private.to_string(),
|
|
})
|
|
.to_string();
|
|
|
|
let result = CString::new(json).unwrap();
|
|
|
|
result.into_raw()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn generate_organization_keys() -> *const c_char {
|
|
let key = SymmetricCryptoKey::make_aes256_cbc_hmac_key();
|
|
|
|
let key = UserKey::new(key);
|
|
let keypair = key.make_key_pair().expect("Failed to generate key pair");
|
|
|
|
let json = serde_json::json!({
|
|
"key": key.0.to_base64(),
|
|
"publicKey": keypair.public.to_string(),
|
|
"privateKey": keypair.private.to_string(),
|
|
})
|
|
.to_string();
|
|
|
|
let result = CString::new(json).unwrap();
|
|
|
|
result.into_raw()
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe extern "C" fn generate_user_organization_key(
|
|
user_public_key: *const c_char,
|
|
organization_key: *const c_char,
|
|
) -> *const c_char {
|
|
let user_public_key = CStr::from_ptr(user_public_key).to_str().unwrap().to_owned();
|
|
let organization_key = CStr::from_ptr(organization_key)
|
|
.to_str()
|
|
.unwrap()
|
|
.to_owned();
|
|
|
|
let user_public_key = STANDARD.decode(user_public_key).unwrap();
|
|
let organization_key = STANDARD.decode(organization_key).unwrap();
|
|
|
|
let encapsulation_key =
|
|
AsymmetricPublicCryptoKey::from_der(&SpkiPublicKeyBytes::from(user_public_key)).unwrap();
|
|
|
|
let encrypted_key = UnsignedSharedKey::encapsulate_key_unsigned(
|
|
&SymmetricCryptoKey::try_from(&BitwardenLegacyKeyBytes::from(organization_key)).unwrap(),
|
|
&encapsulation_key,
|
|
)
|
|
.unwrap();
|
|
|
|
let result = CString::new(encrypted_key.to_string()).unwrap();
|
|
|
|
result.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));
|
|
}
|
|
}
|