#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
pub use crate::hazardous::mac::blake2b::SecretKey;
pub use crate::hazardous::mac::blake2b::Tag;
use crate::{errors::UnknownCryptoError, hazardous::mac::blake2b::Blake2b};
const BLAKE2B_TAG_SIZE: usize = 32;
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn authenticate(secret_key: &SecretKey, data: &[u8]) -> Result<Tag, UnknownCryptoError> {
if secret_key.len() < 32 {
return Err(UnknownCryptoError);
}
let mut state = Blake2b::new(secret_key, BLAKE2B_TAG_SIZE)?;
state.update(data)?;
state.finalize()
}
#[must_use = "SECURITY WARNING: Ignoring a Result can have real security implications."]
pub fn authenticate_verify(
expected: &Tag,
secret_key: &SecretKey,
data: &[u8],
) -> Result<(), UnknownCryptoError> {
if secret_key.len() < 32 || expected.len() != BLAKE2B_TAG_SIZE {
return Err(UnknownCryptoError);
}
Blake2b::verify(expected, secret_key, BLAKE2B_TAG_SIZE, data)
}
#[cfg(test)]
mod public {
use super::*;
mod test_auth_and_verify {
use super::*;
#[test]
fn test_authenticate_verify_bad_key() {
let sec_key_correct = SecretKey::generate().unwrap();
let sec_key_false = SecretKey::generate().unwrap();
let msg = "what do ya want for nothing?".as_bytes().to_vec();
let mac_bob = authenticate(&sec_key_correct, &msg).unwrap();
assert!(authenticate_verify(&mac_bob, &sec_key_correct, &msg).is_ok());
assert!(authenticate_verify(&mac_bob, &sec_key_false, &msg).is_err());
}
#[test]
fn test_authenticate_verify_bad_msg() {
let sec_key = SecretKey::generate().unwrap();
let msg = "what do ya want for nothing?".as_bytes().to_vec();
let mac_bob = authenticate(&sec_key, &msg).unwrap();
assert!(authenticate_verify(&mac_bob, &sec_key, &msg).is_ok());
assert!(authenticate_verify(&mac_bob, &sec_key, b"bad msg").is_err());
}
#[test]
fn test_authenticate_key_too_small() {
let sec_key = SecretKey::try_from(&[0u8; 31]).unwrap();
let msg = "what do ya want for nothing?".as_bytes().to_vec();
assert!(authenticate(&sec_key, &msg).is_err());
}
#[test]
fn test_authenticate_verify_key_too_small() {
let sec_key = SecretKey::try_from(&[0u8; 31]).unwrap();
let msg = "what do ya want for nothing?".as_bytes().to_vec();
let mac = Tag::try_from(&[0u8; 32]).unwrap();
assert!(authenticate_verify(&mac, &sec_key, &msg).is_err());
}
}
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_authenticate_verify(input: Vec<u8>) -> bool {
let sk = SecretKey::generate().unwrap();
let tag = authenticate(&sk, &input[..]).unwrap();
authenticate_verify(&tag, &sk, &input[..]).is_ok()
}
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_verify_fail_diff_key(input: Vec<u8>) -> bool {
let sk = SecretKey::generate().unwrap();
let sk2 = SecretKey::generate().unwrap();
let tag = authenticate(&sk, &input[..]).unwrap();
authenticate_verify(&tag, &sk2, &input[..]).is_err()
}
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_verify_fail_diff_input(input: Vec<u8>) -> bool {
let sk = SecretKey::generate().unwrap();
let tag = authenticate(&sk, &input[..]).unwrap();
authenticate_verify(&tag, &sk, b"Completely wrong input").is_err()
}
use crate::hazardous::hash::blake2::blake2b::BLAKE2B_MAX_KEYSIZE;
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_authenticate_key_size(input: Vec<u8>) -> bool {
let sec_key_res = SecretKey::try_from(&input);
if input.is_empty() || input.len() > BLAKE2B_MAX_KEYSIZE {
return sec_key_res.is_err();
}
let sec_key = sec_key_res.unwrap();
let msg = "what do ya want for nothing?".as_bytes().to_vec();
let auth_res = authenticate(&sec_key, &msg);
if input.len() >= 32 && input.len() <= BLAKE2B_MAX_KEYSIZE {
auth_res.is_ok()
} else {
auth_res.is_err()
}
}
}