cookie config alowing backing stream ownership transfer to be optional

ffi
Avril 3 years ago
parent d5c9492c44
commit b7c8c64733
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -34,6 +34,11 @@ typedef struct cc20_metadata {
enum cc20_mode mode; enum cc20_mode mode;
} cc20_meta_t; } cc20_meta_t;
struct cc20_wrap_cfg {
// default: false (0)
int keep_alive;
};
typedef struct cc20_sink cc20_sink_t; typedef struct cc20_sink cc20_sink_t;
// Functions // // Functions //
@ -48,7 +53,8 @@ cc20_result_t cc20_gen_meta(FILE* file,
enum cc20_mode mode, enum cc20_mode mode,
struct cc20_metadata _cc20_OUT 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_result_t cc20_gen_sink(const struct cc20_metadata* meta,
cc20_sink_t* _cc20_OUT output);
cc20_result_t cc20_gen_sink_full(FILE* file, cc20_result_t cc20_gen_sink_full(FILE* file,
@ -69,8 +75,8 @@ cc20_result_t cc20_gen(const struct cc20_metadata* meta,
cc20_result_t cc20_close_sink(cc20_sink_t* sink, cc20_result_t cc20_close_sink(cc20_sink_t* sink,
struct cc20_metadata* restrict meta); struct cc20_metadata* restrict meta);
FILE* cc20_wrap_sink(cc20_sink_t* sink);
cc20_result_t cc20_write(const void* ptr, size_t * restrict bytes, cc20_sink_t* restrict sink); cc20_result_t cc20_write(const void* ptr, size_t * restrict bytes, cc20_sink_t* restrict sink);
FILE* cc20_wrap_sink(cc20_sink_t* sink, const struct cc20_wrap_cfg* cfg);
#endif /* _CC20_H */ #endif /* _CC20_H */

@ -32,6 +32,7 @@ pub struct CSink
{ {
sink: Sink<CPassthrough>, sink: Sink<CPassthrough>,
cookie_settings: cookie::Config,
//last_err: () //TODO: how to implement this? //last_err: () //TODO: how to implement this?
} }
@ -123,6 +124,7 @@ pub use error::*;
CMode::Encrypt => Sink::encrypt(meta.clone(), meta.key, meta.iv).map_err(|_| CErr::SslError).unwrap(), CMode::Encrypt => Sink::encrypt(meta.clone(), meta.key, meta.iv).map_err(|_| CErr::SslError).unwrap(),
CMode::Decrypt => Sink::decrypt(meta.clone(), meta.key, meta.iv).map_err(|_| CErr::SslError).unwrap(), CMode::Decrypt => Sink::decrypt(meta.clone(), meta.key, meta.iv).map_err(|_| CErr::SslError).unwrap(),
}, },
cookie_settings: Default::default(),
}; };
*output = interop::give(sink); *output = interop::give(sink);
CErr::Success CErr::Success
@ -147,7 +149,7 @@ pub use error::*;
{ {
let mut sink: *mut CSink = ptr::null_mut(); let mut sink: *mut CSink = ptr::null_mut();
errchk!(cc20_gen_sink(meta, &mut sink as *mut *mut CSink)); errchk!(cc20_gen_sink(meta, &mut sink as *mut *mut CSink));
*output = cc20_wrap_sink(sink); *output = cc20_wrap_sink(sink, ptr::null());
CErr::Success CErr::Success
} }
@ -157,7 +159,7 @@ pub use error::*;
// No need to `no_unwind` this, nothing here can panic. // No need to `no_unwind` this, nothing here can panic.
let mut csink: *mut CSink = ptr::null_mut(); let mut csink: *mut CSink = ptr::null_mut();
errchk!(cc20_gen_sink_full(file, key, iv, mode, &mut csink as *mut *mut CSink)); errchk!(cc20_gen_sink_full(file, key, iv, mode, &mut csink as *mut *mut CSink));
*output = cc20_wrap_sink(csink); *output = cc20_wrap_sink(csink, ptr::null());
CErr::Success CErr::Success
} }
/// Closes and frees the wrapper `sink`, and writes inner metadata struct to `meta`, if `file` is non-null. /// Closes and frees the wrapper `sink`, and writes inner metadata struct to `meta`, if `file` is non-null.
@ -172,12 +174,16 @@ pub use error::*;
}).unwrap_or(CErr::Panic) }).unwrap_or(CErr::Panic)
} }
/// Convert a `Sink` into a `FILE*`. /// Convert a `Sink` into a `FILE*` with specific config (if not `NULL`).
#[no_mangle] pub unsafe extern "C" fn cc20_wrap_sink(sink: *mut CSink) -> *mut libc::FILE #[no_mangle] pub unsafe extern "C" fn cc20_wrap_sink(sink: *mut CSink, config: *const cookie::Config) -> *mut libc::FILE
{ {
if sink.is_null() { if sink.is_null() {
return ptr::null_mut(); return ptr::null_mut();
} }
if !config.is_null() {
let sink = &mut *sink;
sink.cookie_settings = *config;
}
cookie::create(sink) cookie::create(sink)
} }

