pull/1/head
Avril 4 years ago
parent ed306ed9f1
commit 2e7e4a69af
Signed by: flanchan
GPG Key ID: 284488987C31F630

1
.gitignore vendored

@ -2,3 +2,4 @@
Cargo.lock
*~
node_modules/
test/build/test

@ -1,6 +1,7 @@
[package]
name = "kana-hash"
version = "0.1.0"
name = "khash"
description = "Kana hashes"
version = "1.0.0"
authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018"
@ -10,8 +11,8 @@ crate-type = ["cdylib"]
[dependencies]
sha2 = "0.9"
malloc-array = "1.3.3"
malloc-array = "1.4"
libc = "0.2"
crc = "1.8"
hex-literal = "0.2"
getrandom = "0.1"
getrandom = "0.1"

@ -1,7 +1,15 @@
INSTALL:= /usr/local/lib
khash:
cargo build --release
strip ./target/release/libkhash.so
test:
cargo test
cd test && $(MAKE)
install:
cp ./target/release/libkana_hash.so /usr/lib/libkana_hash.so
cp -f ./target/release/libkhash.so $(INSTALL)/libkhash.so
uninstall:
rm -f $(INSTALL)/libkana_hash.so

@ -0,0 +1 @@
Add ability to specify which hashing algorithm is used.

@ -0,0 +1,54 @@
#ifndef _KHASH_H
#define _KHASH_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
/// No salt
#define KHASH_SALT_TYPE_NONE ((uint8_t)0)
/// The default static salt
#define KHASH_SALT_TYPE_DEFAULT ((uint8_t)1)
/// A specific salt passed as `data` to `khash_new_salt`.
#define KHASH_SALT_TYPE_SPECIFIC ((uint8_t)2)
/// A randomly generated salt.
#define KHASH_SALT_TYPE_RANDOM ((uint8_t)3)
/// A valid salt for khash functions. Initialised with `khash_new_salt`.
typedef struct {
uint8_t salt_type;
uint32_t size;
uint8_t* body;
} khash_salt;
/// Returned by all functions that succeed.
#define KHASH_SUCCESS ((int32_t)0)
/// Reading into the hash failed
#define KHASH_ERROR_IO ((int32_t)1)
/// Formatting the has failed
#define KHASH_ERROR_FORMAT ((int32_t)2)
/// Bad hash length
#define KHASH_ERROR_LENGTH ((int32_t)3)
/// Random number generation failed
#define KHASH_ERROR_RNG ((int32_t)4)
/// Unknown error
#define KHASH_ERROR_UNKNOWN ((int32_t)-1)
/// Create a new salt. `salt_type` is expected to be one of the above defined `KHASH_SALT_TYPE_*` macros.
/// Depending on the type, `data` may be `NULL`.
extern int32_t khash_new_salt(uint8_t salt_type, const void* data, size_t size, khash_salt* output);
/// Free a salt allocated with `khash_new_salt`. It is okay to call this multiple times.
extern int32_t khash_free_salt(khash_salt* salt);
/// 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);
/// 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);
#ifdef __cplusplus
}
#endif
#endif /* _KHASH_H */

