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::{block::BLOCK_LEN, Tag, TAG_LEN};
19 use crate::{c, cpu};
20 
21 /// A Poly1305 key.
22 pub(super) struct Key {
23     key_and_nonce: [u8; KEY_LEN],
24     cpu_features: cpu::Features,
25 }
26 
27 const KEY_LEN: usize = 2 * BLOCK_LEN;
28 
29 impl Key {
30     #[inline]
new(key_and_nonce: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self31     pub(super) fn new(key_and_nonce: [u8; KEY_LEN], cpu_features: cpu::Features) -> Self {
32         Self {
33             key_and_nonce,
34             cpu_features,
35         }
36     }
37 }
38 
39 pub struct Context {
40     state: poly1305_state,
41     #[allow(dead_code)]
42     cpu_features: cpu::Features,
43 }
44 
45 // Keep in sync with `poly1305_state` in GFp/poly1305.h.
46 //
47 // The C code, in particular the way the `poly1305_aligned_state` functions
48 // are used, is only correct when the state buffer is 64-byte aligned.
49 #[repr(C, align(64))]
50 struct poly1305_state([u8; OPAQUE_LEN]);
51 const OPAQUE_LEN: usize = 512;
52 
53 // Abstracts the dispatching logic that chooses the NEON implementation if and
54 // only if it would work.
55 macro_rules! dispatch {
56     ( $features:expr =>
57       ( $f:ident | $neon_f:ident )
58       ( $( $p:ident : $t:ty ),+ )
59       ( $( $a:expr ),+ ) ) => {
60         match () {
61             // Apple's 32-bit ARM ABI is incompatible with the assembly code.
62             #[cfg(all(target_arch = "arm", not(target_vendor = "apple")))]
63             () if cpu::arm::NEON.available($features) => {
64                 extern "C" {
65                     fn $neon_f( $( $p : $t ),+ );
66                 }
67                 unsafe { $neon_f( $( $a ),+ ) }
68             }
69             () => {
70                 extern "C" {
71                     fn $f( $( $p : $t ),+ );
72                 }
73                 unsafe { $f( $( $a ),+ ) }
74             }
75         }
76     }
77 }
78 
79 impl Context {
80     #[inline]
81     pub(super) fn from_key(
82         Key {
83             key_and_nonce,
84             cpu_features,
85         }: Key,
86     ) -> Self {
87         let mut ctx = Self {
88             state: poly1305_state([0u8; OPAQUE_LEN]),
89             cpu_features,
90         };
91 
92         dispatch!(
93             cpu_features =>
94             (GFp_poly1305_init | GFp_poly1305_init_neon)
95             (statep: &mut poly1305_state, key: &[u8; KEY_LEN])
96             (&mut ctx.state, &key_and_nonce));
97 
98         ctx
99     }
100 
101     #[inline(always)]
update(&mut self, input: &[u8])102     pub fn update(&mut self, input: &[u8]) {
103         dispatch!(
104             self.cpu_features =>
105             (GFp_poly1305_update | GFp_poly1305_update_neon)
106             (statep: &mut poly1305_state, input: *const u8, in_len: c::size_t)
107             (&mut self.state, input.as_ptr(), input.len()));
108     }
109 
finish(mut self) -> Tag110     pub(super) fn finish(mut self) -> Tag {
111         let mut tag = Tag([0u8; TAG_LEN]);
112         dispatch!(
113             self.cpu_features =>
114             (GFp_poly1305_finish | GFp_poly1305_finish_neon)
115             (statep: &mut poly1305_state, mac: &mut [u8; TAG_LEN])
116             (&mut self.state, &mut tag.0));
117         tag
118     }
119 }
120 
121 /// Implements the original, non-IETF padding semantics.
122 ///
123 /// This is used by chacha20_poly1305_openssh and the standalone
124 /// poly1305 test vectors.
sign(key: Key, input: &[u8]) -> Tag125 pub(super) fn sign(key: Key, input: &[u8]) -> Tag {
126     let mut ctx = Context::from_key(key);
127     ctx.update(input);
128     ctx.finish()
129 }
130 
131 #[cfg(test)]
132 mod tests {
133     use super::*;
134     use crate::test;
135     use core::convert::TryInto;
136 
137     // Adapted from BoringSSL's crypto/poly1305/poly1305_test.cc.
138     #[test]
test_poly1305()139     pub fn test_poly1305() {
140         let cpu_features = cpu::features();
141         test::run(test_file!("poly1305_test.txt"), |section, test_case| {
142             assert_eq!(section, "");
143             let key = test_case.consume_bytes("Key");
144             let key: &[u8; BLOCK_LEN * 2] = key.as_slice().try_into().unwrap();
145             let input = test_case.consume_bytes("Input");
146             let expected_mac = test_case.consume_bytes("MAC");
147             let key = Key::new(*key, cpu_features);
148             let Tag(actual_mac) = sign(key, &input);
149             assert_eq!(expected_mac, actual_mac.as_ref());
150 
151             Ok(())
152         })
153     }
154 }
155