From 2725851a6b6f2e9589b2491a56071a2eff426853 Mon Sep 17 00:00:00 2001 From: Avril Date: Tue, 23 Jun 2020 18:01:55 +0100 Subject: [PATCH] rework with context --- cli/src/main.c | 83 +++++++++++++++++++++---------- include/khash.h | 22 +++++++-- src/ctx.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++--- src/lib.rs | 80 +++++++++++++++++++++++++----- 4 files changed, 269 insertions(+), 45 deletions(-) diff --git a/cli/src/main.c b/cli/src/main.c index 9659908..515c0dd 100644 --- a/cli/src/main.c +++ b/cli/src/main.c @@ -10,18 +10,19 @@ int main(void) { setlocale(LC_ALL, ""); + const char* string = "hello world!"; printf("input: %s\n", string); - khash_salt salt; - assert(khash_new_salt(KHASH_SALT_TYPE_RANDOM, NULL, 0, &salt) == KHASH_SUCCESS); - printf("salt: %d\n", (int)salt.size); + khash_ctx ctx; + assert(khash_new_context(KHASH_ALGO_SHA256, KHASH_SALT_TYPE_NONE, NULL, 0, &ctx) == KHASH_SUCCESS); + printf("salt: %d\n", (int)ctx.salt.size); size_t length; - assert(khash_length(string, strlen(string), &salt, &length) == KHASH_SUCCESS); + assert(khash_length(&ctx, string, strlen(string), &length) == KHASH_SUCCESS); printf("length: %d\n", (int)length); char* output = alloca(length+1); - assert(khash_do(string, strlen(string), &salt, output,length) == KHASH_SUCCESS); - + assert(khash_do(&ctx, string, strlen(string), output,length) == KHASH_SUCCESS); + output[length] = 0; printf("output: %s\n", output); return 0; } @@ -29,27 +30,27 @@ int main(void) #define KTRY(expr, msg) (assert(((expr) && (msg))== KHASH_SUCCESS)) -void k_do(const char* input, const khash_salt* salt) +void k_do(const khash_ctx* ctx, const char* input) { - khash_salt clone; - KTRY(khash_clone_salt(salt, &clone), "khash: saltclone failed"); + khash_ctx clone; + KTRY(khash_clone_context(ctx, &clone), "khash: ctxclone failed"); size_t length; - KTRY(khash_length(input, strlen(input), &clone, &length), "khash: hashlength failed"); + KTRY(khash_length(&clone, input, strlen(input), &length), "khash: hashlength failed"); char* output =alloca(length+1); - KTRY(khash_do(input,strlen(input), &clone, output, length), "khash: hashstring failed"); + KTRY(khash_do(&clone, input,strlen(input), output, length), "khash: hashstring failed"); output[length] = 0; //ensure no overflow. printf("%s\n", output); } -void reseed_salt(khash_salt* salt, uint8_t type, const void* in_ptr, size_t ptr_sz) +void reseed_ctx(khash_ctx* ctx, uint8_t algo, uint8_t type, const void* in_ptr, size_t ptr_sz) { - KTRY(khash_free_salt(salt), "khash: saltrefree failed"); - KTRY(khash_new_salt(type, in_ptr, ptr_sz, salt), "khash: saltreseed failed"); + KTRY(khash_free_context(ctx), "khash: ctxrefree failed"); + KTRY(khash_new_context(algo, type, in_ptr, ptr_sz, ctx), "khash: ctxreseed failed"); } -static int _main(int argc, char** argv, khash_salt salt) +static int _main(int argc, char** argv, khash_ctx ctx) { int look = 1; if (argc <= 1) @@ -64,16 +65,43 @@ static int _main(int argc, char** argv, khash_salt salt) if (strcmp(*argv, "--help") == 0) { printf("kana-hash cli\n"); - printf("Usage: khash [--salt SALT-TYPE []] [--] \n"); + printf("Usage: khash [--algo ALGO] [--salt SALT-TYPE []] [--] \n"); + printf(" --algo: Specify the algorithm. (default crc64)\n"); + printf(" ALGO: 3: crc32.\n"); + printf(" ALGO: 6: crc64.\n"); + printf(" ALGO: s: sha256.\n"); printf(" --salt: Specify the salt.\n"); printf(" SALT_TYPE: D: default embedded.\n"); printf(" : N: no salt.\n"); + printf(" : R: random salt.\n"); printf(" : S : specific salt.\n"); printf(" --: Stop reading args here.\n"); return 1; } else if (strcmp(*argv, "--") == 0) look = 0; + else if (strcmp(*argv, "--algo")==0) + { + if (argv[1]) + { + switch(argv[1][0]) + { + case '3': + ctx.algo = KHASH_ALGO_CRC32; + break; + case '6': + ctx.algo = KHASH_ALGO_CRC64; + break; + case 's': + ctx.algo = KHASH_ALGO_SHA256; + break; + default: + fprintf(stderr, "ALGO: unknow algorithm key `%c'\n", *argv[1]); + return 1; + } + } + argv++; + } else if (strcmp(*argv, "--salt")==0) { if (argv[1]) @@ -82,22 +110,26 @@ static int _main(int argc, char** argv, khash_salt salt) { case 'd': case 'D': - reseed_salt(&salt, KHASH_SALT_TYPE_DEFAULT, NULL, 0); + reseed_ctx(&ctx, ctx.algo, KHASH_SALT_TYPE_DEFAULT, NULL, 0); break; case 'N': case 'n': - reseed_salt(&salt, KHASH_SALT_TYPE_NONE, NULL, 0); + reseed_ctx(&ctx, ctx.algo, KHASH_SALT_TYPE_NONE, NULL, 0); break; case 'S': case 's': if(argv[2]) - reseed_salt(&salt, KHASH_SALT_TYPE_SPECIFIC, argv[2], strlen(argv[2])); + reseed_ctx(&ctx, ctx.algo, KHASH_SALT_TYPE_SPECIFIC, argv[2], strlen(argv[2])); else { fprintf(stderr, "SALT_TYPE `%c' expects a value.\n", *argv[1]); return 1; } argv++; break; + case 'R': + case 'r': + reseed_ctx(&ctx, ctx.algo, KHASH_SALT_TYPE_RANDOM, NULL, 0); + break; default: fprintf(stderr, "Unknown SALT_TYPE `%c'\n", *argv[1]); return 1; @@ -111,7 +143,7 @@ static int _main(int argc, char** argv, khash_salt salt) } else { work: - k_do(*argv, &salt); + k_do(&ctx, *argv); } } @@ -120,13 +152,14 @@ static int _main(int argc, char** argv, khash_salt salt) int main(int argc, char** argv) { - - khash_salt salt; - KTRY(khash_new_salt(KHASH_SALT_TYPE_DEFAULT, NULL, 0, &salt), "khash: saltgen failed"); + setlocale(LC_ALL, ""); + + khash_ctx context; + KTRY(khash_new_context(KHASH_ALGO_DEFAULT, KHASH_SALT_TYPE_DEFAULT, NULL, 0, &context), "khash: ctxgen failed"); - int res = _main(argc, argv, salt); + int res = _main(argc, argv, context); - KTRY(khash_free_salt(&salt), "khash: saltfree failed"); + KTRY(khash_free_context(&context), "khash: ctxfree failed"); return res; } diff --git a/include/khash.h b/include/khash.h index 06ea57c..fe41946 100644 --- a/include/khash.h +++ b/include/khash.h @@ -7,6 +7,11 @@ extern "C" { #include +#define KHASH_ALGO_DEFAULT ((uint8_t)0) +#define KHASH_ALGO_CRC32 ((uint8_t)1) +#define KHASH_ALGO_CRC64 ((uint8_t)2) +#define KHASH_ALGO_SHA256 ((uint8_t)3) + /// No salt #define KHASH_SALT_TYPE_NONE ((uint8_t)0) /// The default static salt @@ -16,13 +21,19 @@ extern "C" { /// A randomly generated salt. #define KHASH_SALT_TYPE_RANDOM ((uint8_t)3) - /// A valid salt for khash functions. Initialised with `khash_new_salt`. + /// A valid salt for khash functions. Instantiated with `khash_new_salt`. typedef struct { uint8_t salt_type; uint32_t size; uint8_t* body; } khash_salt; + /// A valid context for khash functinos. Instantiated with `khash_new_context`. + typedef struct { + uint8_t algo; + khash_salt salt; + } khash_ctx; + /// Returned by all functions that succeed. #define KHASH_SUCCESS ((int32_t)0) @@ -44,10 +55,15 @@ extern "C" { extern int32_t khash_free_salt(khash_salt* salt); /// Clone a salt allocated with `khash_new_salt`. extern int32_t khash_clone_salt(const khash_salt* src, khash_salt* dst); + + extern int32_t khash_new_context(uint8_t algo, uint8_t salt_type, const void* data, size_t size, khash_ctx* output); + extern int32_t khash_free_context(khash_ctx* ctx); + extern int32_t khash_clone_context(const khash_ctx* src, khash_ctx* dst); + /// Compute the length of hash required for the specified input. - extern int32_t khash_length(const void* data, size_t size, const khash_salt* salt, size_t* length); + extern int32_t khash_length(const khash_ctx* context, const void* data, size_t size, size_t* length); /// Compute the hash and store it in `string`. Will write no more than `strlen` bytes into `string`. - extern int32_t khash_do(const void* data, size_t size, khash_salt* salt, char* string, size_t strlen); + extern int32_t khash_do(khash_ctx* context, const void* data, size_t size, char* string, size_t strlen); #ifdef __cplusplus } diff --git a/src/ctx.rs b/src/ctx.rs index 05d30f1..8ae8ebb 100644 --- a/src/ctx.rs +++ b/src/ctx.rs @@ -1,10 +1,11 @@ use crate::*; +use std::{ + io::{ + Read, + }, +}; -pub const ALGO_CRC32: u8 = 0; -pub const ALGO_CRC64: u8 = 1; -pub const ALGO_SHA256: u8 = 2; - -#[derive(Debug,PartialEq,Eq,Hash)] +#[derive(Clone,Debug,PartialEq,Eq,Hash)] pub enum Algorithm { Crc32, @@ -12,19 +13,135 @@ pub enum Algorithm Sha256, } +impl Default for Algorithm +{ + fn default() -> Self + { + Self::Crc64 + } +} + +#[derive(Clone,Debug,PartialEq,Eq,Hash)] pub struct Context { algo: Algorithm, salt: salt::Salt, +} + +impl Context +{ + pub fn new(algo: Algorithm, salt: impl Into) -> Self + { + Self { + algo, + salt: salt.into(), + } + } + pub fn get_algorithm(&self) -> &Algorithm + { + &self.algo + } + pub fn get_salt(&self) -> &salt::Salt + { + &self.salt + } + + pub 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, + R: Read + ?Sized + { + let this = P::compute(input, &salt, output)?; + Ok(Vec::from(this.bytes())) + } + + let mut output = 0usize; + let bytes = match self.algo + { + Algorithm::Crc32 => provide::(&mut from, &self.salt, &mut output)?, + Algorithm::Crc64 => provide::(&mut from, &self.salt, &mut output)?, + Algorithm::Sha256 => provide::(&mut from, &self.salt, &mut output)?, + }.into_boxed_slice(); + + Ok((output, bytes)) + } + + pub unsafe fn into_raw(self) -> CContext + { + CContext{ + algo: u8::from(self.algo), + salt: salt::into_raw(self.salt), + } + } + pub unsafe fn clone_from_raw(from: *const CContext) -> Self + { + let from = &*from; + Self { + algo: from.algo.into(), + salt: salt::clone_from_raw(&from.salt as *const salt::FFI), + } + } + + pub unsafe fn from_raw(from: *mut CContext) -> Self + { + let from = &mut *from; + let output = Self{ + algo: from.algo.into(), + salt: salt::from_raw(&mut from.salt as *mut salt::FFI), + }; + from.algo = 0; + output + } } +impl Default for Context +{ + fn default() -> Self + { + Self { + algo: Default::default(), + salt: Default::default(), + } + } +} + +pub const ALGO_DEFAULT: u8 = 0; +pub const ALGO_CRC32: u8 = 1; +pub const ALGO_CRC64: u8 = 2; +pub const ALGO_SHA256: u8 = 3; + /// FFI context #[derive(Debug)] #[repr(C)] pub struct CContext { algo: u8, - salt: *mut salt::FFI, + salt: salt::FFI, } + +impl From for u8 +{ + fn from(al: Algorithm) -> Self + { + match al { + Algorithm::Crc32 => ALGO_CRC32, + Algorithm::Crc64 => ALGO_CRC64, + Algorithm::Sha256 => ALGO_SHA256, + } + } +} +impl From for Algorithm +{ + fn from(al: u8) -> Self + { + match al { + ALGO_CRC32 => Algorithm::Crc32, + ALGO_CRC64 => Algorithm::Crc64, + ALGO_SHA256 => Algorithm::Sha256, + _ => Self::default(), + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 7377b4d..bc14945 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,8 @@ mod tests { fn it_works() -> Result<(), error::Error> { let input = b"lolis are super ultra mega cute"; - let kana = generate(input, salt::Salt::default())?; + let context = ctx::Context::default(); + let kana = generate(&context, input)?; println!("kana: {}", kana); assert_eq!(kana, "ワイトひはっトと"); Ok(()) @@ -24,7 +25,7 @@ mod tests { #[test] fn ffi() -> Result<(), Box> { - + Ok(()) } } @@ -45,17 +46,19 @@ mod hash; mod provider; mod mnemonic; mod error; +mod ctx; #[macro_use] mod ffi; use ffi::*; -fn compute(mut from: T, salt: salt::Salt) -> Result<(usize, String), error::Error> +fn compute(context: &ctx::Context, mut from: T) -> Result<(usize, String), error::Error> { - let (read, hash) = provider::compute::<_, Digest>(&mut from, salt)?; + //let (read, hash) = provider::compute::<_, Digest>(&mut from, salt)?; + let (read, hash) = context.compute(&mut from)?; let mut output = String::with_capacity(128); - for element in hash.bytes().iter() + for element in hash.into_iter() .into_16() .map(|bytes| mnemonic::Digest::new(unsafe{reinterpret::bytes(&bytes)})) { @@ -65,11 +68,11 @@ fn compute(mut from: T, salt: salt::Sal Ok((read,output)) } -pub fn generate>(bytes: T, salt: salt::Salt) -> Result +pub fn generate>(context: &ctx::Context, bytes: T) -> Result { let bytes = bytes.as_ref(); let mut nbytes = bytes; - let (ok, string) = compute::<_, HASHER>(&mut nbytes,salt)?; + let (ok, string) = compute(context, &mut nbytes)?; if ok == bytes.len() { Ok(string) } else { @@ -94,12 +97,13 @@ use malloc_array::{ /// # Note /// Does not consume `salt` #[no_mangle] -pub unsafe extern "C" fn khash_length(bin: *const c_void, sz: size_t, salt: *const salt::FFI, out_len: *mut size_t) -> i32 +pub unsafe extern "C" fn khash_length(context: *const ctx::CContext, bin: *const c_void, sz: size_t, out_len: *mut size_t) -> i32 { no_unwind!{ try error::Error::Unknown; + let context = ctx::Context::clone_from_raw(context); let bin = HeapArray::::from_raw_copied(bin as *const u8, usize::from(sz)); - let string = c_try!(generate(&bin, salt::clone_from_raw(salt))); + let string = c_try!(generate(&context, &bin)); *out_len = string.bytes().len().into(); GENERIC_SUCCESS @@ -111,12 +115,14 @@ pub unsafe extern "C" fn khash_length(bin: *const c_void, sz: size_t, salt: *con /// # Note /// Consumes `salt` #[no_mangle] -pub unsafe extern "C" fn khash_do(bin: *const c_void, sz: size_t, salt: *mut salt::FFI, out_str: *mut c_char, str_len: size_t) -> i32 +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 { no_unwind!{ try error::Error::Unknown; + + let context = ctx::Context::from_raw(context); let bin = HeapArray::::from_raw_copied(bin as *const u8, usize::from(sz)); - let string: Vec = c_try!(generate(&bin, salt::from_raw(salt))).bytes().collect(); + let string: Vec = c_try!(generate(&context, &bin)).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())); @@ -124,6 +130,57 @@ pub unsafe extern "C" fn khash_do(bin: *const c_void, sz: size_t, salt: *mut sal } } +/// Free a context +#[no_mangle] +pub unsafe extern "C" fn khash_free_context(context: *mut ctx::CContext) -> i32 +{ + no_unwind!{ + drop(ctx::Context::from_raw(context)); + GENERIC_SUCCESS + } +} + +/// 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 +{ + no_unwind!{ + try error::Error::Unknown; + let salt = match salt_type { + salt::SALT_TYPE_SPECIFIC => { + let bin = HeapArray::::from_raw_copied(bin as *const u8, usize::from(sz)); + salt::Salt::unfixed(&bin[..]) + }, + salt::SALT_TYPE_DEFAULT => { + salt::Salt::default() + }, + salt::SALT_TYPE_RANDOM => { + match salt::Salt::random() { + Ok(v) => v, + Err(e) => return i32::from(error::Error::RNG(e)), + } + }, + _ => { + salt::Salt::None + }, + }; + let context = ctx::Context::new(algo.into(), salt); + *nptr = context.into_raw(); + GENERIC_SUCCESS + } +} + + +/// Clone a context +#[no_mangle] +pub unsafe extern "C" fn khash_clone_context(raw: *const ctx::CContext, out: *mut ctx::CContext) -> i32 +{ + no_unwind!{ + *out = ctx::Context::clone_from_raw(raw).into_raw(); + GENERIC_SUCCESS + } +} + /// Free a salt allocated with `khash_new_salt` #[no_mangle] pub unsafe extern "C" fn khash_free_salt(salt: *mut salt::FFI) -> i32 @@ -162,6 +219,7 @@ 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 {