common-crypto 0.3.0

Bindings to Apple's Common Crypto library
Documentation
use std::ffi::c_void;

pub struct Hash;

macro_rules! implement_hash {
    ($func:ident, $struct:ident, $ctx:ident, $one_shot:ident, $init:ident, $update:ident, $final:ident, $len:expr) => {
        extern "C" {
            fn $one_shot(data: *const c_void, len: i32, output: *mut u8) -> *mut u8;
            fn $init(ctx: *mut $ctx) -> i32;
            fn $update(ctx: *mut $ctx, data: *const c_void, len: i32) -> i32;
            fn $final(output: *mut c_void, ctx: *mut $ctx) -> i32;
        }

        impl Hash {
            pub fn $func(data: impl AsRef<[u8]>) -> [u8; $len] {
                let mut output = [0u8; $len];

                unsafe {
                    $one_shot(
                        data.as_ref().as_ptr() as *const c_void,
                        data.as_ref().len() as i32,
                        output.as_mut_ptr(),
                    );
                }

                output
            }
        }

        pub struct $struct {
            ctx: $ctx,
        }

        impl $struct {
            pub fn new() -> Self {
                let mut ctx = $ctx::default();

                unsafe {
                    $init(&mut ctx);
                }

                Self { ctx }
            }

            pub fn update(&mut self, data: impl AsRef<[u8]>) {
                unsafe {
                    $update(
                        &mut self.ctx,
                        data.as_ref().as_ptr() as *const c_void,
                        data.as_ref().len() as i32,
                    );
                }
            }

            pub fn finish(mut self) -> [u8; $len] {
                let mut output = [0u8; $len];
                unsafe { $final(output.as_mut_ptr() as *mut c_void, &mut self.ctx) };
                output
            }
        }
    };
}

#[repr(C)]
#[derive(Default)]
struct SHA1Context {
    h0: u32,
    h1: u32,
    h2: u32,
    h3: u32,
    h4: u32,
    nl: u32,
    nh: u32,
    data: [u32; 16],
    num: i32,
}
implement_hash!(
    sha1,
    SHA1,
    SHA1Context,
    CC_SHA1,
    CC_SHA1_Init,
    CC_SHA1_Update,
    CC_SHA1_Final,
    20
);

#[repr(C)]
#[derive(Default)]
struct SHA256Context {
    count: [u32; 2],
    hash: [u32; 8],
    wbuf: [u32; 16],
}

implement_hash!(
    sha224,
    SHA224,
    SHA256Context,
    CC_SHA224,
    CC_SHA224_Init,
    CC_SHA224_Update,
    CC_SHA224_Final,
    28
);

implement_hash!(
    sha256,
    SHA256,
    SHA256Context,
    CC_SHA256,
    CC_SHA256_Init,
    CC_SHA256_Update,
    CC_SHA256_Final,
    32
);

#[repr(C)]
#[derive(Default)]
struct SHA512Context {
    count: [u64; 2],
    hash: [u64; 8],
    wbuf: [u64; 16],
}

implement_hash!(
    sha384,
    SHA384,
    SHA512Context,
    CC_SHA384,
    CC_SHA384_Init,
    CC_SHA384_Update,
    CC_SHA384_Final,
    48
);

implement_hash!(
    sha512,
    SHA512,
    SHA512Context,
    CC_SHA512,
    CC_SHA512_Init,
    CC_SHA512_Update,
    CC_SHA512_Final,
    64
);

#[repr(C)]
#[derive(Default)]
struct MD2Context {
    num: i32,
    data: [u8; 16],
    cksm: [u32; 16],
    state: [u32; 16],
}

implement_hash!(
    md2,
    MD2,
    MD2Context,
    CC_MD2,
    CC_MD2_Init,
    CC_MD2_Update,
    CC_MD2_Final,
    16
);

#[repr(C)]
#[derive(Default)]
struct MD4Context {
    a: u32,
    b: u32,
    c: u32,
    d: u32,
    nl: u32,
    nh: u32,
    data: [u32; 16],
    num: i32,
}

implement_hash!(
    md4,
    MD4,
    MD4Context,
    CC_MD4,
    CC_MD4_Init,
    CC_MD4_Update,
    CC_MD4_Final,
    16
);

#[repr(C)]
#[derive(Default)]
struct MD5Context {
    a: u32,
    b: u32,
    c: u32,
    d: u32,
    nl: u32,
    nh: u32,
    data: [u32; 16],
    num: i32,
}

implement_hash!(
    md5,
    MD5,
    MD5Context,
    CC_MD5,
    CC_MD5_Init,
    CC_MD5_Update,
    CC_MD5_Final,
    16
);