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