#![cfg_attr(docsrs, doc(cfg(feature = "safe_api")))]
pub use super::hltypes::SecretKey;
pub use crate::hazardous::mac::blake2b::Tag;
use crate::{
errors::UnknownCryptoError,
hazardous::mac::blake2b::{self, Blake2b},
};
const BLAKE2B_TAG_SIZE: usize = 32;
const BLAKE2B_MIN_KEY_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() < BLAKE2B_MIN_KEY_SIZE {
return Err(UnknownCryptoError);
}
let blake2b_secret_key = blake2b::SecretKey::from_slice(secret_key.unprotected_as_bytes())?;
let mut state = Blake2b::new(&blake2b_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() < BLAKE2B_MIN_KEY_SIZE || expected.len() != BLAKE2B_TAG_SIZE {
return Err(UnknownCryptoError);
}
let key = blake2b::SecretKey::from_slice(secret_key.unprotected_as_bytes())?;
Blake2b::verify(expected, &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(64).unwrap();
let sec_key_false = SecretKey::default();
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(64).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::generate(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::generate(31).unwrap();
let msg = "what do ya want for nothing?".as_bytes().to_vec();
let mac = Tag::from_slice(&[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::default();
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::default();
let sk2 = SecretKey::default();
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::default();
let tag = authenticate(&sk, &input[..]).unwrap();
authenticate_verify(&tag, &sk, b"Completely wrong input").is_err()
}
use crate::hazardous::hash::blake2::blake2b_core::BLAKE2B_KEYSIZE;
#[quickcheck]
#[cfg(feature = "safe_api")]
fn prop_authenticate_key_size(input: Vec<u8>) -> bool {
let sec_key_res = SecretKey::from_slice(&input);
if input.is_empty() || input.len() >= u32::MAX as usize {
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() >= BLAKE2B_MIN_KEY_SIZE && input.len() <= BLAKE2B_KEYSIZE {
auth_res.is_ok()
} else {
auth_res.is_err()
}
}
}