@ -15,7 +15,25 @@ use libc::{
FILE, FILE,
}; };
//TODO: Remove `wrapper.c`, implement it in Rust here /// Configuration for the `FILE*` wrapper
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Copy)]
#[repr(C)]
pub struct Config
{
pub keep_alive: c_int,
}
impl Default for Config
{
#[inline]
fn default() -> Self
{
Self {
keep_alive: 0,
}
}
}
type cookie_read_function_t = Option<extern "C" fn (cookie: *mut c_void, buf: *mut c_char , size: size_t) -> ssize_t>; type cookie_read_function_t = Option<extern "C" fn (cookie: *mut c_void, buf: *mut c_char , size: size_t) -> ssize_t>;
type cookie_write_function_t = Option<extern "C" fn (cookie: *mut c_void, buf: *const c_char, size: size_t) -> ssize_t>; type cookie_write_function_t = Option<extern "C" fn (cookie: *mut c_void, buf: *const c_char, size: size_t) -> ssize_t>;
@ -98,10 +116,14 @@ extern "C" fn close(cookie: *mut c_void) -> c_int
} else { } else {
cookie as *mut CSink cookie as *mut CSink
}; };
let sink = unsafe { interop::take(sink) }; let CSink { sink, cookie_settings } = unsafe { interop::take(sink) };
drop(sink); let mut meta = sink.into_inner();
if cookie_settings.keep_alive == 0 && !meta.backing.is_null() {
unsafe { (libc::fclose(meta.backing), meta.backing = ptr::null_mut()).0 }
} else {
0 0
} }
}
#[inline(always)] pub unsafe fn create(raw_sink: *mut CSink) -> *mut FILE #[inline(always)] pub unsafe fn create(raw_sink: *mut CSink) -> *mut FILE
{ {

@ -8,23 +8,74 @@
const char write_string[] = "Hello world?"; const char write_string[] = "Hello world?";
FILE* wrap_stream(FILE* wrap, enum cc20_mode mode, const cc20_key_t* k, const cc20_iv_t* i, cc20_meta_t *restrict meta)
{
cc20_meta_t _meta = {0};
if(!meta) meta = &_meta;
if(CC20_OK(cc20_gen_meta(wrap, k, i, mode, meta)))
{
cc20_sink_t* sink;
if(CC20_OK(cc20_gen_sink(meta, &sink)))
return cc20_wrap_sink(sink, (struct cc20_wrap_cfg[1]) {{ .keep_alive = 1 }} );
else perror("cc20_gen_sink()");
} else perror("cc20_gen_meta()");
exit(-1);
}
FILE* wrap_file(const char* filename, enum cc20_mode mode, cc20_meta_t* restrict meta)
{
cc20_meta_t _meta = {0};
if(!meta) meta = &_meta;
FILE* wrap = fopen(filename, "w+b");
if(!wrap) {
perror("fopen()");
exit(-1);
}
return wrap_stream(wrap, mode, NULL, NULL, meta);
/*
if(CC20_OK(cc20_gen_meta(wrap, NULL, NULL, mode, meta))
&& CC20_OK(cc20_gen(meta, &wrap))) return wrap;
perror("cc20_gen()");
exit(-1);*/
}
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
((void)argc);
if(!argv[1]) return 1;
cc20_meta_t meta; cc20_meta_t meta;
cc20_result_t res;
FILE* output = argv[1] ? fopen(argv[1], "wb") : stdout; FILE* output = wrap_file(argv[1], CC20_ENCRYPT, &meta);
if(!output) { perror("failed to open output"); return -1; } size_t wsz;
printf("written %lu bytes\n", (wsz=fwrite(write_string, 1, strlen(write_string), output)));
fclose(output);
FILE* input = meta.backing;
long sz = ftell(input);
printf(" -> backing stream tell: %ld\n", sz);
if(sz<=0) return (perror("ftell()"), -1);
else if(wsz != (size_t)sz) return (fprintf(stderr, "incorrect ftell(): (expected %lu, got %ld)\n", wsz, sz), -2);
if(fseek(input, 0L, SEEK_SET)!=0) return (perror("fseek()"), -3);
TRY(cc20_gen_meta(output, NULL, NULL, CC20_ENCRYPT, &meta)); unsigned char encbuf[wsz];
TRY(cc20_gen(&meta, &output)); if(fread(encbuf, 1, wsz, input)!=wsz) return (perror("fread()"), -4);
printf("written %lu bytes\n", fwrite(write_string, 1, strlen(write_string), output)); printf("decrypted: '"); {
/* owning stdout */
output = wrap_stream(stdout, CC20_DECRYPT, (const cc20_key_t*) &meta.key, (const cc20_iv_t*) &meta.iv, NULL);
wsz = fwrite(encbuf, 1, wsz, output);
fclose(output);
/* releases stdout */
printf("'\n"); }
printf("written %lu bytes\n", wsz);
//fprintf(output, "Hello world!"); fclose(input);
res = CC20_ERR_NONE; return 0;
fail:
if(output) fclose(output);
return (int)res;
} }

@ -1,6 +1,6 @@
#!/bin/bash #!/bin/bash
gcc test.c -Iinclude -Wall --std=gnu11 -pedantic -Wextra -O3 -o test-ffi -l:target/release/libchacha20stream.a -lssl -lcrypto -lpthread -ldl || exit gcc test.c -Iinclude -Wall --std=gnu11 -pedantic -Wextra -Og -g -o test-ffi -l:target/debug/libchacha20stream.a -lssl -lcrypto -lpthread -ldl || exit
valgrind ./test-ffi test-ffi-output valgrind ./test-ffi test-ffi-output
hexview test-ffi-output hexview test-ffi-output
rm -f test-ffi{,-output} rm -f test-ffi{,-output}

Loading…
Cancel
Save