Coverage Report

Created: 2025-10-29 07:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/aws-lc-rs-1.12.4/src/aead/poly1305.rs
Line
Count
Source
1
// Copyright 2015-2016 Brian Smith.
2
// SPDX-License-Identifier: ISC
3
// Modifications copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
4
// SPDX-License-Identifier: Apache-2.0 OR ISC
5
6
// TODO: enforce maximum input length.
7
8
use super::{Tag, TAG_LEN};
9
use crate::aws_lc::{CRYPTO_poly1305_finish, CRYPTO_poly1305_init, CRYPTO_poly1305_update};
10
use crate::cipher::block::BLOCK_LEN;
11
use core::mem::MaybeUninit;
12
13
/// A Poly1305 key.
14
pub(super) struct Key {
15
    pub(super) key_and_nonce: [u8; KEY_LEN],
16
}
17
18
const KEY_LEN: usize = 2 * BLOCK_LEN;
19
20
impl Key {
21
    #[inline]
22
    #[allow(dead_code)]
23
0
    pub(super) fn new(key_and_nonce: [u8; KEY_LEN]) -> Self {
24
0
        Self { key_and_nonce }
25
0
    }
26
}
27
28
pub struct Context {
29
    state: poly1305_state,
30
}
31
32
// Keep in sync with `poly1305_state` in GFp/poly1305.h.
33
//
34
// The C code, in particular the way the `poly1305_aligned_state` functions
35
// are used, is only correct when the state buffer is 64-byte aligned.
36
#[repr(C, align(64))]
37
#[allow(non_camel_case_types)]
38
struct poly1305_state(aws_lc::poly1305_state);
39
40
impl Context {
41
    #[inline]
42
0
    pub(super) fn from_key(Key { key_and_nonce }: Key) -> Self {
43
        unsafe {
44
0
            let mut state = MaybeUninit::<poly1305_state>::uninit();
45
0
            CRYPTO_poly1305_init(state.as_mut_ptr().cast(), key_and_nonce.as_ptr());
46
0
            Self {
47
0
                state: state.assume_init(),
48
0
            }
49
        }
50
0
    }
51
52
    #[inline]
53
0
    pub fn update(&mut self, input: &[u8]) {
54
0
        unsafe {
55
0
            CRYPTO_poly1305_update(
56
0
                self.state.0.as_mut_ptr().cast(),
57
0
                input.as_ptr(),
58
0
                input.len(),
59
0
            );
60
0
        }
61
0
    }
62
63
    #[inline]
64
0
    pub(super) fn finish(mut self) -> Tag {
65
        unsafe {
66
0
            let mut tag = MaybeUninit::<[u8; TAG_LEN]>::uninit();
67
0
            CRYPTO_poly1305_finish(self.state.0.as_mut_ptr().cast(), tag.as_mut_ptr().cast());
68
0
            crate::fips::set_fips_service_status_unapproved();
69
0
            Tag(tag.assume_init(), TAG_LEN)
70
        }
71
0
    }
72
}
73
74
/// Implements the original, non-IETF padding semantics.
75
///
76
/// This is used by `chacha20_poly1305_openssh` and the standalone
77
/// poly1305 test vectors.
78
#[inline]
79
0
pub(super) fn sign(key: Key, input: &[u8]) -> Tag {
80
0
    let mut ctx = Context::from_key(key);
81
0
    ctx.update(input);
82
0
    ctx.finish()
83
0
}
84
85
#[cfg(test)]
86
mod tests {
87
    use super::*;
88
    use crate::{test, test_file};
89
90
    // Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc.
91
    #[test]
92
    pub fn test_poly1305() {
93
        test::run(
94
            test_file!("data/poly1305_test.txt"),
95
            |section, test_case| {
96
                assert_eq!(section, "");
97
                let key = test_case.consume_bytes("Key");
98
                let key: &[u8; BLOCK_LEN * 2] = key.as_slice().try_into().unwrap();
99
                let input = test_case.consume_bytes("Input");
100
                let expected_mac = test_case.consume_bytes("MAC");
101
                let key = Key::new(*key);
102
                let Tag(actual_mac, _) = sign(key, &input);
103
                assert_eq!(expected_mac, actual_mac.as_ref());
104
105
                Ok(())
106
            },
107
        );
108
    }
109
}