From 0d99d6664b602d8c477f5cc1270f4de79bfd9f4a Mon Sep 17 00:00:00 2001 From: Avril Date: Mon, 22 Jun 2020 22:00:50 +0100 Subject: [PATCH] works --- Cargo.toml | 4 +- src/error.rs | 12 ++++ src/ext.rs | 26 ++++++++ src/hash/crc32.rs | 3 +- src/hash/crc64.rs | 3 +- src/hash/sha256.rs | 7 ++- src/lib.rs | 99 +++++++++++++++++++++++++----- src/mnemonic.rs | 5 +- src/provider.rs | 6 +- src/salt.rs | 150 +++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 290 insertions(+), 25 deletions(-) create mode 100644 src/ext.rs create mode 100644 src/salt.rs diff --git a/Cargo.toml b/Cargo.toml index 7f02c50..0908d78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,6 @@ crate-type = ["cdylib"] sha2 = "0.9" malloc-array = "1.3.3" libc = "0.2" -crc = "1.8" \ No newline at end of file +crc = "1.8" +hex-literal = "0.2" +getrandom = "0.1" \ No newline at end of file diff --git a/src/error.rs b/src/error.rs index 9ea0ef2..dde2080 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,6 +10,7 @@ pub enum Error IO(io::Error), Format(fmt::Error), Length{expected: usize, got:usize,}, + RNG(getrandom::Error), Unknown, } @@ -20,6 +21,7 @@ impl error::Error for Error match &self { Error::IO(e_io) => Some(e_io), Error::Format(e_fmt) => Some(e_fmt), + Error::RNG(e_rng) => Some(e_rng), _ => None, } } @@ -34,6 +36,7 @@ impl fmt::Display for Error Error::IO(io) => write!(f, "io: {}", io), Error::Format(fmt) => write!(f, "fmt: {}", fmt), Error::Length{expected, got} => write!(f, "invalid length: expected {}, got {}", expected, got), + Error::RNG(rng) => write!(f, "rng error: {}", rng), _ => write!(f, "unknown failure"), } } @@ -47,6 +50,7 @@ impl From for i32 Error::IO(_) => 1, Error::Format(_) => 2, Error::Length{..} => 3, + Error::RNG(_) => 4, _ => -1, } } @@ -66,3 +70,11 @@ impl From for Error Self::Format(i) } } + +impl From for Error +{ + fn from(rng: getrandom::Error) -> Self + { + Self::RNG(rng) + } +} diff --git a/src/ext.rs b/src/ext.rs new file mode 100644 index 0000000..3a96905 --- /dev/null +++ b/src/ext.rs @@ -0,0 +1,26 @@ +use crate::*; + +pub trait HeapArrayExt: Sized +{ + fn into_unsafe(self) -> Self; + fn into_safe(self) -> Self; + fn set_unsafe(self, un: bool) -> Self; +} +impl HeapArrayExt for HeapArray +{ + fn into_unsafe(mut self) -> Self + { + self.drop_check = false; + self + } + fn into_safe(mut self) -> Self + { + self.drop_check = true; + self + } + fn set_unsafe(mut self, un: bool) -> Self + { + self.drop_check = un; + self + } +} diff --git a/src/hash/crc32.rs b/src/hash/crc32.rs index c14a44b..db332d0 100644 --- a/src/hash/crc32.rs +++ b/src/hash/crc32.rs @@ -13,7 +13,7 @@ impl provider::ByteProvider for Crc32Checksum unsafe{reinterpret::bytes(&self.hash)} } - fn compute(input: &mut T, done: &mut usize) -> Result + fn compute(input: &mut T, salt: &salt::Salt, done: &mut usize) -> Result { let mut buffer = [0u8; BUFFER_SIZE]; let mut hasher = crc32::Digest::new(crc32::IEEE); @@ -23,6 +23,7 @@ impl provider::ByteProvider for Crc32Checksum hasher.write(&buffer[..read]); *done += read; } + hasher.write(salt.bytes()); Ok(Self{hash: hasher.sum32()}) } } diff --git a/src/hash/crc64.rs b/src/hash/crc64.rs index 2af4c3f..c23fc9e 100644 --- a/src/hash/crc64.rs +++ b/src/hash/crc64.rs @@ -13,7 +13,7 @@ impl provider::ByteProvider for Crc64Checksum unsafe{reinterpret::bytes(&self.hash)} } - fn compute(input: &mut T, done: &mut usize) -> Result + fn compute(input: &mut T, salt: &salt::Salt, done: &mut usize) -> Result { let mut buffer = [0u8; BUFFER_SIZE]; let mut hasher = crc64::Digest::new(crc64::ECMA); @@ -23,6 +23,7 @@ impl provider::ByteProvider for Crc64Checksum hasher.write(&buffer[..read]); *done += read; } + hasher.write(salt.bytes()); Ok(Self{hash: hasher.sum64()}) } } diff --git a/src/hash/sha256.rs b/src/hash/sha256.rs index 3e259d3..096e138 100644 --- a/src/hash/sha256.rs +++ b/src/hash/sha256.rs @@ -34,13 +34,14 @@ fn compute_stream(input: &mut T, output: &mut D) -> impl Sha256Hash { /// Compute a hash from a stream. - pub fn compute(input: &mut T) -> io::Result<(usize, Self)> + pub fn compute(input: &mut T, salt: &salt::Salt) -> io::Result<(usize, Self)> { let mut hash = [0u8; SHA256_SIZE]; let mut hasher = Sha256::new(); let ok = compute_stream(input, &mut hasher)?; + hasher.update(salt.bytes()); assert_eq!(array::copy_slice(&mut hash, hasher.finalize()), SHA256_SIZE); Ok((ok, Self{hash})) @@ -74,9 +75,9 @@ impl provider::ByteProvider for hash::Sha256Hash &self.bytes()[..] } - fn compute(input: &mut T, done: &mut usize) -> Result + fn compute(input: &mut T, salt: &salt::Salt, done: &mut usize) -> Result { - let (ok, this) = Self::compute(input)?; + let (ok, this) = Self::compute(input, salt)?; *done = ok; Ok(this) } diff --git a/src/lib.rs b/src/lib.rs index 6034abc..ca1b642 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +//#![feature(const_generics)] #![allow(dead_code)] use std::{ io::{ @@ -6,7 +7,7 @@ use std::{ fmt::Write, }; -type HASHER =hash::Crc64Checksum; +type HASHER = hash::Crc64Checksum; #[cfg(test)] mod tests { @@ -14,10 +15,36 @@ mod tests { #[test] fn it_works() -> Result<(), error::Error> { - let input = b"hello world!!"; - let kana = generate(input)?; + let input = b"lolis are super ultra mega cute"; + let kana = generate(input, salt::Salt::default())?; println!("kana: {}", kana); - panic!("uhh") + assert_eq!(kana, "ワイトひはっトと"); + Ok(()) + } + #[test] + fn ffi() -> Result<(), Box> + { + unsafe { + unsafe fn work_with_salt(salt: salt::Salt) -> Result { + let input = b"lolis are super ultra mega cute"; + let salt = salt::into_raw(salt); + + // Simulate ffi call; + let mut sz: libc::size_t = 0; + assert_eq!(GENERIC_SUCCESS, _kana_length(&input[0] as *const u8 as *const libc::c_void, input.len(), salt as *const libc::c_void, &mut sz as *mut size_t)); + assert_eq!(sz, 24); + + let mut output = malloc_array::heap![unsafe u8; sz]; + assert_eq!(GENERIC_SUCCESS, _kana_do(&input[0] as *const u8 as *const libc::c_void, input.len(), salt as *mut libc::c_void, output.as_ptr_mut() as *mut libc::c_char, sz)); + + let string = std::str::from_utf8(&output[..]).unwrap(); + Ok(string.to_owned()) + } + + assert_eq!("けほほぇほょすゆ", work_with_salt(salt::Salt::None)?); + assert_eq!("ワイトひはっトと", work_with_salt(salt::Salt::default())?); + } + Ok(()) } } @@ -25,11 +52,14 @@ pub const BUFFER_SIZE: usize = 4096; mod array; mod reinterpret; -mod group; +mod ext; +use ext::*; +mod group; //unused mod sixteen; use sixteen::Bit16IterExt; mod def; mod map; +mod salt; mod hash; mod provider; mod mnemonic; @@ -39,9 +69,9 @@ mod error; mod ffi; use ffi::*; -fn compute(mut from: T) -> Result<(usize, String), error::Error> +fn compute(mut from: T, salt: salt::Salt) -> Result<(usize, String), error::Error> { - let (read, hash) = provider::compute::<_, Digest>(&mut from)?; + let (read, hash) = provider::compute::<_, Digest>(&mut from, salt)?; println!("hash ({}): {}", read, hash); let mut output = String::with_capacity(128); @@ -55,11 +85,11 @@ fn compute(mut from: T) -> Result<(usiz Ok((read,output)) } -pub fn generate>(bytes: T) -> Result +pub fn generate>(bytes: T, salt: salt::Salt) -> Result { let bytes = bytes.as_ref(); let mut nbytes = bytes; - let (ok, string) = compute::<_, HASHER>(&mut nbytes)?; + let (ok, string) = compute::<_, HASHER>(&mut nbytes,salt)?; if ok == bytes.len() { Ok(string) } else { @@ -77,28 +107,69 @@ use malloc_array::{ HeapArray, }; +// FFI section + +/// Calculate the length in bytes of a kana hash output. +/// +/// # Note +/// Does not consume `salt` #[no_mangle] -pub unsafe extern "C" fn _kana_length(bin: *const c_void, sz: size_t, out_len: *mut size_t) -> i32 +pub unsafe extern "C" fn _kana_length(bin: *const c_void, sz: size_t, salt: *const c_void, out_len: *mut size_t) -> i32 { no_unwind!{ try error::Error::Unknown; let bin = HeapArray::::from_raw_copied(bin as *const u8, usize::from(sz)); - let string = c_try!(generate(&bin)); - *out_len = (string.bytes().len()+1).into(); + let string = c_try!(generate(&bin, salt::clone_from_raw(salt as *const salt::FFI))); + *out_len = string.bytes().len().into(); GENERIC_SUCCESS } } + +/// Compute and write a kana hash output to a string. +/// +/// # Note +/// Consumes `salt` #[no_mangle] -pub unsafe extern "C" fn _kana_do(bin: *const c_void, sz: size_t, out_str: *mut c_char, str_len: size_t) -> i32 +pub unsafe extern "C" fn _kana_do(bin: *const c_void, sz: size_t, salt: *mut c_void, out_str: *mut c_char, str_len: size_t) -> i32 { no_unwind!{ try error::Error::Unknown; let bin = HeapArray::::from_raw_copied(bin as *const u8, usize::from(sz)); - let string: Vec = c_try!(generate(&bin)).bytes().collect(); + let string: Vec = c_try!(generate(&bin, salt::from_raw(salt as *mut salt::FFI))).bytes().collect(); libc::memcpy(out_str as *mut c_void, &string[0] as *const u8 as *const c_void, std::cmp::min(str_len, string.len())); GENERIC_SUCCESS } } + +/// Free a salt allocated with `_kana_new_salt` +#[no_mangle] +pub unsafe extern "C" fn _kana_free_salt(salt: *mut c_void) -> i32 +{ + no_unwind!{ + drop(salt::from_raw(salt as *mut salt::FFI)); + GENERIC_SUCCESS + } +} + +/// Create a new salt +#[no_mangle] +pub unsafe extern "C" fn _kana_new_salt(bin: *const c_void, sz: size_t, nptr: *mut *const c_void) -> i32 +{ + no_unwind!{ + try error::Error::Unknown; + let nptr = nptr as *mut *const salt::FFI; + if bin.is_null() { + *nptr = salt::into_raw(salt::Salt::default()); + } else if sz == 0 { + *nptr = salt::into_raw(salt::Salt::None); + } else { + let bin = HeapArray::::from_raw_copied(bin as *const u8, usize::from(sz)); + *nptr = salt::into_raw(salt::Salt::unfixed(&bin[..])); + } + + GENERIC_SUCCESS + } +} diff --git a/src/mnemonic.rs b/src/mnemonic.rs index 613e37c..a13b7cd 100644 --- a/src/mnemonic.rs +++ b/src/mnemonic.rs @@ -21,12 +21,13 @@ impl Digest { d.0 = Some(map::KANA[master]); if from[1] > 0 { if let Some(slaves) = map::sub(master) { - if slaves.len() > 0 { + let one = (usize::from(from[1]) / map::KANA.len()) % 2; + if slaves.len() > 0 && one > 0{ d.1 = Some(slaves[usize::from(from[1]) % slaves.len()]); return d; } } - let from = [from[1]]; + let from = [from[1], 0]; d.1 = Self::new(&from[..]).0; } d diff --git a/src/provider.rs b/src/provider.rs index 9f37eb4..056bec3 100644 --- a/src/provider.rs +++ b/src/provider.rs @@ -2,14 +2,14 @@ use crate::*; pub trait ByteProvider: Sized + std::fmt::Display { - fn compute(input: &mut T, provided: &mut usize) -> Result; + fn compute(input: &mut T, salt: &salt::Salt, provided: &mut usize) -> Result; fn bytes(&self) -> &[u8]; } -pub fn compute(input: &mut T) -> Result<(usize, P), error::Error> +pub fn compute(input: &mut T, salt: salt::Salt) -> Result<(usize, P), error::Error> { let mut output = 0usize; - let this = P::compute(input, &mut output)?; + let this = P::compute(input, &salt, &mut output)?; Ok((output, this)) } diff --git a/src/salt.rs b/src/salt.rs new file mode 100644 index 0000000..a9f4781 --- /dev/null +++ b/src/salt.rs @@ -0,0 +1,150 @@ +use crate::*; +use malloc_array::*; +use getrandom::{ + getrandom, + Error, +}; +use hex_literal::hex; + +use std::{ + io::{ + self, + Write, + }, +}; + +pub const SIZE: usize = 32; + +const STATIC_SALT: &[u8; SIZE] = &hex!("6787f049791466d5a31a3aa6f7138d8fbb907fd1785758298b5c97b0f3fb31ff"); + +#[derive(Clone,PartialEq,Eq,Hash,Debug)] +pub enum Salt +{ + None, + Static(&'static [u8; SIZE]), + Fixed([u8; SIZE]), + Dynamic(Box<[u8]>), +} + +impl Default for Salt +{ + fn default() -> Self + { + Self::Static(STATIC_SALT) + } +} + +impl Salt +{ + pub fn fixed(array: [u8; SIZE]) -> Self + { + Self::Fixed(array) + } + pub fn unfixed(slice: &T) -> Self + where T: AsRef<[u8]> + ?Sized + { + let slice = slice.as_ref(); + assert!(slice.len() > 0, "Salt expects at least one byte."); + Self::Dynamic(Vec::from(slice).into_boxed_slice()) + } + pub fn none() -> Self + { + Self::None + } + pub fn random() -> Result + { + let mut buffer = [0u8; SIZE]; + getrandom(&mut buffer[..])?; + Ok(Self::Fixed(buffer)) + } + pub const fn internal() -> Self + { + Self::Static(STATIC_SALT) + } + + pub fn bytes(&self) -> &[u8] + { + match &self { + Self::Fixed(ar) => &ar[..], + Self::Dynamic(vec) => &vec[..], + Self::Static(s) => &s[..], + _ => &[], + } + } + + /// Append salt bytes to a stream. + pub fn append(&self, to: &mut W) -> io::Result + { + to.write(self.bytes()) + } +} + +#[derive(Copy,Clone,Debug)] +#[repr(C)] +#[repr(packed)] +pub struct FFI +{ + size: usize, + body: *mut u8, +} + +/// 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 +{ + if ptr.is_null() { + Salt::default() + } else { + let ptr = &*ptr; + if ptr.size == 0 || ptr.body.is_null() { + return Salt::None; + } + let size = std::cmp::min(ptr.size, MAX_FFI_SALT_SIZE); + Salt::Dynamic(HeapArray::from_raw_copied(ptr.body, size).into_unsafe().into_boxed_slice()) + } +} +/// Consume an `FFI` salt and return a `Salt`. +pub unsafe fn from_raw(ptr: *mut FFI) -> Salt +{ + if ptr.is_null() { + Salt::default() + } else { + let ptr = { + let mut ptr = HeapArray::from_raw_parts(ptr, 1); + let rval = ptr[0].clone(); + ptr.set_memory(0); + rval + }; + if ptr.size == 0 || ptr.body.is_null() { + return Salt::None; + } + let body = HeapArray::from_raw_parts(ptr.body, ptr.size); + Salt::Dynamic(body.into_boxed_slice()) + } +} + +/// Consume a `Salt` and output a newly allocated `FFI` salt. +pub unsafe fn into_raw(salt: Salt) -> *mut FFI +{ + unsafe fn genffi(bytes: &[u8]) -> *mut FFI + { + if bytes.len() == 0 { + let (ffi, _) = heap![FFI{size:0,body:0 as *mut u8}].into_raw_parts(); + ffi + } else { + let mut array = heap![unsafe u8; bytes.len()]; + array.memory_from_raw(&bytes[0] as *const u8, bytes.len()); + let (body, size) = array.into_raw_parts(); + let (ffi, _) = heap![FFI{size,body}].into_raw_parts(); + ffi + } + } + match salt { + Salt::Static(STATIC_SALT) => 0 as *mut FFI, + Salt::Static(&other) | Salt::Fixed(other) => genffi(&other[..]), + Salt::Dynamic(other) => genffi(&other[..]), + _ => genffi(salt.bytes()), + } +} +