use crate::shared::{CryptoProvider, INITIALIZED, Provider, STATE};
use libsodium_rs::crypto_sign;
use std::{mem, ptr::slice_from_raw_parts, slice::from_raw_parts, sync::atomic::Ordering, vec};
pub trait ProviderBeacon {
fn get_registration_bundle(&self) -> Option<Vec<u8>>;
fn finish_registration(&mut self, bytes: &[u8]) -> Option<Vec<u8>>;
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn process_initial_message(
bytes: *const u8,
bytes_len: usize,
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
if bytes.is_null() || bytes_len == 0 {
return -1;
}
let data_slice = unsafe { from_raw_parts(bytes, bytes_len) };
let mut state = STATE.lock().unwrap();
match state.finish_registration(data_slice) {
Some(mut plaintext) => {
unsafe {
*_out = plaintext.as_mut_ptr();
*out_len = plaintext.len();
*out_capa = plaintext.capacity();
mem::forget(plaintext);
};
0i32
}
None => -1i32,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn process_initial_message_signed(
bytes: *const u8,
bytes_len: usize,
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
if bytes.is_null() || bytes_len == 0 {
return -1;
}
let data_slice = unsafe { from_raw_parts(bytes, bytes_len) };
let mut state = STATE.lock().unwrap();
match state.verify_signature(data_slice) {
Some(verified) => match state.finish_registration(&verified.data) {
Some(mut plaintext) => {
unsafe {
*_out = plaintext.as_mut_ptr();
*out_len = plaintext.len();
*out_capa = plaintext.capacity();
mem::forget(plaintext);
};
0i32
}
None => -1i32,
},
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn decrypt_server_message(
bytes: *const u8,
bytes_len: usize,
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
if bytes.is_null() || bytes_len == 0 {
return -1;
}
let mut state = STATE.lock().unwrap();
let data_slice = unsafe { from_raw_parts(bytes, bytes_len) };
let srv_kid = state.server_kid();
match state.decrypt_message(data_slice, srv_kid) {
Some(mut plaintext) => {
unsafe {
*_out = plaintext.as_mut_ptr();
*out_len = plaintext.len();
*out_capa = plaintext.capacity();
mem::forget(plaintext);
};
0
}
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn decrypt_server_message_signed(
bytes: *const u8,
bytes_len: usize,
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
if bytes.is_null() || bytes_len == 0 {
return -1;
}
let mut state = STATE.lock().unwrap();
let data_slice = unsafe { from_raw_parts(bytes, bytes_len) };
match state.verify_signature(data_slice) {
Some(verified) => {
let srv_kid = state.server_kid();
match state.decrypt_message(&verified.data, srv_kid) {
Some(mut plaintext) => {
unsafe {
*_out = plaintext.as_mut_ptr();
*out_len = plaintext.len();
*out_capa = plaintext.capacity();
mem::forget(plaintext);
};
0
}
None => -1,
}
}
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn encrypt_to_server(
bytes: *const u8,
bytes_len: usize,
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
if bytes.is_null() || bytes_len == 0 {
return -1;
}
let mut state = STATE.lock().unwrap();
let data_slice = unsafe { from_raw_parts(bytes, bytes_len) };
let srv_kid = state.server_kid();
match state.encrypt_message(data_slice, srv_kid) {
Some(mut ciphertext) => {
unsafe {
*_out = ciphertext.as_mut_ptr();
*out_len = ciphertext.len();
*out_capa = ciphertext.capacity();
mem::forget(ciphertext);
};
0
}
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn encrypt_to_server_signed(
bytes: *const u8,
bytes_len: usize,
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
if bytes.is_null() || bytes_len == 0 {
return -1;
}
let mut state = STATE.lock().unwrap();
let data_slice = unsafe { from_raw_parts(bytes, bytes_len) };
let srv_kid = state.server_kid();
match state.encrypt_message(data_slice, srv_kid) {
Some(ciphertext) => match state.sign_message(ciphertext.as_slice()) {
Some(mut signed) => {
unsafe {
*_out = signed.as_mut_ptr();
*out_len = signed.len();
*out_capa = signed.capacity();
mem::forget(signed);
};
0
}
None => -1,
},
None => -1,
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn generate_registration(
mut _out: *mut *mut u8,
out_len: *mut usize,
out_capa: *mut usize,
) -> i32 {
let state = STATE.lock().unwrap();
match state.get_registration_bundle() {
Some(mut data) => {
unsafe {
*_out = data.as_mut_ptr();
*out_len = data.len();
*out_capa = data.capacity();
mem::forget(data);
};
0
}
None => -1,
}
}
#[unsafe(no_mangle)]
pub extern "C" fn init_for_server(
is_beacon: bool,
server_kid: u64,
server_pk: *const u8,
server_pk_len: u64,
) {
if !INITIALIZED.swap(true, Ordering::AcqRel) {
let mut state = STATE.lock().unwrap();
let pk_slice = slice_from_raw_parts(server_pk, server_pk_len.try_into().unwrap());
let mut pk_vec = vec![0u8; crypto_sign::PUBLICKEYBYTES];
pk_vec.copy_from_slice(unsafe { pk_slice.as_ref().unwrap() });
*state = Provider::new(is_beacon, server_kid, Some(&pk_vec), None);
}
}