/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 | | } |