macro_rules! auth_module (($auth_name:ident,
$verify_name:ident,
$keybytes:expr,
$tagbytes:expr) => (
use libc::c_ulonglong;
use crate::randombytes::randombytes_into;
pub const KEYBYTES: usize = $keybytes;
pub const TAGBYTES: usize = $tagbytes;
new_type! {
secret Key(KEYBYTES);
}
new_type! {
public Tag(TAGBYTES);
}
pub fn gen_key() -> Key {
let mut k = [0; KEYBYTES];
randombytes_into(&mut k);
Key(k)
}
pub fn authenticate(m: &[u8],
&Key(ref k): &Key) -> Tag {
unsafe {
let mut tag = [0; TAGBYTES];
let _todo_use_result = $auth_name(tag.as_mut_ptr(),
m.as_ptr(),
m.len() as c_ulonglong,
k.as_ptr());
Tag(tag)
}
}
pub fn verify(&Tag(ref tag): &Tag, m: &[u8],
&Key(ref k): &Key) -> bool {
unsafe {
$verify_name(tag.as_ptr(),
m.as_ptr(),
m.len() as c_ulonglong,
k.as_ptr()) == 0
}
}
#[cfg(test)]
mod test_m {
use super::*;
#[test]
fn test_auth_verify() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..256usize {
let k = gen_key();
let m = randombytes(i);
let tag = authenticate(&m, &k);
assert!(verify(&tag, &m, &k));
}
}
#[test]
fn test_auth_verify_tamper() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..32usize {
let k = gen_key();
let mut m = randombytes(i);
let Tag(mut tagbuf) = authenticate(&m, &k);
for j in 0..m.len() {
m[j] ^= 0x20;
assert!(!verify(&Tag(tagbuf), &m, &k));
m[j] ^= 0x20;
}
for j in 0..tagbuf.len() {
tagbuf[j] ^= 0x20;
assert!(!verify(&Tag(tagbuf), &m, &k));
tagbuf[j] ^= 0x20;
}
}
}
#[test]
fn test_serialisation() {
use crate::randombytes::randombytes;
use crate::test_utils::round_trip;
unwrap!(crate::init());
for i in 0..256usize {
let k = gen_key();
let m = randombytes(i);
let tag = authenticate(&m, &k);
round_trip(&k);
round_trip(&tag);
}
}
}
#[cfg(feature = "benchmarks")]
#[cfg(test)]
mod bench_m {
extern crate test;
use crate::randombytes::randombytes;
use super::*;
const BENCH_SIZES: [usize; 14] = [0, 1, 2, 4, 8, 16, 32, 64,
128, 256, 512, 1024, 2048, 4096];
#[bench]
fn bench_auth(b: &mut test::Bencher) {
unwrap!(crate::init());
let k = gen_key();
let ms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| {
randombytes(*s)
}).collect();
b.iter(|| {
for m in ms.iter() {
authenticate(&m, &k);
}
});
}
#[bench]
fn bench_verify(b: &mut test::Bencher) {
unwrap!(crate::init());
let k = gen_key();
let ms: Vec<Vec<u8>> = BENCH_SIZES.iter().map(|s| {
randombytes(*s)
}).collect();
let tags: Vec<Tag> = ms.iter().map(|m| {
authenticate(&m, &k)
}).collect();
b.iter(|| {
for (m, t) in ms.iter().zip(tags.iter()) {
verify(t, &m, &k);
}
});
}
}
));
#[allow(unused)]
macro_rules! auth_state (($state_name:ident,
$init_name:ident,
$update_name:ident,
$final_name:ident,
$tagbytes:expr) => (
use std::mem;
use crate::ffi;
#[must_use]
pub struct State($state_name);
impl Drop for State {
fn drop(&mut self) {
use libc::c_void;
let &mut State(ref mut s) = self;
unsafe {
let sp: *mut $state_name = s;
ffi::sodium_memzero(sp as *mut c_void, mem::size_of_val(s));
}
}
}
impl State {
pub fn init(k: &[u8]) -> State {
unsafe {
let mut s = mem::uninitialized();
let _todo_use_result = $init_name(&mut s, k.as_ptr(), k.len());
State(s)
}
}
pub fn update(&mut self, in_: &[u8]) {
unsafe {
let _ = $update_name(&mut self.0, in_.as_ptr(), in_.len() as c_ulonglong);
}
}
#[allow(trivial_numeric_casts)]
pub fn finalize(mut self) -> Tag {
unsafe {
let mut tag = [0; $tagbytes as usize];
let _ = $final_name(&mut self.0, tag.as_mut_ptr());
Tag(tag)
}
}
}
#[cfg(test)]
mod test_s {
use super::*;
#[test]
fn test_auth_eq_auth_state() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..256usize {
let k = gen_key();
let m = randombytes(i);
let tag = authenticate(&m, &k);
let mut state = State::init(&k[..]);
state.update(&m);
let tag2 = state.finalize();
assert_eq!(tag, tag2);
}
}
#[test]
fn test_auth_eq_auth_state_chunked() {
use crate::randombytes::randombytes;
unwrap!(crate::init());
for i in 0..256usize {
let k = gen_key();
let m = randombytes(i);
let tag = authenticate(&m, &k);
let mut state = State::init(&k[..]);
for c in m.chunks(1) {
state.update(c);
}
let tag2 = state.finalize();
assert_eq!(tag, tag2);
}
}
}
));