use nettle_sys::{
md2_ctx, nettle_hash, nettle_md2, nettle_md2_digest, nettle_md2_init,
nettle_md2_update, MD2_DIGEST_SIZE,
};
use std::default::Default;
use std::mem::zeroed;
use crate::hash::NettleHash;
use crate::hash::Hash;
pub struct Md2 {
context: md2_ctx,
}
impl_write_for_hash!(Md2);
impl Clone for Md2 {
fn clone(&self) -> Self {
use std::ptr::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<dyn 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"
);
}
#[test]
fn clone() {
let mut ctx = Md2::default();
ctx.update(b"\xcf");
let mut ctx2 = ctx.clone();
ctx.update(b"\x00");
ctx2.update(b"\x00");
let mut digest = vec![0u8; ctx.digest_size()];
ctx.digest(&mut digest);
let mut digest2 = vec![0u8; ctx2.digest_size()];
ctx2.digest(&mut digest2);
assert_eq!(digest, digest2);
}
}