diff --git a/include/cc20.h b/include/cc20.h index 9484ac6..efc799d 100644 --- a/include/cc20.h +++ b/include/cc20.h @@ -11,6 +11,19 @@ enum cc20_mode { CC20_DECRYPT, }; +typedef enum cc20_error { + CC20_ERR_PANIC = -1, + CC20_ERR_NONE = 0, + + CC20_ERR_INVALID_FILE, + CC20_ERR_NULL_PTR, + CC20_ERR_SSL, + CC20_ERR_IO +} cc20_result_t; + +#define CC20_OK(v) ((v)==CC20_ERR_NONE) +#define CC20_ERR(v) ((v)!=CC20_ERR_NONE) + typedef uint8_t cc20_key_t[KEY_SIZE]; typedef uint8_t cc20_iv_t[IV_SIZE]; @@ -23,7 +36,10 @@ typedef struct cc20_metadata { typedef struct cc20_sink cc20_sink_t; -int cc20_gen_meta(FILE* file, +cc20_result_t cc20_keygen(cc20_key_t* restrict key, + cc20_iv_t* restrict iv); + +cc20_result_t cc20_gen_meta(FILE* file, const cc20_key_t* key, const cc20_iv_t* iv, enum cc20_mode mode, @@ -43,7 +59,7 @@ FILE* cc20_wrap_full(FILE* file, FILE* cc20_gen(const struct cc20_metadata* meta); -int cc20_close_sink(cc20_sink_t* sink, +cc20_result_t cc20_close_sink(cc20_sink_t* sink, struct cc20_metadata* restrict meta); FILE* cc20_wrap_sink(cc20_sink_t* sink); diff --git a/src/ffi.rs b/src/ffi.rs index e3bdcbc..d6117c7 100644 --- a/src/ffi.rs +++ b/src/ffi.rs @@ -58,6 +58,20 @@ mod cookie; mod error; pub use error::*; +#[no_mangle] pub unsafe extern "C" fn cc20_keygen(key: *mut Key, iv: *mut IV) -> CErr +{ + no_unwind!(ref { + if !key.is_null() { + *key = Key::new(); + } + if !iv.is_null() { + *iv = IV::new(); + } + + CErr::Success + }).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 { let mut output: usize = 0; @@ -79,14 +93,22 @@ pub use error::*; output } -#[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) -> i32 +#[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 { no_unwind!({ if file.is_null() { return CErr::InvalidFile; } - let key = nullchk!(move key); - let iv = nullchk!(move iv); + let key = if key.is_null() { + Key::new() + } else { + *key + }; + let iv = if iv.is_null() { + IV::new() + } else { + *iv + }; let write = CPassthrough { backing: file, key, @@ -96,7 +118,7 @@ pub use error::*; nullchk!(output); output.write(write); CErr::Success - }).unwrap_or(CErr::Panic).into() + }).unwrap_or(CErr::Panic) } /// Create an encrypting `Sink` over a `FILE*` from this metadata struct. @@ -121,8 +143,8 @@ pub use error::*; 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) { - 0 => meta.assume_init(), + match cc20_gen_meta(file, key, iv, mode, &mut meta as *mut _ as *mut CPassthrough).into() { + 0i32 => meta.assume_init(), _ => return ptr::null_mut(), } }; @@ -149,7 +171,7 @@ pub use error::*; cc20_wrap_sink(csink) } /// 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) -> i32 +#[no_mangle] pub unsafe extern "C" fn cc20_close_sink(sink: *mut CSink, meta: *mut CPassthrough) -> CErr { no_unwind!({ let sink = interop::take(nullchk!(sink)); @@ -158,7 +180,6 @@ pub use error::*; } CErr::Success }).unwrap_or(CErr::Panic) - .into() } /// Convert a `Sink` into a `FILE*`. diff --git a/test.c b/test.c new file mode 100644 index 0000000..ede075a --- /dev/null +++ b/test.c @@ -0,0 +1,26 @@ +#include +#include +#include + +#include + +#define TRY(expr) do { if(CC20_ERR(res = (expr))) fprintf(stderr, "cc20 error %d: " #expr "\n", (int)res); goto fail; } while(0) + +int main(int argc, char** argv) +{ + cc20_meta_t meta; + cc20_result_t res; + + FILE* output = argv[1] ? fopen(argv[1], "wb") : stdout; + 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; } + + fprintf(output, "Hello world!"); + + res = CC20_ERR_NONE; + fail: + if(output) fclose(output); + return (int)res; +} diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..4d2880d --- /dev/null +++ b/test.sh @@ -0,0 +1,5 @@ +#!/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