@ -24,26 +24,7 @@ mod tests {
#[test]
fn ffi() -> Result<(), Box<dyn std::error::Error>>
{
unsafe {
unsafe fn work_with_salt(salt: salt::Salt) -> Result<String, error::Error> {
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(())
}
}
@ -113,12 +94,12 @@ use malloc_array::{
/// # Note
/// Does not consume `salt`
#[no_mangle]
pub unsafe extern "C" fn _kana_length(bin: *const c_void, sz: size_t, salt: *const c_void, out_len: *mut size_t) -> i32
pub unsafe extern "C" fn khash_length(bin: *const c_void, sz: size_t, salt: *const salt::FFI, out_len: *mut size_t) -> i32
{
no_unwind!{
try error::Error::Unknown;
let bin = HeapArray::<u8>::from_raw_copied(bin as *const u8, usize::from(sz));
let string = c_try!(generate(&bin, salt::clone_from_raw(salt as *const salt::FFI)));
let string = c_try!(generate(&bin, salt::clone_from_raw(salt)));
*out_len = string.bytes().len().into();
GENERIC_SUCCESS
@ -130,12 +111,12 @@ pub unsafe extern "C" fn _kana_length(bin: *const c_void, sz: size_t, salt: *con
/// # Note
/// Consumes `salt`
#[no_mangle]
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
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
{
no_unwind!{
try error::Error::Unknown;
let bin = HeapArray::<u8>::from_raw_copied(bin as *const u8, usize::from(sz));
let string: Vec<u8> = c_try!(generate(&bin, salt::from_raw(salt as *mut salt::FFI))).bytes().collect();
let string: Vec<u8> = c_try!(generate(&bin, salt::from_raw(salt))).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()));
@ -143,32 +124,40 @@ pub unsafe extern "C" fn _kana_do(bin: *const c_void, sz: size_t, salt: *mut c_v
}
}
/// Free a salt allocated with `_kana_new_salt`
/// Free a salt allocated with `khash_new_salt`
#[no_mangle]
pub unsafe extern "C" fn _kana_free_salt(salt: *mut c_void) -> i32
pub unsafe extern "C" fn khash_free_salt(salt: *mut salt::FFI) -> i32
{
no_unwind!{
drop(salt::from_raw(salt as *mut salt::FFI));
drop(salt::from_raw(salt));
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
pub unsafe extern "C" fn khash_new_salt(salt_type: u8, bin: *const c_void, sz: size_t, nptr: *mut salt::FFI) -> 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::<u8>::from_raw_copied(bin as *const u8, usize::from(sz));
*nptr = salt::into_raw(salt::Salt::unfixed(&bin[..]));
match salt_type {
salt::SALT_TYPE_SPECIFIC => {
let bin = HeapArray::<u8>::from_raw_copied(bin as *const u8, usize::from(sz));
*nptr = salt::into_raw(salt::Salt::unfixed(&bin[..]));
},
salt::SALT_TYPE_DEFAULT => {
*nptr = salt::into_raw(salt::Salt::default());
},
salt::SALT_TYPE_RANDOM => {
*nptr = salt::into_raw(match salt::Salt::random() {
Ok(v) => v,
Err(e) => return i32::from(error::Error::RNG(e)),
})
},
_ => {
*nptr = salt::into_raw(salt::Salt::None);
},
}
GENERIC_SUCCESS
}
}

@ -11,6 +11,7 @@ use std::{
self,
Write,
},
convert::{TryInto,TryFrom},
};
pub const SIZE: usize = 32;
@ -81,70 +82,84 @@ impl Salt
#[derive(Copy,Clone,Debug)]
#[repr(C)]
#[repr(packed)]
pub struct FFI
{
size: usize,
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;
/// 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())
let ffi = &*ptr;
match ffi.salt_type {
SALT_TYPE_SPECIFIC => {
Salt::Dynamic(HeapArray::from_raw_copied(ffi.body as *const u8, usize::try_from(ffi.size).unwrap()).into_boxed_slice())
},
SALT_TYPE_DEFAULT => {
Salt::default()
},
_ => Salt::None,
}
}
/// 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())
}
let ffi = &mut *ptr;
let out = match ffi.salt_type {
SALT_TYPE_SPECIFIC => {
Salt::Dynamic(HeapArray::from_raw_parts(ffi.body as *mut u8, usize::try_from(ffi.size).unwrap()).into_boxed_slice())
},
SALT_TYPE_DEFAULT => {
Salt::default()
},
_ => Salt::None,
};
ffi.salt_type = SALT_TYPE_NONE;
ffi.size = 0;
ffi.body = 0 as *mut u8;
out
}
/// Consume a `Salt` and output a newly allocated `FFI` salt.
pub unsafe fn into_raw(salt: Salt) -> *mut FFI
/// Consume a `Salt` and output a new `FFI` salt.
pub unsafe fn into_raw(salt: Salt) -> FFI
{
unsafe fn genffi(bytes: &[u8]) -> *mut FFI
unsafe fn allocate(slice: impl AsRef<[u8]>) -> 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
let (body, size) = box_with_malloc(slice);
FFI {
salt_type: SALT_TYPE_SPECIFIC,
size: size.try_into().unwrap(),
body
}
}
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()),
match &salt {
Salt::None => FFI {
salt_type: SALT_TYPE_NONE,
size: 0,
body: 0 as *mut u8,
},
Salt::Static(STATIC_SALT) => FFI {
salt_type: SALT_TYPE_DEFAULT,
size: 0,
body: 0 as *mut u8,
},
Salt::Dynamic(bytes) => allocate(&bytes),
Salt::Fixed(bytes) | &Salt::Static(bytes) => allocate(&bytes),
}
}
fn box_with_malloc(slice: impl AsRef<[u8]>) -> (*mut u8, usize)
{
unsafe { HeapArray::from_slice_copied(slice) }.into_raw_parts()
}

@ -0,0 +1,15 @@
SRC:= src/*.c
INCLUDE:=include/
LIB:=../target/release
BUILD:=build/
CFLAGS:= -g -Wall -pedantic
LFLAGS:= -L$(LIB) -lkhash
all: clean test
clean:
test:
gcc $(SRC) -I$(INCLUDE) $(CFLAGS) -o $(BUILD)/$@ $(LFLAGS)
$(BUILD)/$@

@ -0,0 +1 @@
../include

@ -0,0 +1 @@
../../target/release/libkhash.so

@ -0,0 +1,25 @@
#include <stdio.h>
#include <khash.h>
#include <assert.h>
#include <locale.h>
#include <alloca.h>
#include <string.h>
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);
size_t length;
assert(khash_length(string, strlen(string), &salt, &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);
printf("output: %s\n", output);
return 0;
}
Loading…
Cancel
Save