use std::os::raw::c_void;
use std::ptr;
use bindings::{
secure_comparator_append_secret, secure_comparator_begin_compare, secure_comparator_create,
secure_comparator_destroy, secure_comparator_get_result, secure_comparator_proceed_compare,
secure_comparator_t,
};
use crate::error::{Error, ErrorKind, Result};
use crate::utils::into_raw_parts;
#[derive(Debug)]
pub struct SecureComparator {
comp_ctx: *mut secure_comparator_t,
}
unsafe impl Send for SecureComparator {}
impl SecureComparator {
pub fn new() -> Self {
match SecureComparator::try_new() {
Ok(comparator) => comparator,
Err(e) => panic!("secure_comparator_create() failed: {}", e),
}
}
fn try_new() -> Result<Self> {
let comp_ctx = unsafe { secure_comparator_create() };
if comp_ctx.is_null() {
return Err(Error::with_kind(ErrorKind::NoMemory));
}
Ok(Self { comp_ctx })
}
pub fn append_secret(&mut self, secret: impl AsRef<[u8]>) -> Result<()> {
let (secret_ptr, secret_len) = into_raw_parts(secret.as_ref());
unsafe {
let status = secure_comparator_append_secret(
self.comp_ctx,
secret_ptr as *const c_void,
secret_len,
);
let error = Error::from_compare_status(status);
if error.kind() != ErrorKind::Success {
return Err(error);
}
}
Ok(())
}
pub fn begin_compare(&mut self) -> Result<Vec<u8>> {
let mut compare_data = Vec::new();
let mut compare_data_len = 0;
unsafe {
let status = secure_comparator_begin_compare(
self.comp_ctx,
ptr::null_mut(),
&mut compare_data_len,
);
let error = Error::from_compare_status(status);
if error.kind() != ErrorKind::BufferTooSmall {
return Err(error);
}
}
compare_data.reserve(compare_data_len);
unsafe {
let status = secure_comparator_begin_compare(
self.comp_ctx,
compare_data.as_mut_ptr() as *mut c_void,
&mut compare_data_len,
);
let error = Error::from_compare_status(status);
if error.kind() != ErrorKind::CompareSendOutputToPeer {
return Err(error);
}
debug_assert!(compare_data_len <= compare_data.capacity());
compare_data.set_len(compare_data_len);
}
Ok(compare_data)
}
pub fn proceed_compare(&mut self, peer_data: impl AsRef<[u8]>) -> Result<Vec<u8>> {
let (peer_compare_data_ptr, peer_compare_data_len) = into_raw_parts(peer_data.as_ref());
let mut compare_data = Vec::new();
let mut compare_data_len = 0;
unsafe {
let status = secure_comparator_proceed_compare(
self.comp_ctx,
peer_compare_data_ptr as *const c_void,
peer_compare_data_len,
ptr::null_mut(),
&mut compare_data_len,
);
let error = Error::from_compare_status(status);
if error.kind() != ErrorKind::BufferTooSmall {
return Err(error);
}
}
compare_data.reserve(compare_data_len);
unsafe {
let status = secure_comparator_proceed_compare(
self.comp_ctx,
peer_compare_data_ptr as *const c_void,
peer_compare_data_len,
compare_data.as_mut_ptr() as *mut c_void,
&mut compare_data_len,
);
let error = Error::from_compare_status(status);
match error.kind() {
ErrorKind::CompareSendOutputToPeer => {}
ErrorKind::Success => {}
_ => {
return Err(error);
}
}
debug_assert!(compare_data_len <= compare_data.capacity());
compare_data.set_len(compare_data_len);
}
Ok(compare_data)
}
pub fn is_complete(&self) -> bool {
!matches!(self.result(), Err(ref e) if e.kind() == ErrorKind::CompareNotReady)
}
pub fn result(&self) -> Result<bool> {
let status = unsafe { secure_comparator_get_result(self.comp_ctx) };
let error = Error::from_match_status(status);
match error.kind() {
ErrorKind::CompareMatch => Ok(true),
ErrorKind::CompareNoMatch => Ok(false),
_ => Err(error),
}
}
}
impl Default for SecureComparator {
fn default() -> Self {
SecureComparator::new()
}
}
#[doc(hidden)]
impl Drop for SecureComparator {
fn drop(&mut self) {
unsafe {
let status = secure_comparator_destroy(self.comp_ctx);
let error = Error::from_themis_status(status);
if (cfg!(debug) || cfg!(test)) && error.kind() != ErrorKind::Success {
panic!("secure_comparator_destroy() failed: {}", error);
}
}
}
}