nettle 3.0.0

Rust bindings for the Nettle cryptographic library
use nettle_sys::{
    md2_ctx,
    nettle_md2_init,
    nettle_md2_digest,
    nettle_md2_update,
    nettle_hash,
    nettle_md2,
    MD2_DIGEST_SIZE,
};
use std::default::Default;
use std::mem::zeroed;
use Hash;
use hash::NettleHash;

/// Message-Digest Algorithm 2 (MD2) defined in RFC 1319.
/// # Note
/// MD2 is no longer considered a secure cryptographic hash function. Only use it for legacy
/// applications.
pub struct Md2 {
    context: md2_ctx,
}

impl_write_for_hash!(Md2);

impl Clone for Md2 {
    fn clone(&self) -> Self {
        use std::intrinsics::copy_nonoverlapping;

        unsafe {
            let mut ctx: md2_ctx = zeroed();
            copy_nonoverlapping(&self.context, &mut ctx, 1);

            Md2{ context: ctx }
        }
    }
}

impl Default for Md2 {
    fn default() -> Self {
        let mut ctx = unsafe { zeroed() };

        unsafe { nettle_md2_init(&mut ctx as *mut _); }

        Md2{ context: ctx }
    }
}

impl Hash for Md2 {
    fn digest_size(&self) -> usize { MD2_DIGEST_SIZE as usize }

    fn update(&mut self, data: &[u8]) {
        unsafe {
            nettle_md2_update(&mut self.context as *mut _, data.len(), data.as_ptr());
        }
    }

    fn digest(&mut self, digest: &mut [u8]) {
        unsafe {
            nettle_md2_digest(&mut self.context as *mut _, digest.len(), digest.as_mut_ptr());
        }
    }

    fn box_clone(&self) -> Box<Hash> {
        Box::new(self.clone())
    }
}

impl NettleHash for Md2 {
    type Context = md2_ctx;

    unsafe fn nettle_hash() -> &'static nettle_hash { &nettle_md2 }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn do_nothing() {
        let _ = Md2::default();
    }

    #[test]
    fn rfc_1319() {
        let mut ctx = Md2::default();
        let mut digest = vec![0u8; ctx.digest_size()];

        ctx.digest(&mut digest);
        assert_eq!(digest, b"\x83\x50\xe5\xa3\xe2\x4c\x15\x3d\xf2\x27\x5c\x9f\x80\x69\x27\x73");

        ctx.update(b"a");
        ctx.digest(&mut digest);
        assert_eq!(digest, b"\x32\xec\x01\xec\x4a\x6d\xac\x72\xc0\xab\x96\xfb\x34\xc0\xb5\xd1");

        ctx.update(b"abc");
        ctx.digest(&mut digest);
        assert_eq!(digest, b"\xda\x85\x3b\x0d\x3f\x88\xd9\x9b\x30\x28\x3a\x69\xe6\xde\xd6\xbb");

        ctx.update(b"message digest");
        ctx.digest(&mut digest);
        assert_eq!(digest, b"\xab\x4f\x49\x6b\xfb\x2a\x53\x0b\x21\x9f\xf3\x30\x31\xfe\x06\xb0");

        ctx.update(b"abcdefghijklmnopqrstuvwxyz");
        ctx.digest(&mut digest);
        assert_eq!(digest, b"\x4e\x8d\xdf\xf3\x65\x02\x92\xab\x5a\x41\x08\xc3\xaa\x47\x94\x0b");

        ctx.update(b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
        ctx.digest(&mut digest);
        assert_eq!(digest, b"\xda\x33\xde\xf2\xa4\x2d\xf1\x39\x75\x35\x28\x46\xc3\x03\x38\xcd");

        ctx.update(b"12345678901234567890123456789012345678901234567890123456789012345678901234567890");
        ctx.digest(&mut digest);
        assert_eq!(digest, b"\xd5\x97\x6f\x79\xd8\x3d\x3a\x0d\xc9\x80\x6c\x3c\x66\xf3\xef\xd8");
    }
}