1 // Copyright 2015-2016 Brian Smith.
2 // Portions Copyright (c) 2014, 2015, Google Inc.
3 //
4 // Permission to use, copy, modify, and/or distribute this software for any
5 // purpose with or without fee is hereby granted, provided that the above
6 // copyright notice and this permission notice appear in all copies.
7 //
8 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
9 // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
11 // SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13 // OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14 // CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 
16 // TODO: enforce maximum input length.
17 
18 use super::{
19     block::{Block, BLOCK_LEN},
20     Tag,
21 };
22 use crate::{bssl, c, error};
23 
24 /// A Poly1305 key.
25 pub struct Key([Block; KEY_BLOCKS]);
26 
27 impl From<[Block; KEY_BLOCKS]> for Key {
from(value: [Block; KEY_BLOCKS]) -> Self28     fn from(value: [Block; KEY_BLOCKS]) -> Self {
29         Self(value)
30     }
31 }
32 
33 pub const KEY_BLOCKS: usize = 2;
34 
35 pub struct Context {
36     opaque: Opaque,
37     nonce: Nonce,
38     func: Funcs,
39 }
40 
41 /// The memory manipulated by the assembly.
42 #[repr(C, align(8))]
43 struct Opaque([u8; OPAQUE_LEN]);
44 const OPAQUE_LEN: usize = 192;
45 
46 impl Context {
47     #[inline]
from_key(Key(key_and_nonce): Key) -> Self48     pub fn from_key(Key(key_and_nonce): Key) -> Self {
49         extern "C" {
50             fn GFp_poly1305_blocks(
51                 state: &mut Opaque,
52                 input: *const u8,
53                 len: c::size_t,
54                 should_pad: Pad,
55             );
56             fn GFp_poly1305_emit(state: &mut Opaque, tag: &mut Tag, nonce: &Nonce);
57         }
58 
59         let key = DerivedKey(key_and_nonce[0].clone());
60         let nonce = Nonce(key_and_nonce[1].clone());
61 
62         let mut ctx = Self {
63             opaque: Opaque([0u8; OPAQUE_LEN]),
64             nonce,
65             func: Funcs {
66                 blocks_fn: GFp_poly1305_blocks,
67                 emit_fn: GFp_poly1305_emit,
68             },
69         };
70 
71         // On some platforms `init()` doesn't initialize `funcs`. The
72         // return value of `init()` indicates whether it did or not. Since
73         // we already gave `func` a default value above, we can ignore the
74         // return value assuming `init()` doesn't change `func` if it chose
75         // not to initialize it. Note that this is different than what
76         // BoringSSL does.
77         let _ = init(&mut ctx.opaque, key, &mut ctx.func);
78 
79         ctx
80     }
81 
update_block(&mut self, block: Block, pad: Pad)82     pub fn update_block(&mut self, block: Block, pad: Pad) {
83         self.func.blocks(&mut self.opaque, block.as_ref(), pad);
84     }
85 
update_blocks(&mut self, input: &[u8])86     pub fn update_blocks(&mut self, input: &[u8]) {
87         debug_assert_eq!(input.len() % BLOCK_LEN, 0);
88         self.func.blocks(&mut self.opaque, input, Pad::Pad);
89     }
90 
finish(mut self) -> Tag91     pub(super) fn finish(mut self) -> Tag {
92         self.func.emit(&mut self.opaque, &self.nonce)
93     }
94 }
95 
96 #[cfg(test)]
check_state_layout()97 pub fn check_state_layout() {
98     let required_state_size = if cfg!(target_arch = "x86") {
99         // See comment above `_poly1305_init_sse2` in poly1305-x86.pl.
100         Some(4 * (5 + 1 + 4 + 2 + 4 * 9))
101     } else if cfg!(target_arch = "x86_64") {
102         // See comment above `__poly1305_block` in poly1305-x86_64.pl.
103         Some(4 * (5 + 1 + 2 * 2 + 2 + 4 * 9))
104     } else {
105         // TODO(davidben): Figure out the layout of the struct. For now,
106         // `OPAQUE_LEN` is taken from OpenSSL.
107         None
108     };
109 
110     if let Some(required_state_size) = required_state_size {
111         assert!(core::mem::size_of::<Opaque>() >= required_state_size);
112     }
113 }
114 
115 #[repr(C)]
116 struct DerivedKey(Block);
117 
118 /// This is *not* an "AEAD nonce"; it's a Poly1305-specific nonce.
119 #[repr(C)]
120 struct Nonce(Block);
121 
122 #[repr(C)]
123 struct Funcs {
124     blocks_fn:
125         unsafe extern "C" fn(&mut Opaque, input: *const u8, input_len: c::size_t, should_pad: Pad),
126     emit_fn: unsafe extern "C" fn(&mut Opaque, &mut Tag, nonce: &Nonce),
127 }
128 
129 #[inline]
init(state: &mut Opaque, key: DerivedKey, func: &mut Funcs) -> Result<(), error::Unspecified>130 fn init(state: &mut Opaque, key: DerivedKey, func: &mut Funcs) -> Result<(), error::Unspecified> {
131     extern "C" {
132         fn GFp_poly1305_init_asm(
133             state: &mut Opaque,
134             key: &DerivedKey,
135             out_func: &mut Funcs,
136         ) -> bssl::Result;
137     }
138     Result::from(unsafe { GFp_poly1305_init_asm(state, &key, func) })
139 }
140 
141 #[repr(u32)]
142 pub enum Pad {
143     AlreadyPadded = 0,
144     Pad = 1,
145 }
146 
147 impl Funcs {
148     #[inline]
blocks(&self, state: &mut Opaque, data: &[u8], should_pad: Pad)149     fn blocks(&self, state: &mut Opaque, data: &[u8], should_pad: Pad) {
150         unsafe {
151             (self.blocks_fn)(state, data.as_ptr(), data.len(), should_pad);
152         }
153     }
154 
155     #[inline]
emit(&self, state: &mut Opaque, nonce: &Nonce) -> Tag156     fn emit(&self, state: &mut Opaque, nonce: &Nonce) -> Tag {
157         let mut tag = Tag(Block::zero());
158         unsafe {
159             (self.emit_fn)(state, &mut tag, nonce);
160         }
161         tag
162     }
163 }
164 
165 /// Implements the original, non-IETF padding semantics.
166 ///
167 /// This is used by chacha20_poly1305_openssh and the standalone
168 /// poly1305 test vectors.
sign(key: Key, input: &[u8]) -> Tag169 pub(super) fn sign(key: Key, input: &[u8]) -> Tag {
170     let mut ctx = Context::from_key(key);
171     let remainder_len = input.len() % BLOCK_LEN;
172     let full_blocks_len = input.len() - remainder_len;
173     let (full_blocks, remainder) = input.split_at(full_blocks_len);
174     ctx.update_blocks(full_blocks);
175     if remainder_len > 0 {
176         let mut bytes = [0; BLOCK_LEN];
177         bytes[..remainder_len].copy_from_slice(remainder);
178         bytes[remainder_len] = 1;
179         ctx.update_block(Block::from(&bytes), Pad::AlreadyPadded);
180     }
181     ctx.finish()
182 }
183 
184 #[cfg(test)]
185 mod tests {
186     use super::*;
187     use crate::{polyfill::convert::Into_, test};
188     use core::convert::TryInto;
189 
190     #[test]
test_state_layout()191     pub fn test_state_layout() {
192         check_state_layout();
193     }
194 
195     // Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc.
196     #[test]
test_poly1305()197     pub fn test_poly1305() {
198         test::run(test_file!("poly1305_test.txt"), |section, test_case| {
199             assert_eq!(section, "");
200             let key = test_case.consume_bytes("Key");
201             let key: &[u8; BLOCK_LEN * 2] = key.as_slice().try_into().unwrap();
202             let key: [Block; 2] = key.into_();
203             let input = test_case.consume_bytes("Input");
204             let expected_mac = test_case.consume_bytes("MAC");
205             let key = Key::from(key);
206             let Tag(actual_mac) = sign(key, &input);
207             assert_eq!(expected_mac, actual_mac.as_ref());
208 
209             Ok(())
210         })
211     }
212 }
213