use subtle::ConstantTimeEq;
use crate::constants::{
CRYPTO_ONETIMEAUTH_BYTES, CRYPTO_ONETIMEAUTH_KEYBYTES, CRYPTO_ONETIMEAUTH_POLY1305_BYTES,
CRYPTO_ONETIMEAUTH_POLY1305_KEYBYTES,
};
use crate::error::Error;
use crate::poly1305::Poly1305;
use crate::types::*;
struct OnetimeauthPoly1305State {
mac: Poly1305,
}
pub type Key = [u8; CRYPTO_ONETIMEAUTH_POLY1305_KEYBYTES];
pub type Mac = [u8; CRYPTO_ONETIMEAUTH_POLY1305_BYTES];
fn crypto_onetimeauth_poly1305(output: &mut Mac, message: &[u8], key: &Key) {
let mut poly1305 = Poly1305::new(key);
poly1305.update(message);
poly1305.finalize(output)
}
fn crypto_onetimeauth_poly1305_verify(mac: &Mac, input: &[u8], key: &Key) -> Result<(), Error> {
let mut poly1305 = Poly1305::new(key);
poly1305.update(input);
let computed_mac = poly1305.finalize_to_array();
if mac.ct_eq(&computed_mac).unwrap_u8() == 1 {
Ok(())
} else {
Err(dryoc_error!("authentication codes do not match"))
}
}
fn crypto_onetimeauth_poly1305_init(key: &Key) -> OnetimeauthPoly1305State {
OnetimeauthPoly1305State {
mac: Poly1305::new(key),
}
}
fn crypto_onetimeauth_poly1305_update(state: &mut OnetimeauthPoly1305State, input: &[u8]) {
state.mac.update(input)
}
fn crypto_onetimeauth_poly1305_final(
mut state: OnetimeauthPoly1305State,
output: &mut [u8; CRYPTO_ONETIMEAUTH_POLY1305_BYTES],
) {
state.mac.finalize(output)
}
pub fn crypto_onetimeauth(mac: &mut Mac, message: &[u8], key: &Key) {
crypto_onetimeauth_poly1305(mac, message, key)
}
pub fn crypto_onetimeauth_verify(mac: &Mac, input: &[u8], key: &Key) -> Result<(), Error> {
crypto_onetimeauth_poly1305_verify(mac, input, key)
}
pub struct OnetimeauthState {
state: OnetimeauthPoly1305State,
}
pub fn crypto_onetimeauth_keygen() -> Key {
Key::gen()
}
pub fn crypto_onetimeauth_init(key: &[u8; CRYPTO_ONETIMEAUTH_KEYBYTES]) -> OnetimeauthState {
OnetimeauthState {
state: crypto_onetimeauth_poly1305_init(key),
}
}
pub fn crypto_onetimeauth_update(state: &mut OnetimeauthState, input: &[u8]) {
crypto_onetimeauth_poly1305_update(&mut state.state, input)
}
pub fn crypto_onetimeauth_final(
state: OnetimeauthState,
output: &mut [u8; CRYPTO_ONETIMEAUTH_BYTES],
) {
crypto_onetimeauth_poly1305_final(state.state, output)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_onetimeauth() {
use sodiumoxide::crypto::onetimeauth;
use crate::rng::copy_randombytes;
for _ in 0..20 {
let mut key = [0u8; 32];
copy_randombytes(&mut key);
let mut input = [0u8; 1024];
copy_randombytes(&mut input);
let so_mac = onetimeauth::authenticate(
&input,
&onetimeauth::poly1305::Key::from_slice(&key).expect("so key failed"),
);
let mut mac = [0u8; CRYPTO_ONETIMEAUTH_BYTES];
crypto_onetimeauth(&mut mac, &input, &key);
assert_eq!(so_mac.0, mac);
crypto_onetimeauth_verify(&mac, &input, &key).expect("verify failed");
}
}
#[test]
fn test_onetimeauth_incremental() {
use sodiumoxide::crypto::onetimeauth;
use crate::rng::copy_randombytes;
for _ in 0..20 {
let mut key = [0u8; 32];
copy_randombytes(&mut key);
let mut input = [0u8; 1024];
copy_randombytes(&mut input);
let so_mac = onetimeauth::authenticate(
&input,
&onetimeauth::poly1305::Key::from_slice(&key).expect("so key failed"),
);
let mut mac = [0u8; CRYPTO_ONETIMEAUTH_BYTES];
let mut state = crypto_onetimeauth_init(&key);
crypto_onetimeauth_update(&mut state, &input);
crypto_onetimeauth_final(state, &mut mac);
assert_eq!(so_mac.0, mac);
crypto_onetimeauth_verify(&mac, &input, &key).expect("verify failed");
}
}
}