use nettle_sys::{
md5_ctx, nettle_hash, nettle_md5, nettle_md5_digest, nettle_md5_init,
nettle_md5_update, MD5_DIGEST_SIZE,
};
use std::default::Default;
use std::mem::zeroed;
use crate::hash::NettleHash;
use crate::hash::Hash;
pub struct Md5 {
context: md5_ctx,
}
impl_write_for_hash!(Md5);
impl Clone for Md5 {
fn clone(&self) -> Self {
use std::intrinsics::copy_nonoverlapping;
unsafe {
let mut ctx: md5_ctx = zeroed();
copy_nonoverlapping(&self.context, &mut ctx, 1);
Md5 { context: ctx }
}
}
}
impl Default for Md5 {
fn default() -> Self {
let mut ctx = unsafe { zeroed() };
unsafe {
nettle_md5_init(&mut ctx as *mut _);
}
Md5 { context: ctx }
}
}
impl Hash for Md5 {
fn digest_size(&self) -> usize {
MD5_DIGEST_SIZE as usize
}
fn update(&mut self, data: &[u8]) {
unsafe {
nettle_md5_update(
&mut self.context as *mut _,
data.len(),
data.as_ptr(),
);
}
}
fn digest(&mut self, digest: &mut [u8]) {
unsafe {
nettle_md5_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 Md5 {
type Context = md5_ctx;
unsafe fn nettle_hash() -> &'static nettle_hash {
&nettle_md5
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn do_nothing() {
let _ = Md5::default();
}
#[test]
fn rfc_1321() {
let mut ctx = Md5::default();
let mut digest = vec![0u8; ctx.digest_size()];
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04\xe9\x80\x09\x98\xec\xf8\x42\x7e"
);
ctx.update(b"a");
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8\x31\xc3\x99\xe2\x69\x77\x26\x61"
);
ctx.update(b"abc");
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\x90\x01\x50\x98\x3c\xd2\x4f\xb0\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
);
ctx.update(b"message digest");
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
);
ctx.update(b"abcdefghijklmnopqrstuvwxyz");
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\xc3\xfc\xd3\xd7\x61\x92\xe4\x00\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
);
ctx.update(
b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
);
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\xd1\x74\xab\x98\xd2\x77\xd9\xf5\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
);
ctx.update(b"12345678901234567890123456789012345678901234567890123456789012345678901234567890");
ctx.digest(&mut digest);
assert_eq!(
digest,
b"\x57\xed\xf4\xa2\x2b\xe3\xc9\x55\xac\x49\xda\x2e\x21\x07\xb6\x7a"
);
}
}