1use crate::constants::{
56 CRYPTO_ONETIMEAUTH_BYTES, CRYPTO_ONETIMEAUTH_KEYBYTES, CRYPTO_ONETIMEAUTH_POLY1305_BYTES,
57 CRYPTO_ONETIMEAUTH_POLY1305_KEYBYTES,
58};
59use crate::error::Error;
60use crate::poly1305::Poly1305;
61use crate::types::*;
62use crate::utils::{verify_ct, zeroize_bytes};
63struct OnetimeauthPoly1305State {
64 mac: Poly1305,
65}
66
67pub type Key = [u8; CRYPTO_ONETIMEAUTH_POLY1305_KEYBYTES];
69pub type Mac = [u8; CRYPTO_ONETIMEAUTH_POLY1305_BYTES];
71
72fn crypto_onetimeauth_poly1305(output: &mut Mac, message: &[u8], key: &Key) {
73 let mut poly1305 = Poly1305::new(key);
74 poly1305.update(message);
75 poly1305.finalize(output)
76}
77fn crypto_onetimeauth_poly1305_verify(mac: &Mac, input: &[u8], key: &Key) -> Result<(), Error> {
78 let mut poly1305 = Poly1305::new(key);
79 poly1305.update(input);
80 let mut computed_mac = Mac::default();
83 poly1305.finalize(&mut computed_mac);
84
85 let verified = verify_ct(mac, &computed_mac);
86 zeroize_bytes(&mut computed_mac);
87 verified
88}
89
90fn crypto_onetimeauth_poly1305_init(key: &Key) -> OnetimeauthPoly1305State {
91 OnetimeauthPoly1305State {
92 mac: Poly1305::new(key),
93 }
94}
95
96fn crypto_onetimeauth_poly1305_update(state: &mut OnetimeauthPoly1305State, input: &[u8]) {
97 state.mac.update(input)
98}
99fn crypto_onetimeauth_poly1305_final(
100 mut state: OnetimeauthPoly1305State,
101 output: &mut [u8; CRYPTO_ONETIMEAUTH_POLY1305_BYTES],
102) {
103 state.mac.finalize(output)
104}
105
106pub fn crypto_onetimeauth(mac: &mut Mac, message: &[u8], key: &Key) {
111 crypto_onetimeauth_poly1305(mac, message, key)
112}
113
114pub fn crypto_onetimeauth_verify(mac: &Mac, input: &[u8], key: &Key) -> Result<(), Error> {
123 crypto_onetimeauth_poly1305_verify(mac, input, key)
124}
125
126pub struct OnetimeauthState {
128 state: OnetimeauthPoly1305State,
129}
130
131#[must_use]
138pub fn crypto_onetimeauth_keygen() -> Key {
139 Key::generate()
140}
141
142#[must_use]
151pub fn crypto_onetimeauth_init(key: &[u8; CRYPTO_ONETIMEAUTH_KEYBYTES]) -> OnetimeauthState {
152 OnetimeauthState {
153 state: crypto_onetimeauth_poly1305_init(key),
154 }
155}
156
157pub fn crypto_onetimeauth_update(state: &mut OnetimeauthState, input: &[u8]) {
161 crypto_onetimeauth_poly1305_update(&mut state.state, input)
162}
163
164pub fn crypto_onetimeauth_final(
169 state: OnetimeauthState,
170 output: &mut [u8; CRYPTO_ONETIMEAUTH_BYTES],
171) {
172 crypto_onetimeauth_poly1305_final(state.state, output)
173}
174
175#[cfg(test)]
176mod tests {
177 use super::*;
178 use crate::test_prelude::*;
179
180 const RFC_KEY: Key = [
182 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, 0x06,
183 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf, 0x41, 0x49,
184 0xf5, 0x1b,
185 ];
186 const RFC_MESSAGE: &[u8] = b"Cryptographic Forum Research Group";
187 const RFC_TAG: Mac = [
188 0xa8, 0x06, 0x1d, 0xc1, 0x30, 0x51, 0x36, 0xc6, 0xc2, 0x2b, 0x8b, 0xaf, 0x0c, 0x01, 0x27,
189 0xa9,
190 ];
191
192 const SPLITS: [usize; 8] = [0, 1, 15, 16, 17, 31, 32, 33];
195
196 fn incremental(key: &Key, chunks: &[&[u8]]) -> Mac {
197 let mut state = crypto_onetimeauth_init(key);
198 for chunk in chunks {
199 crypto_onetimeauth_update(&mut state, chunk);
200 }
201 let mut mac = Mac::default();
202 crypto_onetimeauth_final(state, &mut mac);
203 mac
204 }
205
206 #[test]
210 fn test_rfc8439_vector_one_shot_and_incremental() {
211 let mut mac = Mac::default();
212 crypto_onetimeauth(&mut mac, RFC_MESSAGE, &RFC_KEY);
213 assert_eq!(mac, RFC_TAG);
214 crypto_onetimeauth_verify(&RFC_TAG, RFC_MESSAGE, &RFC_KEY).expect("verify");
215
216 for split in SPLITS {
217 let (head, rest) = RFC_MESSAGE.split_at(split);
218 assert_eq!(
219 incremental(&RFC_KEY, &[head, rest]),
220 RFC_TAG,
221 "split {split}"
222 );
223 }
224
225 let mut chunks = Vec::new();
226 let mut cuts = SPLITS.to_vec();
227 cuts.push(RFC_MESSAGE.len());
228 for window in cuts.windows(2) {
229 chunks.push(&RFC_MESSAGE[window[0]..window[1]]);
230 }
231 assert_eq!(incremental(&RFC_KEY, &[&[][..], RFC_MESSAGE]), RFC_TAG);
232 assert_eq!(incremental(&RFC_KEY, &chunks), RFC_TAG);
233 }
234
235 #[test]
238 fn test_verify_rejects_mutations() {
239 for index in 0..CRYPTO_ONETIMEAUTH_BYTES {
240 let mut mac = RFC_TAG;
241 mac[index] ^= 1;
242 assert!(
243 matches!(
244 crypto_onetimeauth_verify(&mac, RFC_MESSAGE, &RFC_KEY),
245 Err(Error::AuthenticationFailed)
246 ),
247 "tag byte {index}"
248 );
249 }
250
251 let mut message = RFC_MESSAGE.to_vec();
252 *message.last_mut().unwrap() ^= 1;
253 assert!(matches!(
254 crypto_onetimeauth_verify(&RFC_TAG, &message, &RFC_KEY),
255 Err(Error::AuthenticationFailed)
256 ));
257 assert!(matches!(
258 crypto_onetimeauth_verify(&RFC_TAG, &RFC_MESSAGE[..RFC_MESSAGE.len() - 1], &RFC_KEY),
259 Err(Error::AuthenticationFailed)
260 ));
261
262 let mut key = RFC_KEY;
263 key[31] ^= 1;
264 assert!(matches!(
265 crypto_onetimeauth_verify(&RFC_TAG, RFC_MESSAGE, &key),
266 Err(Error::AuthenticationFailed)
267 ));
268 }
269
270 #[cfg(dryoc_native_tests)]
274 #[test]
275 fn test_matches_libsodium_at_block_boundaries() {
276 use crate::utils::test_util::XorShift64;
277
278 crate::native_test_util::init();
279
280 let mut rng = XorShift64::new(0x0a3e_71c9_5b2d_f804);
281 for len in [0usize, 1, 15, 16, 17, 31, 32, 33, 1023, 1024, 1025] {
282 let key: Key = rng.next_bytes32();
283 let message: Vec<u8> = (0..len.div_ceil(8))
284 .flat_map(|_| rng.next_u64().to_le_bytes())
285 .take(len)
286 .collect();
287 let mut expected = Mac::default();
288 let rc = unsafe {
292 libsodium_sys::crypto_onetimeauth(
293 expected.as_mut_ptr(),
294 message.as_ptr(),
295 len as libc::c_ulonglong,
296 key.as_ptr(),
297 )
298 };
299 assert_eq!(rc, 0);
300
301 let mut mac = Mac::default();
302 crypto_onetimeauth(&mut mac, &message, &key);
303 assert_eq!(mac, expected, "len {len}");
304 crypto_onetimeauth_verify(&expected, &message, &key).expect("verify");
305 for split in SPLITS.into_iter().filter(|&split| split <= len) {
306 let (head, rest) = message.split_at(split);
307 assert_eq!(
308 incremental(&key, &[head, rest]),
309 expected,
310 "len {len}, split {split}"
311 );
312 }
313 }
314 }
315}