diff --git a/build.rs b/build.rs index 8a5b477..86c8dfc 100644 --- a/build.rs +++ b/build.rs @@ -24,8 +24,8 @@ fn build_cookie_wrapper(floc: impl AsRef) .flag_if_supported("-flto") // Not sure if we want these two. We can check the codegen later. - .pic(false) - .use_plt(false) + //.pic(false) + //.use_plt(false) .file(Path::new(FFI_SRC_DIR).join(floc)) .compile("cwrapper"); @@ -52,4 +52,6 @@ fn main() { } build_cookie_wrapper("wrapper.c"); + +//println!("cargo:rustc-link-lib={}", link); } diff --git a/include/cc20.h b/include/cc20.h index efc799d..9904259 100644 --- a/include/cc20.h +++ b/include/cc20.h @@ -36,6 +36,9 @@ typedef struct cc20_metadata { typedef struct cc20_sink cc20_sink_t; +// Functions // +#define _cc20_OUT *restrict + cc20_result_t cc20_keygen(cc20_key_t* restrict key, cc20_iv_t* restrict iv); @@ -43,27 +46,31 @@ cc20_result_t cc20_gen_meta(FILE* file, const cc20_key_t* key, const cc20_iv_t* iv, enum cc20_mode mode, - struct cc20_metadata* restrict output); + struct cc20_metadata _cc20_OUT output); + +cc20_result_t cc20_gen_sink(const struct cc20_metadata* meta, cc20_sink_t* _cc20_OUT output); -cc20_sink_t* cc20_gen_sink(const struct cc20_metadata* meta); -cc20_sink_t* cc20_gen_sink_full(FILE* file, +cc20_result_t cc20_gen_sink_full(FILE* file, const cc20_key_t* key, const cc20_iv_t* iv, - enum cc20_mode mode); + enum cc20_mode mode, + cc20_sink_t* _cc20_OUT output); -FILE* cc20_wrap_full(FILE* file, +cc20_result_t cc20_wrap_full(FILE* file, const cc20_key_t* key, const cc20_iv_t* iv, - enum cc20_mode mode); + enum cc20_mode mode, + FILE* _cc20_OUT output); -FILE* cc20_gen(const struct cc20_metadata* meta); +cc20_result_t cc20_gen(const struct cc20_metadata* meta, + FILE* _cc20_OUT output); cc20_result_t cc20_close_sink(cc20_sink_t* sink, struct cc20_metadata* restrict meta); FILE* cc20_wrap_sink(cc20_sink_t* sink); -size_t cc20_write(const void* ptr, size_t size, size_t nmemb, cc20_sink_t* restrict sink); +cc20_result_t cc20_write(const void* ptr, size_t * restrict bytes, cc20_sink_t* restrict sink); #endif /* _CC20_H */ diff --git a/src/ffi.rs b/src/ffi.rs index da35e62..05c6513 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -61,25 +61,24 @@ pub use error::*; }).unwrap_or(CErr::Panic) } -#[no_mangle] pub unsafe extern "C" fn cc20_write(ptr: *const c_void, size: usize, nmemb: usize, sink: *mut CSink) -> usize +#[no_mangle] pub unsafe extern "C" fn cc20_write(ptr: *const c_void, bytes: *mut usize, sink: *mut CSink) -> CErr { - let mut output: usize = 0; - let _er = no_unwind!(ref { + no_unwind!({ let sink = nullchk!(ref mut sink); - let bytes = size * nmemb; + let nbytes = nullchk!(move bytes); + let slice = if ptr.is_null() { return CErr::NullPointer; } else { - std::slice::from_raw_parts(ptr as *const u8, bytes) + std::slice::from_raw_parts(ptr as *const u8, nbytes) }; match sink.sink.write(&slice[..]) { Err(_) => return CErr::IO, - Ok(v) => output = v, + Ok(v) => *bytes = v, } CErr::Success - }).unwrap_or(CErr::Panic); - //TODO: Write `er` into an error flag for `sink` (parallel to `ferror`/`feof`). - output + }) + .unwrap_or(CErr::Panic) } #[no_mangle] pub unsafe extern "C" fn cc20_gen_meta(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode, output: *mut CPassthrough) -> CErr @@ -111,10 +110,11 @@ pub use error::*; } /// Create an encrypting `Sink` over a `FILE*` from this metadata struct. -#[no_mangle] pub unsafe extern "C" fn cc20_gen_sink(meta: *const CPassthrough) -> *mut CSink +#[no_mangle] pub unsafe extern "C" fn cc20_gen_sink(meta: *const CPassthrough, output: *mut *mut CSink) -> CErr { no_unwind!({ let meta = nullchk!(ref meta); + let output = nullchk!(ref mut output); let sink = CSink { sink: match meta.mode { @@ -122,42 +122,41 @@ pub use error::*; CMode::Decrypt => Sink::decrypt(meta.clone(), meta.key, meta.iv).map_err(|_| CErr::SslError).unwrap(), }, }; - - interop::give(sink) - }).unwrap_or(ptr::null_mut()) + *output = interop::give(sink); + CErr::Success + }).unwrap_or(CErr::Panic) } + /// Create an encrypting `Sink` over a `FILE*` with these options. -#[no_mangle] pub unsafe extern "C" fn cc20_gen_sink_full(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode) -> *mut CSink +#[no_mangle] pub unsafe extern "C" fn cc20_gen_sink_full(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode, output: *mut *mut CSink) -> CErr { let meta = { // No need to `no_unwind` this, `cc20_gen_meta` already does it, and nothing else here can panic. let mut meta: std::mem::MaybeUninit = std::mem::MaybeUninit::uninit(); - match cc20_gen_meta(file, key, iv, mode, &mut meta as *mut _ as *mut CPassthrough).into() { - 0i32 => meta.assume_init(), - _ => return ptr::null_mut(), + match cc20_gen_meta(file, key, iv, mode, &mut meta as *mut _ as *mut CPassthrough) { + CErr::Success => meta.assume_init(), + x => return x, } }; - cc20_gen_sink(&meta as *const _) + cc20_gen_sink(&meta as *const _, output) } -#[no_mangle] pub unsafe extern "C" fn cc20_gen(meta: *const CPassthrough) -> *mut libc::FILE +#[no_mangle] pub unsafe extern "C" fn cc20_gen(meta: *const CPassthrough, output: *mut *mut libc::FILE) -> CErr { - let sink = cc20_gen_sink(meta); - if sink.is_null() { - return ptr::null_mut(); - } - cc20_wrap_sink(sink) + let mut sink: *mut CSink = ptr::null_mut(); + errchk!(cc20_gen_sink(meta, &mut sink as *mut *mut CSink)); + *output = cc20_wrap_sink(sink); + CErr::Success } /// Create a wrapper `FILE*` that acts as a `Sink` when written to. -#[no_mangle] pub unsafe extern "C" fn cc20_wrap_full(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode) -> *mut libc::FILE +#[no_mangle] pub unsafe extern "C" fn cc20_wrap_full(file: *mut libc::FILE, key: *const Key, iv: *const IV, mode: CMode, output: &mut *mut libc::FILE) -> CErr { // No need to `no_unwind` this, nothing here can panic. - let csink = cc20_gen_sink_full(file, key, iv, mode); - if csink.is_null() { - return ptr::null_mut(); - } - cc20_wrap_sink(csink) + let mut csink: *mut CSink = ptr::null_mut(); + errchk!(cc20_gen_sink_full(file, key, iv, mode, &mut csink as *mut *mut CSink)); + *output = cc20_wrap_sink(csink); + CErr::Success } /// Closes and frees the wrapper `sink`, and writes inner metadata struct to `meta`, if `file` is non-null. #[no_mangle] pub unsafe extern "C" fn cc20_close_sink(sink: *mut CSink, meta: *mut CPassthrough) -> CErr @@ -174,7 +173,9 @@ pub use error::*; /// Convert a `Sink` into a `FILE*`. #[no_mangle] pub unsafe extern "C" fn cc20_wrap_sink(sink: *mut CSink) -> *mut libc::FILE { - //todo!("Create a Custom Stream in `wrapper.c` that allows creating a FILE* object from `sink`.") + if sink.is_null() { + return ptr::null_mut(); + } cookie::create(sink) } diff --git a/src/ffi/error.rs b/src/ffi/error.rs index cf52eae..444baac 100644 --- a/src/ffi/error.rs +++ b/src/ffi/error.rs @@ -2,6 +2,15 @@ use super::*; +#[macro_export] macro_rules! errchk { + ($expr:expr) => { + match CErr::from($expr) { + CErr::Success => (), + x => return x, + } + }; +} + //TODO: Rework the error handling/reporting here. #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)] #[repr(C)] diff --git a/src/ffi/wrapper.c b/src/ffi/wrapper.c index 24f4701..64e87a9 100644 --- a/src/ffi/wrapper.c +++ b/src/ffi/wrapper.c @@ -18,8 +18,9 @@ static ssize_t cc20c_read(void* cookie, char* buffer, size_t size) static ssize_t cc20c_write(void* cookie, const char* buffer, size_t size) { - register int c = cc20_write(buffer, 1, size, cookie); - return c < 0 ? 0 : c; + cc20_result_t res = cc20_write(buffer, &size, cookie); + IGNORE(res); // TODO: set an error flag `res` in `cookie` (i.e. `CSink`) + return (ssize_t) size; } static int cc20c_seek(void* cookie, off64_t* pos, int w) diff --git a/test.c b/test.c index ede075a..20f9138 100644 --- a/test.c +++ b/test.c @@ -4,7 +4,9 @@ #include -#define TRY(expr) do { if(CC20_ERR(res = (expr))) fprintf(stderr, "cc20 error %d: " #expr "\n", (int)res); goto fail; } while(0) +#define TRY(expr) do { if(CC20_ERR(res = (expr))) { fprintf(stderr, "cc20 error %d: " #expr "\n", (int)res); goto fail; } } while(0) + +const char write_string[] = "Hello world?"; int main(int argc, char** argv) { @@ -15,9 +17,11 @@ int main(int argc, char** argv) if(!output) { perror("failed to open output"); return -1; } TRY(cc20_gen_meta(output, NULL, NULL, CC20_ENCRYPT, &meta)); - if(! (output = cc20_gen(&meta)) ) { perror("failed to open encrypted output"); fclose(meta.backing); return -1; } + TRY(cc20_gen(&meta, &output)); + + printf("written %lu bytes\n", fwrite(write_string, 1, strlen(write_string), output)); - fprintf(output, "Hello world!"); + //fprintf(output, "Hello world!"); res = CC20_ERR_NONE; fail: diff --git a/test.sh b/test.sh index 4d2880d..1cc1806 100755 --- a/test.sh +++ b/test.sh @@ -1,5 +1,7 @@ #!/bin/bash -gcc test.c -Iinclude -Wall --std=gnu11 -pedantic -Wextra -O3 -o test-ffi -l:target/debug/libchacha20stream.so || exit -./test-ffi -rm -f test-ffi +gcc test.c -Iinclude -Wall --std=gnu11 -pedantic -Wextra -O3 -o test-ffi -l:target/release/libchacha20stream.so || exit +#-lssl -lcrypto -lpthread -ldl || exit +valgrind ./test-ffi test-ffi-output +hexview test-ffi-output +rm -f test-ffi{,-output}