From e113c90c53225cb81b03e3a2f2c89c3c2a91eb8c Mon Sep 17 00:00:00 2001 From: Avril Date: Thu, 25 Jun 2020 19:03:23 +0100 Subject: [PATCH] adding rust interface --- src/ctx.rs | 27 +++++++++++++++++---------- src/error.rs | 6 ++++++ src/lib.rs | 37 ++++++++++++++++++++++++++----------- src/salt.rs | 27 ++++++++++++++++++--------- src/stream.rs | 35 +++++++++++++++++++++++++++++++++++ 5 files changed, 102 insertions(+), 30 deletions(-) create mode 100644 src/stream.rs diff --git a/src/ctx.rs b/src/ctx.rs index f673523..4b59224 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -5,6 +5,7 @@ use std::{ }, }; +/// An algorithm to use for the context. #[derive(Clone,Debug,PartialEq,Eq,Hash)] pub enum Algorithm { @@ -22,6 +23,7 @@ impl Default for Algorithm } } +/// A kana-hash context containing it's salt and algorithm. #[derive(Clone,Debug,PartialEq,Eq,Hash)] pub struct Context { @@ -31,6 +33,7 @@ pub struct Context impl Context { + /// Create a new kana-hash context with an algorithm and a salt pub fn new(algo: Algorithm, salt: impl Into) -> Self { Self { @@ -38,16 +41,20 @@ impl Context salt: salt.into(), } } + + /// The algorithm used pub fn get_algorithm(&self) -> &Algorithm { &self.algo } + /// The salt used pub fn get_salt(&self) -> &salt::Salt { &self.salt } - pub fn compute(&self, mut from: R) -> Result<(usize, Box<[u8]>), error::Error> + + pub(crate) fn compute(&self, mut from: R) -> Result<(usize, Box<[u8]>), error::Error> { fn provide(input: &mut R, salt: &salt::Salt, output: &mut usize) -> Result, error::Error> where P: provider::ByteProvider, @@ -69,7 +76,7 @@ impl Context Ok((output, bytes)) } - pub unsafe fn into_raw(self) -> CContext + pub(crate) unsafe fn into_raw(self) -> CContext { CContext{ algo: u8::from(self.algo), @@ -78,7 +85,7 @@ impl Context } } - pub unsafe fn clone_from_raw(from: *const CContext) -> Self + pub(crate) unsafe fn clone_from_raw(from: *const CContext) -> Self { let from = &*from; Self { @@ -87,7 +94,7 @@ impl Context } } - pub unsafe fn from_raw(from: *mut CContext) -> Self + pub(crate) unsafe fn from_raw(from: *mut CContext) -> Self { let from = &mut *from; let output = Self{ @@ -110,16 +117,16 @@ impl Default for Context } } -pub const ALGO_DEFAULT: u8 = 0; -pub const ALGO_CRC32: u8 = 1; -pub const ALGO_CRC64: u8 = 2; -pub const ALGO_SHA256: u8 = 3; -pub const ALGO_SHA256_TRUNCATED: u8 = 4; +pub(crate) const ALGO_DEFAULT: u8 = 0; +pub(crate) const ALGO_CRC32: u8 = 1; +pub(crate) const ALGO_CRC64: u8 = 2; +pub(crate) const ALGO_SHA256: u8 = 3; +pub(crate) const ALGO_SHA256_TRUNCATED: u8 = 4; /// FFI context #[derive(Debug)] #[repr(C)] -pub struct CContext +pub(crate) struct CContext { algo: u8, flags: u64, //nothing yet, might be flags later idk diff --git a/src/error.rs b/src/error.rs index dde2080..0a80d31 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,13 +4,19 @@ use std::{ error, }; +/// An error value used by all kana-hash functions. #[derive(Debug)] pub enum Error { + /// There was an IO error reading or writing a buffer. IO(io::Error), + /// There was a text formatting error writing the context. Format(fmt::Error), + /// There was a length mismatch. Length{expected: usize, got:usize,}, + /// The random number generator failed. RNG(getrandom::Error), + /// There was an unknown error. Unknown, } diff --git a/src/lib.rs b/src/lib.rs index 1f3e55a..c2b58ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,12 +242,14 @@ mod sixteen; use sixteen::Bit16IterExt; mod def; mod map; -mod salt; +pub mod salt; mod hash; mod provider; mod mnemonic; -mod error; -mod ctx; +pub mod error; +pub mod ctx; +mod stream; +pub use stream::Digest; #[macro_use] mod ffi; @@ -269,6 +271,7 @@ fn compute(context: &ctx::Context, mut from: T) -> Result<(usize, Strin Ok((read,output)) } +/// Generate kana hash from a slice. pub fn generate>(context: &ctx::Context, bytes: T) -> Result { let bytes = bytes.as_ref(); @@ -291,6 +294,8 @@ use malloc_array::{ HeapArray, }; + + // FFI section /// Calculate the length in bytes of a kana hash output. @@ -298,8 +303,9 @@ use malloc_array::{ /// # Note /// Does not consume `salt` #[no_mangle] -pub unsafe extern "C" fn khash_length(context: *const ctx::CContext, bin: *const c_void, sz: size_t, out_len: *mut size_t) -> i32 +pub unsafe extern "C" fn khash_length(context: *const c_void, bin: *const c_void, sz: size_t, out_len: *mut size_t) -> i32 { + let context = context as *const ctx::CContext; no_unwind!{ try error::Error::Unknown; let context = ctx::Context::clone_from_raw(context); @@ -316,8 +322,9 @@ pub unsafe extern "C" fn khash_length(context: *const ctx::CContext, bin: *const /// # Note /// Consumes `salt` #[no_mangle] -pub unsafe extern "C" fn khash_do(context: *mut ctx::CContext, bin: *const c_void, sz: size_t, out_str: *mut c_char, str_len: size_t) -> i32 +pub unsafe extern "C" fn khash_do(context: *mut c_void, bin: *const c_void, sz: size_t, out_str: *mut c_char, str_len: size_t) -> i32 { + let context = context as *mut ctx::CContext; no_unwind!{ try error::Error::Unknown; @@ -333,8 +340,9 @@ pub unsafe extern "C" fn khash_do(context: *mut ctx::CContext, bin: *const c_voi /// Free a context #[no_mangle] -pub unsafe extern "C" fn khash_free_context(context: *mut ctx::CContext) -> i32 +pub unsafe extern "C" fn khash_free_context(context: *mut c_void) -> i32 { + let context = context as *mut ctx::CContext; no_unwind!{ drop(ctx::Context::from_raw(context)); GENERIC_SUCCESS @@ -343,8 +351,9 @@ pub unsafe extern "C" fn khash_free_context(context: *mut ctx::CContext) -> i32 /// Create a new context #[no_mangle] -pub unsafe extern "C" fn khash_new_context(algo: u8, salt_type: u8, bin: *const c_void, sz: size_t, nptr: *mut ctx::CContext) -> i32 +pub unsafe extern "C" fn khash_new_context(algo: u8, salt_type: u8, bin: *const c_void, sz: size_t, nptr: *mut c_void) -> i32 { + let nptr = nptr as *mut ctx::CContext; no_unwind!{ try error::Error::Unknown; let salt = match salt_type { @@ -374,8 +383,10 @@ pub unsafe extern "C" fn khash_new_context(algo: u8, salt_type: u8, bin: *const /// Clone a context #[no_mangle] -pub unsafe extern "C" fn khash_clone_context(raw: *const ctx::CContext, out: *mut ctx::CContext) -> i32 +pub unsafe extern "C" fn khash_clone_context(raw: *const c_void, out: *mut c_void) -> i32 { + let raw = raw as *const ctx::CContext; + let out = out as *mut ctx::CContext; no_unwind!{ *out = ctx::Context::clone_from_raw(raw).into_raw(); GENERIC_SUCCESS @@ -384,8 +395,9 @@ pub unsafe extern "C" fn khash_clone_context(raw: *const ctx::CContext, out: *mu /// Free a salt allocated with `khash_new_salt` #[no_mangle] -pub unsafe extern "C" fn khash_free_salt(salt: *mut salt::FFI) -> i32 +pub unsafe extern "C" fn khash_free_salt(salt: *mut c_void) -> i32 { + let salt = salt as *mut salt::FFI; no_unwind!{ drop(salt::from_raw(salt)); GENERIC_SUCCESS @@ -394,8 +406,9 @@ pub unsafe extern "C" fn khash_free_salt(salt: *mut salt::FFI) -> i32 /// Create a new salt #[no_mangle] -pub unsafe extern "C" fn khash_new_salt(salt_type: u8, bin: *const c_void, sz: size_t, nptr: *mut salt::FFI) -> i32 +pub unsafe extern "C" fn khash_new_salt(salt_type: u8, bin: *const c_void, sz: size_t, nptr: *mut c_void) -> i32 { + let nptr = nptr as *mut salt::FFI; no_unwind!{ try error::Error::Unknown; match salt_type { @@ -422,8 +435,10 @@ pub unsafe extern "C" fn khash_new_salt(salt_type: u8, bin: *const c_void, sz: s /// Clone a salt #[no_mangle] -pub unsafe extern "C" fn khash_clone_salt(salt: *const salt::FFI, out: *mut salt::FFI) -> i32 +pub unsafe extern "C" fn khash_clone_salt(salt: *const c_void, out: *mut c_void) -> i32 { + let salt = salt as *const salt::FFI; + let out = out as *mut salt::FFI; no_unwind!{ *out = salt::into_raw(salt::clone_from_raw(salt)); GENERIC_SUCCESS diff --git a/src/salt.rs b/src/salt.rs index 457b4dd..3505329 100644 --- a/src/salt.rs +++ b/src/salt.rs @@ -13,10 +13,13 @@ use std::{ convert::{TryInto,TryFrom}, }; +/// The static salt size pub const SIZE: usize = 32; +/// The default static salt const STATIC_SALT: &[u8; SIZE] = &hex!("6787f049791466d5a31a3aa6f7138d8fbb907fd1785758298b5c97b0f3fb31ff"); +/// A salt to use for the kana-hash algorithm #[derive(Clone,PartialEq,Eq,Hash,Debug)] pub enum Salt { @@ -36,10 +39,12 @@ impl Default for Salt impl Salt { + /// A fixed size salt of [SIZE] pub fn fixed(array: [u8; SIZE]) -> Self { Self::Fixed(array) } + /// A salt from a slice pub fn unfixed(slice: &T) -> Self where T: AsRef<[u8]> + ?Sized { @@ -47,21 +52,25 @@ impl Salt assert!(slice.len() > 0, "Salt expects at least one byte."); Self::Dynamic(Vec::from(slice).into_boxed_slice()) } - pub fn none() -> Self + /// No salt + pub const fn none() -> Self { Self::None } + /// Try to create a random salt pub fn random() -> Result { let mut buffer = [0u8; SIZE]; getrandom(&mut buffer[..])?; Ok(Self::Fixed(buffer)) } + /// The default internal salt pub const fn internal() -> Self { Self::Static(STATIC_SALT) } + /// Get the raw bytes of this salt pub fn bytes(&self) -> &[u8] { match &self { @@ -81,22 +90,22 @@ impl Salt #[derive(Copy,Clone,Debug)] #[repr(C)] -pub struct FFI +pub(crate) struct FFI { salt_type: u8, size: u32, body: *mut u8, } -pub const SALT_TYPE_NONE: u8 = 0; -pub const SALT_TYPE_DEFAULT: u8 = 1; -pub const SALT_TYPE_SPECIFIC: u8 = 2; -pub const SALT_TYPE_RANDOM: u8 = 3; +pub(crate) const SALT_TYPE_NONE: u8 = 0; +pub(crate) const SALT_TYPE_DEFAULT: u8 = 1; +pub(crate) const SALT_TYPE_SPECIFIC: u8 = 2; +pub(crate) const SALT_TYPE_RANDOM: u8 = 3; /// We won't try to copy more than this much data. const MAX_FFI_SALT_SIZE: usize = 1024; /// Clone a new `Salt` from an `FFI` salt. -pub unsafe fn clone_from_raw(ptr: *const FFI) -> Salt +pub(crate) unsafe fn clone_from_raw(ptr: *const FFI) -> Salt { let ffi = &*ptr; match ffi.salt_type { @@ -110,7 +119,7 @@ pub unsafe fn clone_from_raw(ptr: *const FFI) -> Salt } } /// Consume an `FFI` salt and return a `Salt`. -pub unsafe fn from_raw(ptr: *mut FFI) -> Salt +pub(crate) unsafe fn from_raw(ptr: *mut FFI) -> Salt { let ffi = &mut *ptr; let out = match ffi.salt_type { @@ -129,7 +138,7 @@ pub unsafe fn from_raw(ptr: *mut FFI) -> Salt } /// Consume a `Salt` and output a new `FFI` salt. -pub unsafe fn into_raw(salt: Salt) -> FFI +pub(crate) unsafe fn into_raw(salt: Salt) -> FFI { unsafe fn allocate(slice: impl AsRef<[u8]>) -> FFI { diff --git a/src/stream.rs b/src/stream.rs new file mode 100644 index 0000000..5b2d2d0 --- /dev/null +++ b/src/stream.rs @@ -0,0 +1,35 @@ +use crate::*; + +/// A streaming kana hash digest +pub struct Digest<'a, T> +where T: Read +{ + input: &'a mut T, +} + +impl<'a, T: Read> Digest<'a, T> +{ + /// Create a new stream digest from the input + pub fn new(input: &'a mut T) -> Self + { + Self{input} + } +} + +impl<'a, T: Read> Iterator for Digest<'a, T> +{ + type Item = String; + fn next(&mut self) -> Option + { + let mut buffer = [0u8; 2]; + let mut rd =0; + while rd < 2 { + match self.input.read(&mut buffer[rd..]) { + Ok(2) => break, + Err(_) | Ok(0) => return None, + Ok(v) => rd+=v, + } + } + Some(format!("{}",mnemonic::Digest::new(&buffer[..]))) + } +}