1 | // Copyright 2018 Brian Smith. |
2 | // |
3 | // Permission to use, copy, modify, and/or distribute this software for any |
4 | // purpose with or without fee is hereby granted, provided that the above |
5 | // copyright notice and this permission notice appear in all copies. |
6 | // |
7 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES |
8 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
9 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY |
10 | // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
11 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION |
12 | // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
13 | // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
14 | |
15 | use crate::{ |
16 | constant_time, |
17 | polyfill::{slice::AsChunks, ArraySplitMap}, |
18 | }; |
19 | |
20 | pub(in super::super) const BLOCK_LEN: usize = 16; |
21 | pub(in super::super) type Block = [u8; BLOCK_LEN]; |
22 | pub(super) const ZERO_BLOCK: Block = [0u8; BLOCK_LEN]; |
23 | |
24 | #[cfg (any( |
25 | all(target_arch = "aarch64" , target_endian = "little" ), |
26 | all(target_arch = "arm" , target_endian = "little" ), |
27 | target_arch = "x86" , |
28 | target_arch = "x86_64" |
29 | ))] |
30 | macro_rules! htable_new { |
31 | ( $name:ident, $value:expr $(,)? ) => {{ |
32 | use crate::aead::gcm::ffi::HTable; |
33 | prefixed_extern! { |
34 | fn $name(HTable: &mut HTable, h: &[u64; 2]); |
35 | } |
36 | HTable::new($name, $value) |
37 | }}; |
38 | } |
39 | |
40 | /// SAFETY: |
41 | /// * The function `$name` must meet the contract of the `f` paramweter of |
42 | /// `ghash()`. |
43 | #[cfg (any( |
44 | all(target_arch = "aarch64" , target_endian = "little" ), |
45 | all(target_arch = "arm" , target_endian = "little" ), |
46 | target_arch = "x86" , |
47 | target_arch = "x86_64" |
48 | ))] |
49 | macro_rules! ghash { |
50 | ( $name:ident, $xi:expr, $h_table:expr, $input:expr $(,)? ) => {{ |
51 | use crate::aead::gcm::ffi::{HTable, Xi}; |
52 | prefixed_extern! { |
53 | fn $name( |
54 | xi: &mut Xi, |
55 | Htable: &HTable, |
56 | inp: *const u8, |
57 | len: crate::c::NonZero_size_t, |
58 | ); |
59 | } |
60 | $h_table.ghash($name, $xi, $input) |
61 | }}; |
62 | } |
63 | |
64 | pub(in super::super) struct KeyValue([u64; 2]); |
65 | |
66 | impl KeyValue { |
67 | pub(in super::super) fn new(value: Block) -> Self { |
68 | Self(value.array_split_map(u64::from_be_bytes)) |
69 | } |
70 | |
71 | pub(super) fn into_inner(self) -> [u64; 2] { |
72 | self.0 |
73 | } |
74 | } |
75 | |
76 | /// SAFETY: |
77 | /// * `f` must read `len` bytes from `inp`; it may assume |
78 | /// that `len` is a (non-zero) multiple of `BLOCK_LEN`. |
79 | /// * `f` may inspect CPU features. |
80 | #[cfg (any( |
81 | all(target_arch = "aarch64" , target_endian = "little" ), |
82 | all(target_arch = "arm" , target_endian = "little" ), |
83 | target_arch = "x86" , |
84 | target_arch = "x86_64" |
85 | ))] |
86 | impl HTable { |
87 | pub(super) unsafe fn new( |
88 | init: unsafe extern "C" fn(HTable: &mut HTable, &[u64; 2]), |
89 | value: KeyValue, |
90 | ) -> Self { |
91 | let mut r = Self { |
92 | Htable: [U128 { hi: 0, lo: 0 }; HTABLE_LEN], |
93 | }; |
94 | unsafe { init(&mut r, &value.0) }; |
95 | r |
96 | } |
97 | |
98 | #[cfg (any( |
99 | all(target_arch = "aarch64" , target_endian = "little" ), |
100 | all(target_arch = "arm" , target_endian = "little" ) |
101 | ))] |
102 | pub(super) unsafe fn gmult( |
103 | &self, |
104 | f: unsafe extern "C" fn(xi: &mut Xi, h_table: &HTable), |
105 | xi: &mut Xi, |
106 | ) { |
107 | unsafe { f(xi, self) } |
108 | } |
109 | |
110 | pub(super) unsafe fn ghash( |
111 | &self, |
112 | f: unsafe extern "C" fn( |
113 | xi: &mut Xi, |
114 | Htable: &HTable, |
115 | inp: *const u8, |
116 | len: crate::c::NonZero_size_t, |
117 | ), |
118 | xi: &mut Xi, |
119 | input: AsChunks<u8, BLOCK_LEN>, |
120 | ) { |
121 | use core::num::NonZeroUsize; |
122 | |
123 | let input = input.as_flattened(); |
124 | |
125 | let input_len = match NonZeroUsize::new(input.len()) { |
126 | Some(len) => len, |
127 | None => { |
128 | return; |
129 | } |
130 | }; |
131 | |
132 | // SAFETY: |
133 | // * There are `input_len: NonZeroUsize` bytes available at `input` for |
134 | // `f` to read. |
135 | unsafe { |
136 | f(xi, self, input.as_ptr(), input_len); |
137 | } |
138 | } |
139 | } |
140 | |
141 | // The alignment is required by some assembly code. |
142 | #[derive (Clone)] |
143 | #[repr (C, align(16))] |
144 | pub(in super::super) struct HTable { |
145 | Htable: [U128; HTABLE_LEN], |
146 | } |
147 | |
148 | #[derive (Clone, Copy)] |
149 | #[repr (C)] |
150 | pub(super) struct U128 { |
151 | pub(super) hi: u64, |
152 | pub(super) lo: u64, |
153 | } |
154 | |
155 | const HTABLE_LEN: usize = 16; |
156 | |
157 | #[repr (transparent)] |
158 | pub(in super::super) struct Xi(pub(super) Block); |
159 | |
160 | impl Xi { |
161 | #[inline ] |
162 | pub(super) fn bitxor_assign(&mut self, a: Block) { |
163 | self.0 = constant_time::xor_16(self.0, b:a) |
164 | } |
165 | } |
166 | |